public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [lto] Refactor streamer (1/N) (issue4809083)
@ 2011-08-08 14:37 Diego Novillo
  2011-08-08 14:52 ` Jack Howarth
  2011-08-08 14:59 ` Michael Matz
  0 siblings, 2 replies; 11+ messages in thread
From: Diego Novillo @ 2011-08-08 14:37 UTC (permalink / raw)
  To: reply, rguenther, jh, matz, gcc-patches


This is the first patch in a series of refactoring patches to cleanup
the API for the LTO streamer.  I need this cleanup so I can change the
way things like caching and external references work in PPH.  With the
current code, I would need to introduce even more streamer hooks.  But
if we simplify the API and create smaller low-level streaming
functions, then we can have the LTO and PPH streamer use these
functions without having to resort to a lot of callbacks.

With these patches I'd like to:

1 Create independent facilities to stream trees, gimple and other
  data structures independently of LTO.  This first patch creates
  the files data-streamer*.[ch], tree-streamer*.[ch] and
  gimple-streamer*.[ch]. There are no other changes yet.  This simply
  moves functions out of lto-streamer*[ch], but no functions or data
  structures have been renamed.  This comes in a separate patch.

2 Make the naming scheme consistent.  We use a mix of names to mean
  the same thing (_out_, _output_, _write_, etc).  We have lto_
  prefixes for functions that are actually generic.  And we still have
  references to dwarf names (uleb, sleb, etc).

3 Abstract the LTO data structures.  The buffering and
  descriptor data structures used for LTO are somewhat confusing.  The
  generic streaming routines should simply work on bytecode buffers
  that are independent of LTO, PPH or other streamers we may want to
  create in the future.

4 Reduce the number of callbacks.  Ideally, I'd like to eliminate them
  completely.  The API we need to use from PPH is more settled now, so
  it should be easier to decide what needs a callback and what can be
  exposed.

Richard, Michael, Jan, how does this plan sound?  Other cleanups or
changes?  This patch implements #1.  There are no functional changes.
The only minor change I made as to unify the string hashing structure
and functions that we were using in two different files.

Bootstrapped with LTO profiledbootstrap on x86_64.  I will commit it
in the next few days, unless there are objections.


Diego.

	* Makefile.in (LTO_STREAMER_H): Add DIAGNOSTIC_H.
	(DATA_STREAMER_H): New.
	(GIMPLE_STREAMER_H): New.
	(TREE_STREAMER_H): New.
	(STREAMER_HOOKS_H): New.
	(OBJS): Add data-streamer.o, data-streamer-in.o, data-streamer-out.o,
	gimple-streamer-in.o, gimple-streamer-out.o, streamer-hooks.o,
	tree-streamer.o, tree-streamer-in.o and tree-streamer-out.o.
	(data-streamer.o): New.
	(data-streamer-in.o): New.
	(data-streamer-out.o): New.
	(gimple-streamer-in.o): New.
	(gimple-streamer-out.o): New.
	(streamer-hooks.o): New.
	(tree-streamer.o): New.
	(tree-streamer-in.o): New.
	(tree-streamer-out.o): New.
	(lto-cgraph.o): Add dependency on DATA_STREAMER_H and
	TREE_STREAMER_H.
	(lto-streamer-in.o): Add dependency on DATA_STREAMER_H,
	GIMPLE_STREAMER_H and TREE_STREAMER_H.
	(lto-streamer-out.o): Add dependency on DATA_STREAMER_H,
	GIMPLE_STREAMER_H and TREE_STREAMER_H.
	(lto-streamer.o): Add dependency on STREAMER_HOOKS_H.
	(ipa-prop.o): Add dependency on DATA_STREAMER_H and
	TREE_STREAMER_H.
	(ipa-inline-analysis.o): Likewise.
	(ipa-pure-const.o): Likewise.
	* data-streamer-in.c: New.
	* data-streamer-out.c: New.
	* data-streamer.c: New.
	* data-streamer.h: New.
	* gimple-streamer-in.c: New.
	* gimple-streamer-out.c: New.
	* gimple-streamer.h: New.
	* ipa-inline-analysis.c: Include data-streamer.h.
	* ipa-prop.c: Include data-streamer.h.
	* ipa-pure-const.c: Include data-streamer.h.
	* lto-cgraph.c: Include data-streamer.h.
	* lto-section-in.c (lto_input_uleb128): Move to data-streamer-in.c.
	(lto_input_widest_uint_uleb128): Likewise.
	(lto_input_sleb128): Likewise.
	(bp_unpack_var_len_unsigned): Likewise.
	(bp_unpack_var_len_int): Likewise.
	* lto-section-out.c (lto_output_uleb128_stream): Move to
	data-streamer-out.c.
	(lto_output_widest_uint_uleb128_stream): Likewise.
	(lto_output_sleb128_stream): Likewise.
	(bp_pack_var_len_unsigned): Likewise.
	(bp_pack_var_len_int): Likewise.
	* lto-streamer-in.c: Include data-streamer.h and
	gimple-streamer.h.
	(struct string_slot): Remove.  Update all users.
	(lto_tag_check_set): Make extern.
	(lto_tag_check_range): Move to lto-streamer.h.
	(lto_tag_check): Likewise.
	(hash_string_slot_node): Remove.  Update all users.
	(eq_string_slot_node): Remove.  Update all users.
	(string_for_index): Move to data-streamer-in.c
	(input_string_internal): Likewise.
	(input_string_cst): Move to tree-streamer-in.c.
	(input_identifier): Likewise.
	(lto_input_string): Move to data-streamer-in.c
	(input_record_start): Move to data-streamer.h
	(canon_file_name): Use new definition of struct string_slot
	from data-streamer.h.
	Set S_SLOT.LEN.
	(lto_input_location): Make extern.
	(lto_input_chain): Move to tree-streamer-in.c.
	(lto_init_eh): Make extern.
	(input_phi): Move to gimple-streamer-in.c.
	(input_gimple_stmt): Likewise.
	(input_bb): Likewise.
	(unpack_ts_base_value_fields): Move to tree-streamer-in.c.
	(unpack_ts_real_cst_value_fields): Likewise.
	(unpack_ts_fixed_cst_value_fields): Likewise.
	(unpack_ts_decl_common_value_fields): Likewise.
	(unpack_ts_decl_wrtl_value_fields): Likewise.
	(unpack_ts_decl_with_vis_value_fields): Likewise.
	(unpack_ts_function_decl_value_fields): Likewise.
	(unpack_ts_type_common_value_fields): Likewise.
	(unpack_ts_block_value_fields): Likewise.
	(unpack_ts_translation_unit_decl_value_fields): Likewise.
	(unpack_value_fields): Likewise.
	(lto_materialize_tree): Likewise.
	(lto_input_ts_common_tree_pointers): Likewise.
	(lto_input_ts_vector_tree_pointers): Likewise.
	(lto_input_ts_complex_tree_pointers): Likewise.
	(lto_input_ts_decl_minimal_tree_pointers): Likewise.
	(lto_input_ts_decl_common_tree_pointers): Likewise.
	(lto_input_ts_decl_non_common_tree_pointers): Likewise.
	(lto_input_ts_decl_with_vis_tree_pointers): Likewise.
	(lto_input_ts_field_decl_tree_pointers): Likewise.
	(lto_input_ts_function_decl_tree_pointers): Likewise.
	(lto_input_ts_type_common_tree_pointers): Likewise.
	(lto_input_ts_type_non_common_tree_pointers): Likewise.
	(lto_input_ts_list_tree_pointers): Likewise.
	(lto_input_ts_vec_tree_pointers): Likewise.
	(lto_input_ts_exp_tree_pointers): Likewise.
	(lto_input_ts_block_tree_pointers): Likewise.
	(lto_input_ts_binfo_tree_pointers): Likewise.
	(lto_input_ts_constructor_tree_pointers): Likewise.
	(lto_input_ts_target_option): Likewise.
	(lto_input_ts_translation_unit_decl_tree_pointers): Likewise.
	(lto_input_tree_pointers): Likewise.
	(lto_get_pickled_tree): Likewise.
	(lto_get_builtin_tree): Likewise.
	(lto_read_tree): Likewise.
	(lto_input_integer_cst): Likewise.
	(lto_input_tree): Likewise.
	* lto-streamer-out.c: Include data-streamer.h,
	gimple-streamer.h and streamer-hooks.h.
	(struct string_slot): Move to data-streamer.h.
	(hash_string_slot_node): Likewise.
	(eq_string_slot_node): Likewise.
	(lto_string_index): Move to data-streamer-out.c.
	(lto_output_string_with_length): Likewise.
	(lto_output_string): Likewise.
	(output_string_cst): Move to tree-streamer-out.c.
	(output_identifier): Likewise.
	(output_zero): Move to data-streamer-out.c
	(output_uleb128): Likewise.
	(output_sleb128): Likewise.
	(output_record_start): Move to data-streamer.h
	(pack_ts_base_value_fields): Move to tree-streamer-out.c.
	(pack_ts_real_cst_value_fields): Likewise.
	(pack_ts_fixed_cst_value_fields): Likewise.
	(pack_ts_decl_common_value_fields): Likewise.
	(pack_ts_decl_wrtl_value_fields): Likewise.
	(pack_ts_decl_with_vis_value_fields): Likewise.
	(pack_ts_function_decl_value_fields): Likewise.
	(pack_ts_type_common_value_fields): Likewise.
	(pack_ts_block_value_fields): Likewise.
	(pack_ts_translation_unit_decl_value_fields): Likewise.
	(pack_value_fields): Likewise.
	(lto_output_chain): Likewise.
	(lto_output_ts_common_tree_pointers): Likewise.
	(lto_output_ts_vector_tree_pointers): Likewise.
	(lto_output_ts_complex_tree_pointers): Likewise.
	(lto_output_ts_decl_minimal_tree_pointers): Likewise.
	(lto_output_ts_decl_common_tree_pointers): Likewise.
	(lto_output_ts_decl_non_common_tree_pointers): Likewise.
	(lto_output_ts_decl_with_vis_tree_pointers): Likewise.
	(lto_output_ts_field_decl_tree_pointers): Likewise.
	(lto_output_ts_function_decl_tree_pointers): Likewise.
	(lto_output_ts_type_common_tree_pointers): Likewise.
	(lto_output_ts_type_non_common_tree_pointers): Likewise.
	(lto_output_ts_list_tree_pointers): Likewise.
	(lto_output_ts_vec_tree_pointers): Likewise.
	(lto_output_ts_exp_tree_pointers): Likewise.
	(lto_output_ts_block_tree_pointers): Likewise.
	(lto_output_ts_binfo_tree_pointers): Likewise.
	(lto_output_ts_constructor_tree_pointers): Likewise.
	(lto_output_ts_target_option): Likewise.
	(lto_output_ts_translation_unit_decl_tree_pointers): Likewise.
	(lto_output_tree_pointers): Likewise.
	(lto_output_tree_header): Likewise.
	(lto_output_builtin_tree): Likewise.
	(lto_write_tree): Likewise.
	(lto_output_integer_cst): Likewise.
	(lto_output_tree): Likewise.
	(output_phi): Move to gimple-streamer-out.c.
	(output_gimple_stmt): Likewise.
	(output_bb): Likewise.
	* lto-streamer.c: Include tree-streamer.h and streamer-hooks.h.
	(streamer_hooks): Move to streamer-hooks.c.
	(check_handled_ts_structures): Move to tree-streamer.c
	(lto_streamer_cache_add_to_node_array): Likewise.
	(lto_streamer_cache_insert_1): Likewise.
	(lto_streamer_cache_insert): Likewise.
	(lto_streamer_cache_insert_at): Likewise.
	(lto_streamer_cache_append): Likewise.
	(lto_streamer_cache_lookup): Likewise.
	(lto_streamer_cache_get): Likewise.
	(lto_record_common_node): Likewise.
	(lto_preload_common_nodes): Likewise.
	(lto_streamer_cache_create): Likewise.
	(lto_streamer_cache_delete): Likewise.
	(streamer_hooks_init): Move to streamer-hooks.c.
	* lto-streamer.h: Include diagnostic.h
	(struct output_block, struct lto_input_block,
	struct data_in, struct bitpack_d): Remove forward
	declarations.
	(struct bitpack_d): Move to data-streamer.h.
	(struct lto_streamer_cache_d): Move to tree-streamer.h.
	(struct streamer_hooks): Move to streamer-hooks.h.
	(bp_pack_var_len_unsigned): Move to data-streamer.h.
	(bp_pack_var_len_int): Likewise.
	(bp_unpack_var_len_unsigned): Likewise.
	(bp_unpack_var_len_int): Likewise.
	(lto_input_location): Declare.
	(lto_tag_check_set): Declare.
	(lto_init_eh): Declare.
	(lto_output_tree_ref): Declare.
	(lto_output_location): Declare.
	(bitpack_create): Move to data-streamer.h.
	(bp_pack_value): Likewise.
	(lto_output_bitpack): Likewise.
	(lto_input_bitpack): Likewise.
	(bp_unpack_value): Likewise.
	(lto_output_1_stream): Likewise.
	(lto_input_1_unsigned): Likewise.
	(lto_output_int_in_range): Likewise.
	(lto_input_int_in_range): Likewise.
	(bp_pack_int_in_range): Likewise.
	(bp_unpack_int_in_range): Likewise.
	(lto_output_enum): Likewise.
	(lto_input_enum): Likewise.
	(bp_pack_enum): Likewise.
	(bp_unpack_enum): Likewise.
	* streamer-hooks.c: New.
	* streamer-hooks.h: New.
	* tree-streamer-in.c: New.
	* tree-streamer-out.c: New.
	* tree-streamer.c: New.
	* tree-streamer.h: New.

lto/ChangeLog

	* Make-lang.in (lto/lto.o): Add TREE_STREAMER_H.
	* lto.c: Include tree-streamer.h.

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index ed96672..9fc4f05 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -992,7 +992,12 @@ DBGCNT_H = dbgcnt.h dbgcnt.def
 EBITMAP_H = ebitmap.h sbitmap.h
 LTO_STREAMER_H = lto-streamer.h $(LINKER_PLUGIN_API_H) $(TARGET_H) \
 		$(CGRAPH_H) $(VEC_H) vecprim.h $(TREE_H) $(GIMPLE_H) \
-		$(GCOV_IO_H)
+		$(GCOV_IO_H) $(DIAGNOSTIC_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)
+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
 GSTAB_H = gstab.h stab.def
@@ -1236,6 +1241,9 @@ OBJS = \
 	cprop.o \
 	cse.o \
 	cselib.o \
+	data-streamer.o \
+	data-streamer-in.o \
+	data-streamer-out.o \
 	dbxout.o \
 	dbgcnt.o \
 	dce.o \
@@ -1272,6 +1280,8 @@ OBJS = \
 	gimple-fold.o \
 	gimple-low.o \
 	gimple-pretty-print.o \
+	gimple-streamer-in.o \
+	gimple-streamer-out.o \
 	gimplify.o \
 	godump.o \
 	graph.o \
@@ -1327,13 +1337,13 @@ OBJS = \
 	loop-unswitch.o \
 	lower-subreg.o \
 	lto-cgraph.o \
+	lto-streamer.o \
 	lto-streamer-in.o \
 	lto-streamer-out.o \
 	lto-section-in.o \
 	lto-section-out.o \
 	lto-symtab.o \
 	lto-opts.o \
-	lto-streamer.o \
 	lto-compress.o \
 	matrix-reorg.o \
 	mcf.o \
@@ -1388,6 +1398,7 @@ OBJS = \
 	stmt.o \
 	stor-layout.o \
 	store-motion.o \
+	streamer-hooks.o \
 	stringpool.o \
 	target-globals.o \
 	targhooks.o \
@@ -1464,6 +1475,9 @@ OBJS = \
 	tree-ssa.o \
 	tree-ssanames.o \
 	tree-stdarg.o \
+	tree-streamer.o \
+	tree-streamer-in.o \
+	tree-streamer-out.o \
 	tree-tailcall.o \
 	tree-vect-generic.o \
 	tree-vect-patterns.o \
@@ -2276,22 +2290,47 @@ lto-compress.o: lto-compress.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
 	$(TREE_H) langhooks.h $(LTO_STREAMER_H) $(LTO_SECTION_H) \
 	lto-compress.h $(DIAGNOSTIC_CORE_H) $(DIAGNOSTIC_CORE_H)
 	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(ZLIBINC) $< $(OUTPUT_OPTION)
-
+data-streamer-in.o: data-streamer-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+    $(DATA_STREAMER_H) $(DIAGNOSTIC_H)
+data-streamer-out.o: data-streamer-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+    $(DATA_STREAMER_H)
+data-streamer.o: data-streamer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+    $(DATA_STREAMER_H)
+gimple-streamer-in.o: gimple-streamer-in.c $(CONFIG_H) $(SYSTEM_H) \
+    coretypes.h $(GIMPLE_STREAMER_H) $(TREE_FLOW_H) $(DATA_STREAMER_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)
+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) \
+    coretypes.h $(DIAGNOSTIC_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_STREAMER_H) \
+    $(DATA_STREAMER_H) $(STREAMER_HOOKS_H) $(LTO_STREAMER_H)
+tree-streamer-out.o: tree-streamer-out.c $(CONFIG_H) $(SYSTEM_H) \
+    coretypes.h $(DIAGNOSTIC_H) $(TREE_STREAMER_H) $(DATA_STREAMER_H) \
+    $(STREAMER_HOOKS_H)
+streamer-hooks.o: streamer-hooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+    $(STREAMER_HOOKS_H)
 lto-cgraph.o: lto-cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h   \
    $(TM_H) $(DIAGNOSTIC_CORE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
    $(HASHTAB_H) langhooks.h $(BASIC_BLOCK_H) \
    $(TREE_FLOW_H) $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_CORE_H) \
-   $(EXCEPT_H) $(TIMEVAR_H) output.h pointer-set.h $(LTO_STREAMER_H) $(GCOV_IO_H)
+   $(EXCEPT_H) $(TIMEVAR_H) output.h pointer-set.h $(LTO_STREAMER_H) \
+   $(GCOV_IO_H) $(DATA_STREAMER_H) $(TREE_STREAMER_H)
 lto-streamer-in.o: lto-streamer-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    $(TM_H) toplev.h $(DIAGNOSTIC_CORE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
    $(HASHTAB_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(TREE_PASS_H) $(CGRAPH_H) \
    $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) $(LIBFUNCS_H) $(EXCEPT_H) debug.h \
-   $(TIMEVAR_H) output.h $(IPA_UTILS_H) $(LTO_STREAMER_H) toplev.h
+   $(TIMEVAR_H) output.h $(IPA_UTILS_H) $(LTO_STREAMER_H) toplev.h \
+   $(DATA_STREAMER_H) $(GIMPLE_STREAMER_H) $(TREE_STREAMER_H)
 lto-streamer-out.o : lto-streamer-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    $(TM_H) $(DIAGNOSTIC_CORE_H) $(TREE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
    $(HASHTAB_H) $(BASIC_BLOCK_H) tree-iterator.h \
    $(TREE_FLOW_H) $(TREE_PASS_H) $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) \
-   $(DIAGNOSTIC_CORE_H) $(EXCEPT_H) $(LTO_STREAMER_H) $(DIAGNOSTIC_CORE_H)
+   $(DIAGNOSTIC_CORE_H) $(EXCEPT_H) $(LTO_STREAMER_H) $(DIAGNOSTIC_CORE_H) \
+   $(DATA_STREAMER_H) $(STREAMER_HOOKS_H) $(GIMPLE_STREAMER_H) \
+   $(TREE_STREAMER_H)
 lto-section-in.o: lto-section-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(DIAGNOSTIC_CORE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
    $(HASHTAB_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(CGRAPH_H) $(FUNCTION_H) \
@@ -2310,7 +2349,8 @@ lto-opts.o: lto-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
    $(COMMON_TARGET_H) $(DIAGNOSTIC_H) $(LTO_STREAMER_H)
 lto-streamer.o: lto-streamer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h   \
    $(TM_H) $(TREE_H) $(GIMPLE_H) $(BITMAP_H) $(LTO_STREAMER_H) $(FLAGS_H) \
-   $(TREE_FLOW_H) $(DIAGNOSTIC_CORE_H) $(LTO_SYMTAB_H) toplev.h $(DIAGNOSTIC_CORE_H)
+   $(TREE_FLOW_H) $(DIAGNOSTIC_CORE_H) $(LTO_SYMTAB_H) toplev.h \
+   $(DIAGNOSTIC_CORE_H) $(STREAMER_HOOKS_H)
 langhooks.o : langhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TREE_H) toplev.h $(DIAGNOSTIC_CORE_H) $(TREE_INLINE_H) $(RTL_H) insn-config.h $(INTEGRATE_H) \
    langhooks.h $(TARGET_H) $(LANGHOOKS_DEF_H) $(FLAGS_H) $(GGC_H) $(DIAGNOSTIC_H) \
@@ -2990,7 +3030,8 @@ ipa-prop.o : ipa-prop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H) $(IPA_PROP_H) $(DIAGNOSTIC_H) \
    $(TREE_FLOW_H) $(TM_H) $(TREE_PASS_H) $(FLAGS_H) $(TREE_H) \
    $(TREE_INLINE_H) $(GIMPLE_H) $(TIMEVAR_H) \
-   tree-pretty-print.h gimple-pretty-print.h $(LTO_STREAMER_H)
+   tree-pretty-print.h gimple-pretty-print.h $(LTO_STREAMER_H) \
+   $(DATA_STREAMER_H) $(TREE_STREAMER_H)
 ipa-ref.o : ipa-ref.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H)  $(TREE_H) $(TARGET_H) \
    $(TREE_FLOW_H) $(TM_H) $(TREE_PASS_H) $(FLAGS_H) $(TREE_H) $(GGC_H) 
@@ -3018,7 +3059,8 @@ ipa-inline-analysis.o : ipa-inline-analysis.c $(CONFIG_H) $(SYSTEM_H) coretypes.
    $(TREE_H) langhooks.h $(TREE_INLINE_H) $(FLAGS_H) $(CGRAPH_H) intl.h \
    $(DIAGNOSTIC_H) $(PARAMS_H) $(TIMEVAR_H) $(TREE_PASS_H) \
    $(HASHTAB_H) $(COVERAGE_H) $(GGC_H) $(TREE_FLOW_H) $(IPA_PROP_H) \
-   gimple-pretty-print.h ipa-inline.h $(LTO_STREAMER_H)
+   gimple-pretty-print.h ipa-inline.h $(LTO_STREAMER_H) $(DATA_STREAMER_H) \
+   $(TREE_STREAMER_H)
 ipa-inline-transform.o : ipa-inline-transform.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TREE_H) langhooks.h $(TREE_INLINE_H) $(FLAGS_H) $(CGRAPH_H) intl.h \
    $(DIAGNOSTIC_H) $(PARAMS_H) $(TIMEVAR_H) $(TREE_PASS_H) \
@@ -3038,7 +3080,7 @@ ipa-pure-const.o : ipa-pure-const.c $(CONFIG_H) $(SYSTEM_H) \
    pointer-set.h $(GGC_H) $(IPA_UTILS_H) $(TARGET_H) \
    $(GIMPLE_H) $(CGRAPH_H) output.h $(FLAGS_H) $(TREE_PASS_H) $(TIMEVAR_H) \
    $(DIAGNOSTIC_H) $(CFGLOOP_H) $(SCEV_H) $(LTO_STREAMER_H) \
-   gimple-pretty-print.h
+   gimple-pretty-print.h $(DATA_STREAMER_H) $(TREE_STREAMER_H)
 coverage.o : coverage.c $(GCOV_IO_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    $(TM_H) $(RTL_H) $(TREE_H) $(FLAGS_H) output.h $(REGS_H) $(EXPR_H) \
    $(FUNCTION_H) $(BASIC_BLOCK_H) toplev.h $(DIAGNOSTIC_CORE_H) $(GGC_H) langhooks.h $(COVERAGE_H) \
diff --git a/gcc/data-streamer-in.c b/gcc/data-streamer-in.c
new file mode 100644
index 0000000..5e366b1
--- /dev/null
+++ b/gcc/data-streamer-in.c
@@ -0,0 +1,152 @@
+/* Routines for restoring various data types from a file stream.  This deals
+   with various data types like strings, integers, enums, etc.
+
+   Copyright 2011 Free Software Foundation, Inc.
+   Contributed by Diego Novillo <dnovillo@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostic.h"
+#include "data-streamer.h"
+
+/* Read a string from the string table in DATA_IN using input block
+   IB.  Write the length to RLEN.  */
+
+const char *
+string_for_index (struct data_in *data_in, unsigned int loc, unsigned int *rlen)
+{
+  struct lto_input_block str_tab;
+  unsigned int len;
+  const char *result;
+
+  if (!loc)
+    {
+      *rlen = 0;
+      return NULL;
+    }
+
+  /* Get the string stored at location LOC in DATA_IN->STRINGS.  */
+  LTO_INIT_INPUT_BLOCK (str_tab, data_in->strings, loc - 1,
+			data_in->strings_len);
+  len = lto_input_uleb128 (&str_tab);
+  *rlen = len;
+
+  if (str_tab.p + len > data_in->strings_len)
+    internal_error ("bytecode stream: string too long for the string table");
+
+  result = (const char *)(data_in->strings + str_tab.p);
+
+  return result;
+}
+
+
+/* Read a string from the string table in DATA_IN using input block
+   IB.  Write the length to RLEN.  */
+
+const char *
+input_string_internal (struct data_in *data_in, struct lto_input_block *ib,
+		       unsigned int *rlen)
+{
+  return string_for_index (data_in, lto_input_uleb128 (ib), rlen);
+}
+
+
+/* Read a NULL terminated string from the string table in DATA_IN.  */
+
+const char *
+lto_input_string (struct data_in *data_in, struct lto_input_block *ib)
+{
+  unsigned int len;
+  const char *ptr;
+
+  ptr = input_string_internal (data_in, ib, &len);
+  if (!ptr)
+    return NULL;
+  if (ptr[len - 1] != '\0')
+    internal_error ("bytecode stream: found non-null terminated string");
+
+  return ptr;
+}
+
+
+/* Read an ULEB128 Number of IB.  */
+
+unsigned HOST_WIDE_INT
+lto_input_uleb128 (struct lto_input_block *ib)
+{
+  unsigned HOST_WIDE_INT result = 0;
+  int shift = 0;
+  unsigned HOST_WIDE_INT byte;
+
+  while (true)
+    {
+      byte = lto_input_1_unsigned (ib);
+      result |= (byte & 0x7f) << shift;
+      shift += 7;
+      if ((byte & 0x80) == 0)
+	return result;
+    }
+}
+
+
+/* HOST_WIDEST_INT version of lto_input_uleb128.  IB is as in
+   lto_input_uleb128.  */
+
+unsigned HOST_WIDEST_INT
+lto_input_widest_uint_uleb128 (struct lto_input_block *ib)
+{
+  unsigned HOST_WIDEST_INT result = 0;
+  int shift = 0;
+  unsigned HOST_WIDEST_INT byte;
+
+  while (true)
+    {
+      byte = lto_input_1_unsigned (ib);
+      result |= (byte & 0x7f) << shift;
+      shift += 7;
+      if ((byte & 0x80) == 0)
+	return result;
+    }
+}
+
+
+/* Read an SLEB128 Number of IB.  */
+
+HOST_WIDE_INT
+lto_input_sleb128 (struct lto_input_block *ib)
+{
+  HOST_WIDE_INT result = 0;
+  int shift = 0;
+  unsigned HOST_WIDE_INT byte;
+
+  while (true)
+    {
+      byte = lto_input_1_unsigned (ib);
+      result |= (byte & 0x7f) << shift;
+      shift += 7;
+      if ((byte & 0x80) == 0)
+	{
+	  if ((shift < HOST_BITS_PER_WIDE_INT) && (byte & 0x40))
+	    result |= - ((HOST_WIDE_INT)1 << shift);
+
+	  return result;
+	}
+    }
+}
diff --git a/gcc/data-streamer-out.c b/gcc/data-streamer-out.c
new file mode 100644
index 0000000..07d5b35
--- /dev/null
+++ b/gcc/data-streamer-out.c
@@ -0,0 +1,207 @@
+/* Routines for saving various data types to a file stream.  This deals
+   with various data types like strings, integers, enums, etc.
+
+   Copyright 2011 Free Software Foundation, Inc.
+   Contributed by Diego Novillo <dnovillo@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "data-streamer.h"
+
+/* Return index used to reference STRING of LEN characters in the string table
+   in OB.  The string might or might not include a trailing '\0'.
+   Then put the index onto the INDEX_STREAM.  
+   When PERSISTENT is set, the string S is supposed to not change during
+   duration of the OB and thus OB can keep pointer into it.  */
+
+unsigned
+lto_string_index (struct output_block *ob, const char *s, unsigned int len,
+		  bool persistent)
+{
+  struct string_slot **slot;
+  struct string_slot s_slot;
+
+  s_slot.s = s;
+  s_slot.len = len;
+  s_slot.slot_num = 0;
+
+  slot = (struct string_slot **) htab_find_slot (ob->string_hash_table,
+						 &s_slot, INSERT);
+  if (*slot == NULL)
+    {
+      struct lto_output_stream *string_stream = ob->string_stream;
+      unsigned int start = string_stream->total_size;
+      struct string_slot *new_slot = XOBNEW (&ob->obstack, struct string_slot);
+      const char *string;
+
+      if (!persistent)
+	{
+	  char *tmp;
+	  string = tmp = XOBNEWVEC (&ob->obstack, char, len);
+          memcpy (tmp, s, len);
+        }
+      else
+	string = s;
+
+      new_slot->s = string;
+      new_slot->len = len;
+      new_slot->slot_num = start;
+      *slot = new_slot;
+      lto_output_uleb128_stream (string_stream, len);
+      lto_output_data_stream (string_stream, string, len);
+      return start + 1;
+    }
+  else
+    {
+      struct string_slot *old_slot = *slot;
+      return old_slot->slot_num + 1;
+    }
+}
+
+
+/* Output STRING of LEN characters to the string table in OB. The
+   string might or might not include a trailing '\0'. Then put the
+   index onto the INDEX_STREAM. 
+   When PERSISTENT is set, the string S is supposed to not change during
+   duration of the OB and thus OB can keep pointer into it.  */
+
+void
+lto_output_string_with_length (struct output_block *ob,
+			       struct lto_output_stream *index_stream,
+			       const char *s, unsigned int len, bool persistent)
+{
+  if (s)
+    lto_output_uleb128_stream (index_stream,
+			       lto_string_index (ob, s, len, persistent));
+  else
+    lto_output_1_stream (index_stream, 0);
+}
+
+
+/* Output the '\0' terminated STRING to the string
+   table in OB.  Then put the index onto the INDEX_STREAM.
+   When PERSISTENT is set, the string S is supposed to not change during
+   duration of the OB and thus OB can keep pointer into it.  */
+
+void
+lto_output_string (struct output_block *ob,
+	           struct lto_output_stream *index_stream,
+	           const char *string, bool persistent)
+{
+  if (string)
+    lto_output_string_with_length (ob, index_stream, string,
+				   strlen (string) + 1,
+				   persistent);
+  else
+    lto_output_1_stream (index_stream, 0);
+}
+
+
+/* Write a zero to the output stream.  */
+
+void
+output_zero (struct output_block *ob)
+{
+  lto_output_1_stream (ob->main_stream, 0);
+}
+
+
+/* Output an unsigned LEB128 quantity to OB->main_stream.  */
+
+void
+output_uleb128 (struct output_block *ob, unsigned HOST_WIDE_INT work)
+{
+  lto_output_uleb128_stream (ob->main_stream, work);
+}
+
+
+/* Output a signed LEB128 quantity to OB->main_stream.  */
+
+void
+output_sleb128 (struct output_block *ob, HOST_WIDE_INT work)
+{
+  lto_output_sleb128_stream (ob->main_stream, work);
+}
+
+
+/* Output an unsigned LEB128 quantity to OBS.  */
+
+void
+lto_output_uleb128_stream (struct lto_output_stream *obs,
+			   unsigned HOST_WIDE_INT work)
+{
+  do
+    {
+      unsigned int byte = (work & 0x7f);
+      work >>= 7;
+      if (work != 0)
+	/* More bytes to follow.  */
+	byte |= 0x80;
+
+      lto_output_1_stream (obs, byte);
+    }
+  while (work != 0);
+}
+
+
+/* Identical to output_uleb128_stream above except using unsigned
+   HOST_WIDEST_INT type.  For efficiency on host where unsigned HOST_WIDEST_INT
+   is not native, we only use this if we know that HOST_WIDE_INT is not wide
+   enough.  */
+
+void
+lto_output_widest_uint_uleb128_stream (struct lto_output_stream *obs,
+				       unsigned HOST_WIDEST_INT work)
+{
+  do
+    {
+      unsigned int byte = (work & 0x7f);
+      work >>= 7;
+      if (work != 0)
+	/* More bytes to follow.  */
+	byte |= 0x80;
+
+      lto_output_1_stream (obs, byte);
+    }
+  while (work != 0);
+}
+
+
+/* Output a signed LEB128 quantity.  */
+
+void
+lto_output_sleb128_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
+{
+  int more, byte;
+
+  do
+    {
+      byte = (work & 0x7f);
+      /* arithmetic shift */
+      work >>= 7;
+      more = !((work == 0 && (byte & 0x40) == 0)
+	       || (work == -1 && (byte & 0x40) != 0));
+      if (more)
+	byte |= 0x80;
+
+      lto_output_1_stream (obs, byte);
+    }
+  while (more);
+}
diff --git a/gcc/data-streamer.c b/gcc/data-streamer.c
new file mode 100644
index 0000000..5eaacfc
--- /dev/null
+++ b/gcc/data-streamer.c
@@ -0,0 +1,111 @@
+/* Generic streaming support for basic data types.
+
+   Copyright 2011 Free Software Foundation, Inc.
+   Contributed by Diego Novillo <dnovillo@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "data-streamer.h"
+
+/* Pack WORK into BP in a variant of uleb format.  */
+
+void
+bp_pack_var_len_unsigned (struct bitpack_d *bp, unsigned HOST_WIDE_INT work)
+{
+  do
+    {
+      unsigned int half_byte = (work & 0x7);
+      work >>= 3;
+      if (work != 0)
+	/* More half_bytes to follow.  */
+	half_byte |= 0x8;
+
+      bp_pack_value (bp, half_byte, 4);
+    }
+  while (work != 0);
+}
+
+
+/* Pack WORK into BP in a variant of sleb format.  */
+
+void
+bp_pack_var_len_int (struct bitpack_d *bp, HOST_WIDE_INT work)
+{
+  int more, half_byte;
+
+  do
+    {
+      half_byte = (work & 0x7);
+      /* arithmetic shift */
+      work >>= 3;
+      more = !((work == 0 && (half_byte & 0x4) == 0)
+	       || (work == -1 && (half_byte & 0x4) != 0));
+      if (more)
+	half_byte |= 0x8;
+
+      bp_pack_value (bp, half_byte, 4);
+    }
+  while (more);
+}
+
+
+/* Unpack VAL from BP in a variant of uleb format.  */
+
+unsigned HOST_WIDE_INT
+bp_unpack_var_len_unsigned (struct bitpack_d *bp)
+{
+  unsigned HOST_WIDE_INT result = 0;
+  int shift = 0;
+  unsigned HOST_WIDE_INT half_byte;
+
+  while (true)
+    {
+      half_byte = bp_unpack_value (bp, 4);
+      result |= (half_byte & 0x7) << shift;
+      shift += 3;
+      if ((half_byte & 0x8) == 0)
+	return result;
+    }
+}
+
+
+/* Unpack VAL from BP in a variant of sleb format.  */
+
+HOST_WIDE_INT
+bp_unpack_var_len_int (struct bitpack_d *bp)
+{
+  HOST_WIDE_INT result = 0;
+  int shift = 0;
+  unsigned HOST_WIDE_INT half_byte;
+
+  while (true)
+    {
+      half_byte = bp_unpack_value (bp, 4);
+      result |= (half_byte & 0x7) << shift;
+      shift += 3;
+      if ((half_byte & 0x8) == 0)
+	{
+	  if ((shift < HOST_BITS_PER_WIDE_INT) && (half_byte & 0x4))
+	    result |= - ((HOST_WIDE_INT)1 << shift);
+
+	  return result;
+	}
+    }
+}
diff --git a/gcc/data-streamer.h b/gcc/data-streamer.h
new file mode 100644
index 0000000..c2f6fa8
--- /dev/null
+++ b/gcc/data-streamer.h
@@ -0,0 +1,355 @@
+/* Generic streaming support for various data types.
+
+   Copyright 2011 Free Software Foundation, Inc.
+   Contributed by Diego Novillo <dnovillo@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_DATA_STREAMER_H
+#define GCC_DATA_STREAMER_H
+
+#include "vec.h"
+#include "lto-streamer.h"
+
+/* Data structures used to pack values and bitflags into a vector of
+   words.  Used to stream values of a fixed number of bits in a space
+   efficient way.  */
+static unsigned const BITS_PER_BITPACK_WORD = HOST_BITS_PER_WIDE_INT;
+
+typedef unsigned HOST_WIDE_INT bitpack_word_t;
+DEF_VEC_I(bitpack_word_t);
+DEF_VEC_ALLOC_I(bitpack_word_t, heap);
+
+struct bitpack_d
+{
+  /* The position of the first unused or unconsumed bit in the word.  */
+  unsigned pos;
+
+  /* The current word we are (un)packing.  */
+  bitpack_word_t word;
+
+  /* The lto_output_stream or the lto_input_block we are streaming to/from.  */
+  void *stream;
+};
+
+
+/* String hashing.  */
+struct string_slot
+{
+  const char *s;
+  int len;
+  unsigned int slot_num;
+};
+
+
+/* Returns a hash code for P.  Adapted from libiberty's htab_hash_string
+   to support strings that may not end in '\0'.  */
+
+static inline hashval_t
+hash_string_slot_node (const void *p)
+{
+  const struct string_slot *ds = (const struct string_slot *) p;
+  hashval_t r = ds->len;
+  int i;
+
+  for (i = 0; i < ds->len; i++)
+     r = r * 67 + (unsigned)ds->s[i] - 113;
+  return r;
+}
+
+/* Returns nonzero if P1 and P2 are equal.  */
+
+static inline int
+eq_string_slot_node (const void *p1, const void *p2)
+{
+  const struct string_slot *ds1 = (const struct string_slot *) p1;
+  const struct string_slot *ds2 = (const struct string_slot *) p2;
+
+  if (ds1->len == ds2->len)
+    return memcmp (ds1->s, ds2->s, ds1->len) == 0;
+
+  return 0;
+}
+
+/* Returns a new bit-packing context for bit-packing into S.  */
+static inline struct bitpack_d
+bitpack_create (struct lto_output_stream *s)
+{
+  struct bitpack_d bp;
+  bp.pos = 0;
+  bp.word = 0;
+  bp.stream = (void *)s;
+  return bp;
+}
+
+/* Pack the NBITS bit sized value VAL into the bit-packing context BP.  */
+static inline void
+bp_pack_value (struct bitpack_d *bp, bitpack_word_t val, unsigned nbits)
+{
+  bitpack_word_t word = bp->word;
+  int pos = bp->pos;
+
+  /* Verify that VAL fits in the NBITS.  */
+  gcc_checking_assert (nbits == BITS_PER_BITPACK_WORD
+		       || !(val & ~(((bitpack_word_t)1<<nbits)-1)));
+
+  /* If val does not fit into the current bitpack word switch to the
+     next one.  */
+  if (pos + nbits > BITS_PER_BITPACK_WORD)
+    {
+      lto_output_uleb128_stream ((struct lto_output_stream *) bp->stream, word);
+      word = val;
+      pos = nbits;
+    }
+  else
+    {
+      word |= val << pos;
+      pos += nbits;
+    }
+  bp->word = word;
+  bp->pos = pos;
+}
+
+/* Finishes bit-packing of BP.  */
+static inline void
+lto_output_bitpack (struct bitpack_d *bp)
+{
+  lto_output_uleb128_stream ((struct lto_output_stream *) bp->stream,
+			     bp->word);
+  bp->word = 0;
+  bp->pos = 0;
+}
+
+/* Returns a new bit-packing context for bit-unpacking from IB.  */
+static inline struct bitpack_d
+lto_input_bitpack (struct lto_input_block *ib)
+{
+  struct bitpack_d bp;
+  bp.word = lto_input_uleb128 (ib);
+  bp.pos = 0;
+  bp.stream = (void *)ib;
+  return bp;
+}
+
+/* Unpacks NBITS bits from the bit-packing context BP and returns them.  */
+static inline bitpack_word_t
+bp_unpack_value (struct bitpack_d *bp, unsigned nbits)
+{
+  bitpack_word_t mask, val;
+  int pos = bp->pos;
+
+  mask = (nbits == BITS_PER_BITPACK_WORD
+	  ? (bitpack_word_t) -1
+	  : ((bitpack_word_t) 1 << nbits) - 1);
+
+  /* If there are not continuous nbits in the current bitpack word
+     switch to the next one.  */
+  if (pos + nbits > BITS_PER_BITPACK_WORD)
+    {
+      bp->word = val = lto_input_uleb128 ((struct lto_input_block *)bp->stream);
+      bp->pos = nbits;
+      return val & mask;
+    }
+  val = bp->word;
+  val >>= pos;
+  bp->pos = pos + nbits;
+
+  return val & mask;
+}
+
+
+/* Write a character to the output block.  */
+
+static inline void
+lto_output_1_stream (struct lto_output_stream *obs, char c)
+{
+  /* No space left.  */
+  if (obs->left_in_block == 0)
+    lto_append_block (obs);
+
+  /* Write the actual character.  */
+  *obs->current_pointer = c;
+  obs->current_pointer++;
+  obs->total_size++;
+  obs->left_in_block--;
+}
+
+
+/* Read byte from the input block.  */
+
+static inline unsigned char
+lto_input_1_unsigned (struct lto_input_block *ib)
+{
+  if (ib->p >= ib->len)
+    lto_section_overrun (ib);
+  return (ib->data[ib->p++]);
+}
+
+/* Output VAL into OBS and verify it is in range MIN...MAX that is supposed
+   to be compile time constant.
+   Be host independent, limit range to 31bits.  */
+
+static inline void
+lto_output_int_in_range (struct lto_output_stream *obs,
+			 HOST_WIDE_INT min,
+			 HOST_WIDE_INT max,
+			 HOST_WIDE_INT val)
+{
+  HOST_WIDE_INT range = max - min;
+
+  gcc_checking_assert (val >= min && val <= max && range > 0
+		       && range < 0x7fffffff);
+
+  val -= min;
+  lto_output_1_stream (obs, val & 255);
+  if (range >= 0xff)
+    lto_output_1_stream (obs, (val >> 8) & 255);
+  if (range >= 0xffff)
+    lto_output_1_stream (obs, (val >> 16) & 255);
+  if (range >= 0xffffff)
+    lto_output_1_stream (obs, (val >> 24) & 255);
+}
+
+/* Input VAL into OBS and verify it is in range MIN...MAX that is supposed
+   to be compile time constant.  PURPOSE is used for error reporting.  */
+
+static inline HOST_WIDE_INT
+lto_input_int_in_range (struct lto_input_block *ib,
+			const char *purpose,
+			HOST_WIDE_INT min,
+			HOST_WIDE_INT max)
+{
+  HOST_WIDE_INT range = max - min;
+  HOST_WIDE_INT val = lto_input_1_unsigned (ib);
+
+  gcc_checking_assert (range > 0 && range < 0x7fffffff);
+
+  if (range >= 0xff)
+    val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 8;
+  if (range >= 0xffff)
+    val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 16;
+  if (range >= 0xffffff)
+    val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 24;
+  val += min;
+  if (val < min || val > max)
+    lto_value_range_error (purpose, val, min, max);
+  return val;
+}
+
+/* Output VAL into BP and verify it is in range MIN...MAX that is supposed
+   to be compile time constant.
+   Be host independent, limit range to 31bits.  */
+
+static inline void
+bp_pack_int_in_range (struct bitpack_d *bp,
+		      HOST_WIDE_INT min,
+		      HOST_WIDE_INT max,
+		      HOST_WIDE_INT val)
+{
+  HOST_WIDE_INT range = max - min;
+  int nbits = floor_log2 (range) + 1;
+
+  gcc_checking_assert (val >= min && val <= max && range > 0
+		       && range < 0x7fffffff);
+
+  val -= min;
+  bp_pack_value (bp, val, nbits);
+}
+
+/* Input VAL into BP and verify it is in range MIN...MAX that is supposed
+   to be compile time constant.  PURPOSE is used for error reporting.  */
+
+static inline HOST_WIDE_INT
+bp_unpack_int_in_range (struct bitpack_d *bp,
+		        const char *purpose,
+		        HOST_WIDE_INT min,
+		        HOST_WIDE_INT max)
+{
+  HOST_WIDE_INT range = max - min;
+  int nbits = floor_log2 (range) + 1;
+  HOST_WIDE_INT val = bp_unpack_value (bp, nbits);
+
+  gcc_checking_assert (range > 0 && range < 0x7fffffff);
+
+  if (val < min || val > max)
+    lto_value_range_error (purpose, val, min, max);
+  return val;
+}
+
+/* Output VAL of type "enum enum_name" into OBS.
+   Assume range 0...ENUM_LAST - 1.  */
+#define lto_output_enum(obs,enum_name,enum_last,val) \
+  lto_output_int_in_range ((obs), 0, (int)(enum_last) - 1, (int)(val))
+
+/* Input enum of type "enum enum_name" from IB.
+   Assume range 0...ENUM_LAST - 1.  */
+#define lto_input_enum(ib,enum_name,enum_last) \
+  (enum enum_name)lto_input_int_in_range ((ib), #enum_name, 0, \
+					  (int)(enum_last) - 1)
+
+/* Output VAL of type "enum enum_name" into BP.
+   Assume range 0...ENUM_LAST - 1.  */
+#define bp_pack_enum(bp,enum_name,enum_last,val) \
+  bp_pack_int_in_range ((bp), 0, (int)(enum_last) - 1, (int)(val))
+
+/* Input enum of type "enum enum_name" from BP.
+   Assume range 0...ENUM_LAST - 1.  */
+#define bp_unpack_enum(bp,enum_name,enum_last) \
+  (enum enum_name)bp_unpack_int_in_range ((bp), #enum_name, 0, \
+					(int)(enum_last) - 1)
+
+/* Output the start of a record with TAG to output block OB.  */
+
+static inline void
+output_record_start (struct output_block *ob, enum LTO_tags tag)
+{
+  lto_output_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS, tag);
+}
+
+/* Return the next tag in the input block IB.  */
+
+static inline enum LTO_tags
+input_record_start (struct lto_input_block *ib)
+{
+  return lto_input_enum (ib, LTO_tags, LTO_NUM_TAGS);
+}
+
+/* In data-streamer.c  */
+void bp_pack_var_len_unsigned (struct bitpack_d *, unsigned HOST_WIDE_INT);
+void bp_pack_var_len_int (struct bitpack_d *, HOST_WIDE_INT);
+unsigned HOST_WIDE_INT bp_unpack_var_len_unsigned (struct bitpack_d *);
+HOST_WIDE_INT bp_unpack_var_len_int (struct bitpack_d *);
+
+/* In data-streamer-out.c  */
+void output_zero (struct output_block *);
+void output_uleb128 (struct output_block *, unsigned HOST_WIDE_INT);
+void output_sleb128 (struct output_block *, HOST_WIDE_INT);
+void lto_output_string (struct output_block *, struct lto_output_stream *,
+			const char *, bool);
+unsigned lto_string_index (struct output_block *, const char *, unsigned int,
+			   bool);
+void lto_output_string_with_length (struct output_block *,
+				    struct lto_output_stream *,
+				    const char *, unsigned int, bool);
+const char *input_string_internal (struct data_in *, struct lto_input_block *,
+				   unsigned int *);
+
+/* In data-streamer-in.c  */
+const char *string_for_index (struct data_in *, unsigned int, unsigned int *);
+const char *lto_input_string (struct data_in *, struct lto_input_block *);
+
+#endif  /* GCC_DATA_STREAMER_H  */
diff --git a/gcc/gimple-streamer-in.c b/gcc/gimple-streamer-in.c
new file mode 100644
index 0000000..dd91c73
--- /dev/null
+++ b/gcc/gimple-streamer-in.c
@@ -0,0 +1,333 @@
+/* Routines for reading GIMPLE from a file stream.
+
+   Copyright 2011 Free Software Foundation, Inc.
+   Contributed by Diego Novillo <dnovillo@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostic.h"
+#include "tree.h"
+#include "tree-flow.h"
+#include "data-streamer.h"
+#include "tree-streamer.h"
+#include "gimple-streamer.h"
+
+/* Read a PHI function for basic block BB in function FN.  DATA_IN is
+   the file being read.  IB is the input block to use for reading.  */
+
+static gimple
+input_phi (struct lto_input_block *ib, basic_block bb, struct data_in *data_in,
+	   struct function *fn)
+{
+  unsigned HOST_WIDE_INT ix;
+  tree phi_result;
+  int i, len;
+  gimple result;
+
+  ix = lto_input_uleb128 (ib);
+  phi_result = VEC_index (tree, SSANAMES (fn), ix);
+  len = EDGE_COUNT (bb->preds);
+  result = create_phi_node (phi_result, bb);
+  SSA_NAME_DEF_STMT (phi_result) = result;
+
+  /* We have to go through a lookup process here because the preds in the
+     reconstructed graph are generally in a different order than they
+     were in the original program.  */
+  for (i = 0; i < len; i++)
+    {
+      tree def = lto_input_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);
+
+      edge e = NULL;
+      int j;
+
+      for (j = 0; j < len; j++)
+	if (EDGE_PRED (bb, j)->src == sbb)
+	  {
+	    e = EDGE_PRED (bb, j);
+	    break;
+	  }
+
+      add_phi_arg (result, def, e, arg_loc);
+    }
+
+  return result;
+}
+
+
+/* Read a statement with tag TAG in function FN from block IB using
+   descriptors in DATA_IN.  */
+
+static gimple
+input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
+		   struct function *fn, enum LTO_tags tag)
+{
+  gimple stmt;
+  enum gimple_code code;
+  unsigned HOST_WIDE_INT num_ops;
+  size_t i;
+  struct bitpack_d bp;
+
+  code = lto_tag_to_gimple_code (tag);
+
+  /* Read the tuple header.  */
+  bp = lto_input_bitpack (ib);
+  num_ops = bp_unpack_var_len_unsigned (&bp);
+  stmt = gimple_alloc (code, num_ops);
+  stmt->gsbase.no_warning = bp_unpack_value (&bp, 1);
+  if (is_gimple_assign (stmt))
+    stmt->gsbase.nontemporal_move = bp_unpack_value (&bp, 1);
+  stmt->gsbase.has_volatile_ops = bp_unpack_value (&bp, 1);
+  stmt->gsbase.subcode = bp_unpack_var_len_unsigned (&bp);
+
+  /* Read location information.  */
+  gimple_set_location (stmt, lto_input_location (ib, data_in));
+
+  /* Read lexical block reference.  */
+  gimple_set_block (stmt, lto_input_tree (ib, data_in));
+
+  /* Read in all the operands.  */
+  switch (code)
+    {
+    case GIMPLE_RESX:
+      gimple_resx_set_region (stmt, lto_input_sleb128 (ib));
+      break;
+
+    case GIMPLE_EH_MUST_NOT_THROW:
+      gimple_eh_must_not_throw_set_fndecl (stmt, lto_input_tree (ib, data_in));
+      break;
+
+    case GIMPLE_EH_DISPATCH:
+      gimple_eh_dispatch_set_region (stmt, lto_input_sleb128 (ib));
+      break;
+
+    case GIMPLE_ASM:
+      {
+	/* FIXME lto.  Move most of this into a new gimple_asm_set_string().  */
+	tree str;
+	stmt->gimple_asm.ni = lto_input_uleb128 (ib);
+	stmt->gimple_asm.no = lto_input_uleb128 (ib);
+	stmt->gimple_asm.nc = lto_input_uleb128 (ib);
+	stmt->gimple_asm.nl = lto_input_uleb128 (ib);
+	str = input_string_cst (data_in, ib);
+	stmt->gimple_asm.string = TREE_STRING_POINTER (str);
+      }
+      /* Fallthru  */
+
+    case GIMPLE_ASSIGN:
+    case GIMPLE_CALL:
+    case GIMPLE_RETURN:
+    case GIMPLE_SWITCH:
+    case GIMPLE_LABEL:
+    case GIMPLE_COND:
+    case GIMPLE_GOTO:
+    case GIMPLE_DEBUG:
+      for (i = 0; i < num_ops; i++)
+	{
+	  tree op = lto_input_tree (ib, data_in);
+	  gimple_set_op (stmt, i, op);
+	  if (!op)
+	    continue;
+
+	  /* Fixup FIELD_DECLs in COMPONENT_REFs, they are not handled
+	     by decl merging.  */
+	  if (TREE_CODE (op) == ADDR_EXPR)
+	    op = TREE_OPERAND (op, 0);
+	  while (handled_component_p (op))
+	    {
+	      if (TREE_CODE (op) == COMPONENT_REF)
+		{
+		  tree field, type, tem;
+		  tree closest_match = NULL_TREE;
+		  field = TREE_OPERAND (op, 1);
+		  type = DECL_CONTEXT (field);
+		  for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
+		    {
+		      if (tem == field)
+			break;
+		      if (DECL_NONADDRESSABLE_P (tem)
+			  == DECL_NONADDRESSABLE_P (field)
+			  && gimple_compare_field_offset (tem, field))
+			{
+			  if (types_compatible_p (TREE_TYPE (tem),
+						  TREE_TYPE (field)))
+			    break;
+			  else
+			    closest_match = tem;
+			}
+		    }
+		  /* In case of type mismatches across units we can fail
+		     to unify some types and thus not find a proper
+		     field-decl here.  */
+		  if (tem == NULL_TREE)
+		    {
+		      /* Thus, emit a ODR violation warning.  */
+		      if (warning_at (gimple_location (stmt), 0,
+				      "use of type %<%E%> with two mismatching "
+				      "declarations at field %<%E%>",
+				      type, TREE_OPERAND (op, 1)))
+			{
+			  if (TYPE_FIELDS (type))
+			    inform (DECL_SOURCE_LOCATION (TYPE_FIELDS (type)),
+				    "original type declared here");
+			  inform (DECL_SOURCE_LOCATION (TREE_OPERAND (op, 1)),
+				  "field in mismatching type declared here");
+			  if (TYPE_NAME (TREE_TYPE (field))
+			      && (TREE_CODE (TYPE_NAME (TREE_TYPE (field)))
+				  == TYPE_DECL))
+			    inform (DECL_SOURCE_LOCATION
+				      (TYPE_NAME (TREE_TYPE (field))),
+				    "type of field declared here");
+			  if (closest_match
+			      && TYPE_NAME (TREE_TYPE (closest_match))
+			      && (TREE_CODE (TYPE_NAME
+				   (TREE_TYPE (closest_match))) == TYPE_DECL))
+			    inform (DECL_SOURCE_LOCATION
+				      (TYPE_NAME (TREE_TYPE (closest_match))),
+				    "type of mismatching field declared here");
+			}
+		      /* And finally fixup the types.  */
+		      TREE_OPERAND (op, 0)
+			= build1 (VIEW_CONVERT_EXPR, type,
+				  TREE_OPERAND (op, 0));
+		    }
+		  else
+		    TREE_OPERAND (op, 1) = tem;
+		}
+
+	      op = TREE_OPERAND (op, 0);
+	    }
+	}
+      if (is_gimple_call (stmt))
+	{
+	  if (gimple_call_internal_p (stmt))
+	    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));
+	}
+      break;
+
+    case GIMPLE_NOP:
+    case GIMPLE_PREDICT:
+      break;
+
+    default:
+      internal_error ("bytecode stream: unknown GIMPLE statement tag %s",
+		      lto_tag_name (tag));
+    }
+
+  /* Update the properties of symbols, SSA names and labels associated
+     with STMT.  */
+  if (code == GIMPLE_ASSIGN || code == GIMPLE_CALL)
+    {
+      tree lhs = gimple_get_lhs (stmt);
+      if (lhs && TREE_CODE (lhs) == SSA_NAME)
+	SSA_NAME_DEF_STMT (lhs) = stmt;
+    }
+  else if (code == GIMPLE_LABEL)
+    gcc_assert (emit_label_in_global_context_p (gimple_label_label (stmt))
+	        || DECL_CONTEXT (gimple_label_label (stmt)) == fn->decl);
+  else if (code == GIMPLE_ASM)
+    {
+      unsigned i;
+
+      for (i = 0; i < gimple_asm_noutputs (stmt); i++)
+	{
+	  tree op = TREE_VALUE (gimple_asm_output_op (stmt, i));
+	  if (TREE_CODE (op) == SSA_NAME)
+	    SSA_NAME_DEF_STMT (op) = stmt;
+	}
+    }
+
+  /* Reset alias information.  */
+  if (code == GIMPLE_CALL)
+    gimple_call_reset_alias_info (stmt);
+
+  /* Mark the statement modified so its operand vectors can be filled in.  */
+  gimple_set_modified (stmt, true);
+
+  return stmt;
+}
+
+
+/* Read a basic block with tag TAG from DATA_IN using input block IB.
+   FN is the function being processed.  */
+
+void
+input_bb (struct lto_input_block *ib, enum LTO_tags tag,
+	  struct data_in *data_in, struct function *fn,
+	  int count_materialization_scale)
+{
+  unsigned int index;
+  basic_block bb;
+  gimple_stmt_iterator bsi;
+
+  /* This routine assumes that CFUN is set to FN, as it needs to call
+     basic GIMPLE routines that use CFUN.  */
+  gcc_assert (cfun == fn);
+
+  index = lto_input_uleb128 (ib);
+  bb = BASIC_BLOCK_FOR_FUNCTION (fn, index);
+
+  bb->count = (lto_input_sleb128 (ib) * count_materialization_scale
+	       + REG_BR_PROB_BASE / 2) / REG_BR_PROB_BASE;
+  bb->loop_depth = lto_input_sleb128 (ib);
+  bb->frequency = lto_input_sleb128 (ib);
+  bb->flags = lto_input_sleb128 (ib);
+
+  /* LTO_bb1 has statements.  LTO_bb0 does not.  */
+  if (tag == LTO_bb0)
+    return;
+
+  bsi = gsi_start_bb (bb);
+  tag = input_record_start (ib);
+  while (tag)
+    {
+      gimple stmt = input_gimple_stmt (ib, data_in, fn, tag);
+      if (!is_gimple_debug (stmt))
+	find_referenced_vars_in (stmt);
+      gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
+
+      /* After the statement, expect a 0 delimiter or the EH region
+	 that the previous statement belongs to.  */
+      tag = input_record_start (ib);
+      lto_tag_check_set (tag, 2, LTO_eh_region, LTO_null);
+
+      if (tag == LTO_eh_region)
+	{
+	  HOST_WIDE_INT region = lto_input_sleb128 (ib);
+	  gcc_assert (region == (int) region);
+	  add_stmt_to_eh_lp (stmt, region);
+	}
+
+      tag = input_record_start (ib);
+    }
+
+  tag = input_record_start (ib);
+  while (tag)
+    {
+      gimple phi = input_phi (ib, bb, data_in, fn);
+      find_referenced_vars_in (phi);
+      tag = input_record_start (ib);
+    }
+}
diff --git a/gcc/gimple-streamer-out.c b/gcc/gimple-streamer-out.c
new file mode 100644
index 0000000..0a41510
--- /dev/null
+++ b/gcc/gimple-streamer-out.c
@@ -0,0 +1,213 @@
+/* Routines for emitting GIMPLE to a file stream.
+
+   Copyright 2011 Free Software Foundation, Inc.
+   Contributed by Diego Novillo <dnovillo@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "tree-flow.h"
+#include "data-streamer.h"
+#include "gimple-streamer.h"
+#include "lto-streamer.h"
+
+/* Output PHI function PHI to the main stream in OB.  */
+
+static void
+output_phi (struct output_block *ob, gimple phi)
+{
+  unsigned i, len = gimple_phi_num_args (phi);
+
+  output_record_start (ob, lto_gimple_code_to_tag (GIMPLE_PHI));
+  output_uleb128 (ob, SSA_NAME_VERSION (PHI_RESULT (phi)));
+
+  for (i = 0; i < len; i++)
+    {
+      lto_output_tree_ref (ob, gimple_phi_arg_def (phi, i));
+      output_uleb128 (ob, gimple_phi_arg_edge (phi, i)->src->index);
+      lto_output_location (ob, gimple_phi_arg_location (phi, i));
+    }
+}
+
+
+/* Emit statement STMT on the main stream of output block OB.  */
+
+static void
+output_gimple_stmt (struct output_block *ob, gimple stmt)
+{
+  unsigned i;
+  enum gimple_code code;
+  enum LTO_tags tag;
+  struct bitpack_d bp;
+
+  /* Emit identifying tag.  */
+  code = gimple_code (stmt);
+  tag = lto_gimple_code_to_tag (code);
+  output_record_start (ob, tag);
+
+  /* Emit the tuple header.  */
+  bp = bitpack_create (ob->main_stream);
+  bp_pack_var_len_unsigned (&bp, gimple_num_ops (stmt));
+  bp_pack_value (&bp, gimple_no_warning_p (stmt), 1);
+  if (is_gimple_assign (stmt))
+    bp_pack_value (&bp, gimple_assign_nontemporal_move_p (stmt), 1);
+  bp_pack_value (&bp, gimple_has_volatile_ops (stmt), 1);
+  bp_pack_var_len_unsigned (&bp, stmt->gsbase.subcode);
+  lto_output_bitpack (&bp);
+
+  /* Emit location information for the statement.  */
+  lto_output_location (ob, gimple_location (stmt));
+
+  /* Emit the lexical block holding STMT.  */
+  lto_output_tree (ob, gimple_block (stmt), true);
+
+  /* Emit the operands.  */
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_RESX:
+      output_sleb128 (ob, gimple_resx_region (stmt));
+      break;
+
+    case GIMPLE_EH_MUST_NOT_THROW:
+      lto_output_tree_ref (ob, gimple_eh_must_not_throw_fndecl (stmt));
+      break;
+
+    case GIMPLE_EH_DISPATCH:
+      output_sleb128 (ob, gimple_eh_dispatch_region (stmt));
+      break;
+
+    case GIMPLE_ASM:
+      lto_output_uleb128_stream (ob->main_stream, gimple_asm_ninputs (stmt));
+      lto_output_uleb128_stream (ob->main_stream, gimple_asm_noutputs (stmt));
+      lto_output_uleb128_stream (ob->main_stream, gimple_asm_nclobbers (stmt));
+      lto_output_uleb128_stream (ob->main_stream, gimple_asm_nlabels (stmt));
+      lto_output_string (ob, ob->main_stream, gimple_asm_string (stmt), true);
+      /* Fallthru  */
+
+    case GIMPLE_ASSIGN:
+    case GIMPLE_CALL:
+    case GIMPLE_RETURN:
+    case GIMPLE_SWITCH:
+    case GIMPLE_LABEL:
+    case GIMPLE_COND:
+    case GIMPLE_GOTO:
+    case GIMPLE_DEBUG:
+      for (i = 0; i < gimple_num_ops (stmt); i++)
+	{
+	  tree op = gimple_op (stmt, i);
+	  /* Wrap all uses of non-automatic variables inside MEM_REFs
+	     so that we do not have to deal with type mismatches on
+	     merged symbols during IL read in.  The first operand
+	     of GIMPLE_DEBUG must be a decl, not MEM_REF, though.  */
+	  if (op && (i || !is_gimple_debug (stmt)))
+	    {
+	      tree *basep = &op;
+	      while (handled_component_p (*basep))
+		basep = &TREE_OPERAND (*basep, 0);
+	      if (TREE_CODE (*basep) == VAR_DECL
+		  && !auto_var_in_fn_p (*basep, current_function_decl)
+		  && !DECL_REGISTER (*basep))
+		{
+		  bool volatilep = TREE_THIS_VOLATILE (*basep);
+		  *basep = build2 (MEM_REF, TREE_TYPE (*basep),
+				   build_fold_addr_expr (*basep),
+				   build_int_cst (build_pointer_type
+						  (TREE_TYPE (*basep)), 0));
+		  TREE_THIS_VOLATILE (*basep) = volatilep;
+		}
+	    }
+	  lto_output_tree_ref (ob, op);
+	}
+      if (is_gimple_call (stmt))
+	{
+	  if (gimple_call_internal_p (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));
+	}
+      break;
+
+    case GIMPLE_NOP:
+    case GIMPLE_PREDICT:
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+
+/* Output a basic block BB to the main stream in OB for this FN.  */
+
+void
+output_bb (struct output_block *ob, basic_block bb, struct function *fn)
+{
+  gimple_stmt_iterator bsi = gsi_start_bb (bb);
+
+  output_record_start (ob,
+		       (!gsi_end_p (bsi)) || phi_nodes (bb)
+		        ? LTO_bb1
+			: LTO_bb0);
+
+  output_uleb128 (ob, bb->index);
+  output_sleb128 (ob, bb->count);
+  output_sleb128 (ob, bb->loop_depth);
+  output_sleb128 (ob, bb->frequency);
+  output_sleb128 (ob, bb->flags);
+
+  if (!gsi_end_p (bsi) || phi_nodes (bb))
+    {
+      /* Output the statements.  The list of statements is terminated
+	 with a zero.  */
+      for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+	{
+	  int region;
+	  gimple stmt = gsi_stmt (bsi);
+
+	  output_gimple_stmt (ob, stmt);
+
+	  /* Emit the EH region holding STMT.  */
+	  region = lookup_stmt_eh_lp_fn (fn, stmt);
+	  if (region != 0)
+	    {
+	      output_record_start (ob, LTO_eh_region);
+	      output_sleb128 (ob, region);
+	    }
+	  else
+	    output_record_start (ob, LTO_null);
+	}
+
+      output_record_start (ob, LTO_null);
+
+      for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+	{
+	  gimple phi = gsi_stmt (bsi);
+
+	  /* Only emit PHIs for gimple registers.  PHI nodes for .MEM
+	     will be filled in on reading when the SSA form is
+	     updated.  */
+	  if (is_gimple_reg (gimple_phi_result (phi)))
+	    output_phi (ob, phi);
+	}
+
+      output_record_start (ob, LTO_null);
+    }
+}
diff --git a/gcc/gimple-streamer.h b/gcc/gimple-streamer.h
new file mode 100644
index 0000000..257fdbc
--- /dev/null
+++ b/gcc/gimple-streamer.h
@@ -0,0 +1,36 @@
+/* Data structures and functions for streaming GIMPLE.
+
+   Copyright 2011 Free Software Foundation, Inc.
+   Contributed by Diego Novillo <dnovillo@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_GIMPLE_STREAMER_H
+#define GCC_GIMPLE_STREAMER_H
+
+#include "basic-block.h"
+#include "function.h"
+#include "lto-streamer.h"
+
+/* In gimple-streamer-in.c  */
+void input_bb (struct lto_input_block *, enum LTO_tags, struct data_in *,
+	       struct function *, int);
+
+/* In gimple-streamer-out.c  */
+void output_bb (struct output_block *, basic_block, struct function *);
+
+#endif  /* GCC_GIMPLE_STREAMER_H  */
diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
index df96c99..bc65a45 100644
--- a/gcc/ipa-inline-analysis.c
+++ b/gcc/ipa-inline-analysis.c
@@ -84,6 +84,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-flow.h"
 #include "ipa-prop.h"
 #include "lto-streamer.h"
+#include "data-streamer.h"
+#include "tree-streamer.h"
 #include "ipa-inline.h"
 #include "alloc-pool.h"
 
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index def34c3..7f9f547 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pretty-print.h"
 #include "gimple-pretty-print.h"
 #include "lto-streamer.h"
+#include "data-streamer.h"
+#include "tree-streamer.h"
 
 
 /* Intermediate information about a parameter that is only useful during the
diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index 0414273..4f02c7b 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -54,6 +54,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "target.h"
 #include "lto-streamer.h"
+#include "data-streamer.h"
+#include "tree-streamer.h"
 #include "cfgloop.h"
 #include "tree-scalar-evolution.h"
 #include "intl.h"
diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
index 9d9cb43..c4da1ff 100644
--- a/gcc/lto-cgraph.c
+++ b/gcc/lto-cgraph.c
@@ -43,6 +43,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "pointer-set.h"
 #include "lto-streamer.h"
+#include "data-streamer.h"
+#include "tree-streamer.h"
 #include "gcov-io.h"
 
 static void output_varpool (cgraph_node_set, varpool_node_set);
diff --git a/gcc/lto-section-in.c b/gcc/lto-section-in.c
index 0c2c4c0..1c285fa 100644
--- a/gcc/lto-section-in.c
+++ b/gcc/lto-section-in.c
@@ -63,115 +63,6 @@ const char *lto_section_name[LTO_N_SECTION_TYPES] =
 };
 
 
-/* Read an ULEB128 Number of IB.  */
-
-unsigned HOST_WIDE_INT
-lto_input_uleb128 (struct lto_input_block *ib)
-{
-  unsigned HOST_WIDE_INT result = 0;
-  int shift = 0;
-  unsigned HOST_WIDE_INT byte;
-
-  while (true)
-    {
-      byte = lto_input_1_unsigned (ib);
-      result |= (byte & 0x7f) << shift;
-      shift += 7;
-      if ((byte & 0x80) == 0)
-	return result;
-    }
-}
-
-/* HOST_WIDEST_INT version of lto_input_uleb128.  IB is as in
-   lto_input_uleb128.  */
-
-unsigned HOST_WIDEST_INT
-lto_input_widest_uint_uleb128 (struct lto_input_block *ib)
-{
-  unsigned HOST_WIDEST_INT result = 0;
-  int shift = 0;
-  unsigned HOST_WIDEST_INT byte;
-
-  while (true)
-    {
-      byte = lto_input_1_unsigned (ib);
-      result |= (byte & 0x7f) << shift;
-      shift += 7;
-      if ((byte & 0x80) == 0)
-	return result;
-    }
-}
-
-/* Read an SLEB128 Number of IB.  */
-
-HOST_WIDE_INT
-lto_input_sleb128 (struct lto_input_block *ib)
-{
-  HOST_WIDE_INT result = 0;
-  int shift = 0;
-  unsigned HOST_WIDE_INT byte;
-
-  while (true)
-    {
-      byte = lto_input_1_unsigned (ib);
-      result |= (byte & 0x7f) << shift;
-      shift += 7;
-      if ((byte & 0x80) == 0)
-	{
-	  if ((shift < HOST_BITS_PER_WIDE_INT) && (byte & 0x40))
-	    result |= - ((HOST_WIDE_INT)1 << shift);
-
-	  return result;
-	}
-    }
-}
-
-
-/* Unpack VAL from BP in a variant of uleb format.  */
-
-unsigned HOST_WIDE_INT
-bp_unpack_var_len_unsigned (struct bitpack_d *bp)
-{
-  unsigned HOST_WIDE_INT result = 0;
-  int shift = 0;
-  unsigned HOST_WIDE_INT half_byte;
-
-  while (true)
-    {
-      half_byte = bp_unpack_value (bp, 4);
-      result |= (half_byte & 0x7) << shift;
-      shift += 3;
-      if ((half_byte & 0x8) == 0)
-	return result;
-    }
-}
-
-
-/* Unpack VAL from BP in a variant of sleb format.  */
-
-HOST_WIDE_INT
-bp_unpack_var_len_int (struct bitpack_d *bp)
-{
-  HOST_WIDE_INT result = 0;
-  int shift = 0;
-  unsigned HOST_WIDE_INT half_byte;
-
-  while (true)
-    {
-      half_byte = bp_unpack_value (bp, 4);
-      result |= (half_byte & 0x7) << shift;
-      shift += 3;
-      if ((half_byte & 0x8) == 0)
-	{
-	  if ((shift < HOST_BITS_PER_WIDE_INT) && (half_byte & 0x4))
-	    result |= - ((HOST_WIDE_INT)1 << shift);
-
-	  return result;
-	}
-    }
-}
-
-
 /* Hooks so that the ipa passes can call into the lto front end to get
    sections.  */
 
diff --git a/gcc/lto-section-out.c b/gcc/lto-section-out.c
index 55c9d8d..7f44d6e 100644
--- a/gcc/lto-section-out.c
+++ b/gcc/lto-section-out.c
@@ -265,113 +265,6 @@ lto_output_data_stream (struct lto_output_stream *obs, const void *data,
 }
 
 
-/* Output an unsigned LEB128 quantity to OBS.  */
-
-void
-lto_output_uleb128_stream (struct lto_output_stream *obs,
-			   unsigned HOST_WIDE_INT work)
-{
-  do
-    {
-      unsigned int byte = (work & 0x7f);
-      work >>= 7;
-      if (work != 0)
-	/* More bytes to follow.  */
-	byte |= 0x80;
-
-      lto_output_1_stream (obs, byte);
-    }
-  while (work != 0);
-}
-
-/* Identical to output_uleb128_stream above except using unsigned
-   HOST_WIDEST_INT type.  For efficiency on host where unsigned HOST_WIDEST_INT
-   is not native, we only use this if we know that HOST_WIDE_INT is not wide
-   enough.  */
-
-void
-lto_output_widest_uint_uleb128_stream (struct lto_output_stream *obs,
-				       unsigned HOST_WIDEST_INT work)
-{
-  do
-    {
-      unsigned int byte = (work & 0x7f);
-      work >>= 7;
-      if (work != 0)
-	/* More bytes to follow.  */
-	byte |= 0x80;
-
-      lto_output_1_stream (obs, byte);
-    }
-  while (work != 0);
-}
-
-
-/* Output a signed LEB128 quantity.  */
-
-void
-lto_output_sleb128_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
-{
-  int more, byte;
-
-  do
-    {
-      byte = (work & 0x7f);
-      /* arithmetic shift */
-      work >>= 7;
-      more = !((work == 0 && (byte & 0x40) == 0)
-	       || (work == -1 && (byte & 0x40) != 0));
-      if (more)
-	byte |= 0x80;
-
-      lto_output_1_stream (obs, byte);
-    }
-  while (more);
-}
-
-
-/* Pack WORK into BP in a variant of uleb format.  */
-
-void
-bp_pack_var_len_unsigned (struct bitpack_d *bp, unsigned HOST_WIDE_INT work)
-{
-  do
-    {
-      unsigned int half_byte = (work & 0x7);
-      work >>= 3;
-      if (work != 0)
-	/* More half_bytes to follow.  */
-	half_byte |= 0x8;
-
-      bp_pack_value (bp, half_byte, 4);
-    }
-  while (work != 0);
-}
-
-
-/* Pack WORK into BP in a variant of sleb format.  */
-
-void
-bp_pack_var_len_int (struct bitpack_d *bp, HOST_WIDE_INT work)
-{
-  int more, half_byte;
-
-  do
-    {
-      half_byte = (work & 0x7);
-      /* arithmetic shift */
-      work >>= 3;
-      more = !((work == 0 && (half_byte & 0x4) == 0)
-	       || (work == -1 && (half_byte & 0x4) != 0));
-      if (more)
-	half_byte |= 0x8;
-
-      bp_pack_value (bp, half_byte, 4);
-    }
-  while (more);
-}
-
-
 /* Lookup NAME in ENCODER.  If NAME is not found, create a new entry in
    ENCODER for NAME with the next available index of ENCODER,  then
    print the index to OBS.  True is returned if NAME was added to
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index d249033..1330d60 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -45,16 +45,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "timevar.h"
 #include "output.h"
 #include "ipa-utils.h"
+#include "data-streamer.h"
+#include "gimple-streamer.h"
 #include "lto-streamer.h"
+#include "tree-streamer.h"
 #include "tree-pass.h"
 
-/* Data structure used to hash file names in the source_location field.  */
-struct string_slot
-{
-  const char *s;
-  unsigned int slot_num;
-};
-
 /* The table to hold the file names.  */
 static htab_t file_name_hash_table;
 
@@ -62,7 +58,7 @@ static htab_t file_name_hash_table;
 /* Check that tag ACTUAL has one of the given values.  NUM_TAGS is the
    number of valid tag values to check.  */
 
-static void
+void
 lto_tag_check_set (enum LTO_tags actual, int ntags, ...)
 {
   va_list ap;
@@ -81,128 +77,6 @@ lto_tag_check_set (enum LTO_tags actual, int ntags, ...)
 }
 
 
-/* Check that tag ACTUAL is in the range [TAG1, TAG2].  */
-
-static void
-lto_tag_check_range (enum LTO_tags actual, enum LTO_tags tag1,
-		     enum LTO_tags tag2)
-{
-  if (actual < tag1 || actual > tag2)
-    internal_error ("bytecode stream: tag %s is not in the expected range "
-		    "[%s, %s]",
-		    lto_tag_name (actual),
-		    lto_tag_name (tag1),
-		    lto_tag_name (tag2));
-}
-
-
-/* Check that tag ACTUAL == EXPECTED.  */
-
-static void
-lto_tag_check (enum LTO_tags actual, enum LTO_tags expected)
-{
-  if (actual != expected)
-    internal_error ("bytecode stream: expected tag %s instead of %s",
-		    lto_tag_name (expected), lto_tag_name (actual));
-}
-
-
-/* Return a hash code for P.  */
-
-static hashval_t
-hash_string_slot_node (const void *p)
-{
-  const struct string_slot *ds = (const struct string_slot *) p;
-  return (hashval_t) htab_hash_string (ds->s);
-}
-
-
-/* Returns nonzero if P1 and P2 are equal.  */
-
-static int
-eq_string_slot_node (const void *p1, const void *p2)
-{
-  const struct string_slot *ds1 = (const struct string_slot *) p1;
-  const struct string_slot *ds2 = (const struct string_slot *) p2;
-  return strcmp (ds1->s, ds2->s) == 0;
-}
-
-
-/* Read a string from the string table in DATA_IN using input block
-   IB.  Write the length to RLEN.  */
-
-static const char *
-string_for_index (struct data_in *data_in,
-		  unsigned int loc,
-		  unsigned int *rlen)
-{
-  struct lto_input_block str_tab;
-  unsigned int len;
-  const char *result;
-
-  if (!loc)
-    {
-      *rlen = 0;
-      return NULL;
-    }
-
-  /* Get the string stored at location LOC in DATA_IN->STRINGS.  */
-  LTO_INIT_INPUT_BLOCK (str_tab, data_in->strings, loc - 1, data_in->strings_len);
-  len = lto_input_uleb128 (&str_tab);
-  *rlen = len;
-
-  if (str_tab.p + len > data_in->strings_len)
-    internal_error ("bytecode stream: string too long for the string table");
-
-  result = (const char *)(data_in->strings + str_tab.p);
-
-  return result;
-}
-
-
-/* Read a string from the string table in DATA_IN using input block
-   IB.  Write the length to RLEN.  */
-
-static const char *
-input_string_internal (struct data_in *data_in, struct lto_input_block *ib,
-		       unsigned int *rlen)
-{
-  return string_for_index (data_in, lto_input_uleb128 (ib), rlen);
-}
-
-
-/* Read a STRING_CST from the string table in DATA_IN using input
-   block IB.  */
-
-static tree
-input_string_cst (struct data_in *data_in, struct lto_input_block *ib)
-{
-  unsigned int len;
-  const char * ptr;
-
-  ptr = input_string_internal (data_in, ib, &len);
-  if (!ptr)
-    return NULL;
-  return build_string (len, ptr);
-}
-
-
-/* Read an IDENTIFIER from the string table in DATA_IN using input
-   block IB.  */
-
-static tree
-input_identifier (struct data_in *data_in, struct lto_input_block *ib)
-{
-  unsigned int len;
-  const char *ptr;
-
-  ptr = input_string_internal (data_in, ib, &len);
-  if (!ptr)
-    return NULL;
-  return get_identifier_with_length (ptr, len);
-}
-
-
 /* Read LENGTH bytes from STREAM to ADDR.  */
 
 void
@@ -216,33 +90,6 @@ lto_input_data_block (struct lto_input_block *ib, void *addr, size_t length)
 }
 
 
-/* Read a NULL terminated string from the string table in DATA_IN.  */
-
-const char *
-lto_input_string (struct data_in *data_in, struct lto_input_block *ib)
-{
-  unsigned int len;
-  const char *ptr;
-
-  ptr = input_string_internal (data_in, ib, &len);
-  if (!ptr)
-    return NULL;
-  if (ptr[len - 1] != '\0')
-    internal_error ("bytecode stream: found non-null terminated string");
-
-  return ptr;
-}
-
-
-/* Return the next tag in the input block IB.  */
-
-static inline enum LTO_tags
-input_record_start (struct lto_input_block *ib)
-{
-  return lto_input_enum (ib, LTO_tags, LTO_NUM_TAGS);
-}
-
-
 /* Lookup STRING in file_name_hash_table.  If found, return the existing
    string, otherwise insert STRING as the canonical version.  */
 
@@ -252,6 +99,7 @@ canon_file_name (const char *string)
   void **slot;
   struct string_slot s_slot;
   s_slot.s = string;
+  s_slot.len = strlen (string);
 
   slot = htab_find_slot (file_name_hash_table, &s_slot, INSERT);
   if (*slot == NULL)
@@ -333,7 +181,7 @@ lto_input_location_bitpack (struct data_in *data_in, struct bitpack_d *bp)
 
 /* Read a location from input block IB.  */
 
-static location_t
+location_t
 lto_input_location (struct lto_input_block *ib, struct data_in *data_in)
 {
   struct bitpack_d bp;
@@ -350,7 +198,7 @@ lto_input_location (struct lto_input_block *ib, struct data_in *data_in)
    representation of the tree using lto_input_tree.  FN is the
    function scope for the read tree.  */
 
-static tree
+tree
 lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
 		    struct function *fn, enum LTO_tags tag)
 {
@@ -411,33 +259,6 @@ lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
 }
 
 
-/* Read a chain of tree nodes from input block IB. DATA_IN contains
-   tables and descriptors for the file being read.  */
-
-static tree
-lto_input_chain (struct lto_input_block *ib, struct data_in *data_in)
-{
-  int i, count;
-  tree first, prev, curr;
-
-  first = prev = NULL_TREE;
-  count = lto_input_sleb128 (ib);
-  for (i = 0; i < count; i++)
-    {
-      curr = lto_input_tree (ib, data_in);
-      if (prev)
-	TREE_CHAIN (prev) = curr;
-      else
-	first = curr;
-
-      TREE_CHAIN (curr) = NULL_TREE;
-      prev = curr;
-    }
-
-  return first;
-}
-
-
 /* Read and return a double-linked list of catch handlers from input
    block IB, using descriptors in DATA_IN.  */
 
@@ -641,7 +462,7 @@ fixup_eh_region_pointers (struct function *fn, HOST_WIDE_INT root_region)
 
 /* Initialize EH support.  */
 
-static void
+void
 lto_init_eh (void)
 {
   static bool eh_initialized_p = false;
@@ -856,51 +677,6 @@ input_cfg (struct lto_input_block *ib, struct function *fn,
 }
 
 
-/* Read a PHI function for basic block BB in function FN.  DATA_IN is
-   the file being read.  IB is the input block to use for reading.  */
-
-static gimple
-input_phi (struct lto_input_block *ib, basic_block bb, struct data_in *data_in,
-	   struct function *fn)
-{
-  unsigned HOST_WIDE_INT ix;
-  tree phi_result;
-  int i, len;
-  gimple result;
-
-  ix = lto_input_uleb128 (ib);
-  phi_result = VEC_index (tree, SSANAMES (fn), ix);
-  len = EDGE_COUNT (bb->preds);
-  result = create_phi_node (phi_result, bb);
-  SSA_NAME_DEF_STMT (phi_result) = result;
-
-  /* We have to go through a lookup process here because the preds in the
-     reconstructed graph are generally in a different order than they
-     were in the original program.  */
-  for (i = 0; i < len; i++)
-    {
-      tree def = lto_input_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);
-
-      edge e = NULL;
-      int j;
-
-      for (j = 0; j < len; j++)
-	if (EDGE_PRED (bb, j)->src == sbb)
-	  {
-	    e = EDGE_PRED (bb, j);
-	    break;
-	  }
-
-      add_phi_arg (result, def, e, arg_loc);
-    }
-
-  return result;
-}
-
-
 /* Read the SSA names array for function FN from DATA_IN using input
    block IB.  */
 
@@ -934,263 +710,6 @@ input_ssa_names (struct lto_input_block *ib, struct data_in *data_in,
     }
 }
 
-/* Read a statement with tag TAG in function FN from block IB using
-   descriptors in DATA_IN.  */
-
-static gimple
-input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
-		   struct function *fn, enum LTO_tags tag)
-{
-  gimple stmt;
-  enum gimple_code code;
-  unsigned HOST_WIDE_INT num_ops;
-  size_t i;
-  struct bitpack_d bp;
-
-  code = lto_tag_to_gimple_code (tag);
-
-  /* Read the tuple header.  */
-  bp = lto_input_bitpack (ib);
-  num_ops = bp_unpack_var_len_unsigned (&bp);
-  stmt = gimple_alloc (code, num_ops);
-  stmt->gsbase.no_warning = bp_unpack_value (&bp, 1);
-  if (is_gimple_assign (stmt))
-    stmt->gsbase.nontemporal_move = bp_unpack_value (&bp, 1);
-  stmt->gsbase.has_volatile_ops = bp_unpack_value (&bp, 1);
-  stmt->gsbase.subcode = bp_unpack_var_len_unsigned (&bp);
-
-  /* Read location information.  */
-  gimple_set_location (stmt, lto_input_location (ib, data_in));
-
-  /* Read lexical block reference.  */
-  gimple_set_block (stmt, lto_input_tree (ib, data_in));
-
-  /* Read in all the operands.  */
-  switch (code)
-    {
-    case GIMPLE_RESX:
-      gimple_resx_set_region (stmt, lto_input_sleb128 (ib));
-      break;
-
-    case GIMPLE_EH_MUST_NOT_THROW:
-      gimple_eh_must_not_throw_set_fndecl (stmt, lto_input_tree (ib, data_in));
-      break;
-
-    case GIMPLE_EH_DISPATCH:
-      gimple_eh_dispatch_set_region (stmt, lto_input_sleb128 (ib));
-      break;
-
-    case GIMPLE_ASM:
-      {
-	/* FIXME lto.  Move most of this into a new gimple_asm_set_string().  */
-	tree str;
-	stmt->gimple_asm.ni = lto_input_uleb128 (ib);
-	stmt->gimple_asm.no = lto_input_uleb128 (ib);
-	stmt->gimple_asm.nc = lto_input_uleb128 (ib);
-	stmt->gimple_asm.nl = lto_input_uleb128 (ib);
-	str = input_string_cst (data_in, ib);
-	stmt->gimple_asm.string = TREE_STRING_POINTER (str);
-      }
-      /* Fallthru  */
-
-    case GIMPLE_ASSIGN:
-    case GIMPLE_CALL:
-    case GIMPLE_RETURN:
-    case GIMPLE_SWITCH:
-    case GIMPLE_LABEL:
-    case GIMPLE_COND:
-    case GIMPLE_GOTO:
-    case GIMPLE_DEBUG:
-      for (i = 0; i < num_ops; i++)
-	{
-	  tree op = lto_input_tree (ib, data_in);
-	  gimple_set_op (stmt, i, op);
-	  if (!op)
-	    continue;
-
-	  /* Fixup FIELD_DECLs in COMPONENT_REFs, they are not handled
-	     by decl merging.  */
-	  if (TREE_CODE (op) == ADDR_EXPR)
-	    op = TREE_OPERAND (op, 0);
-	  while (handled_component_p (op))
-	    {
-	      if (TREE_CODE (op) == COMPONENT_REF)
-		{
-		  tree field, type, tem;
-		  tree closest_match = NULL_TREE;
-		  field = TREE_OPERAND (op, 1);
-		  type = DECL_CONTEXT (field);
-		  for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
-		    {
-		      if (tem == field)
-			break;
-		      if (DECL_NONADDRESSABLE_P (tem)
-			  == DECL_NONADDRESSABLE_P (field)
-			  && gimple_compare_field_offset (tem, field))
-			{
-			  if (types_compatible_p (TREE_TYPE (tem),
-						  TREE_TYPE (field)))
-			    break;
-			  else
-			    closest_match = tem;
-			}
-		    }
-		  /* In case of type mismatches across units we can fail
-		     to unify some types and thus not find a proper
-		     field-decl here.  */
-		  if (tem == NULL_TREE)
-		    {
-		      /* Thus, emit a ODR violation warning.  */
-		      if (warning_at (gimple_location (stmt), 0,
-				      "use of type %<%E%> with two mismatching "
-				      "declarations at field %<%E%>",
-				      type, TREE_OPERAND (op, 1)))
-			{
-			  if (TYPE_FIELDS (type))
-			    inform (DECL_SOURCE_LOCATION (TYPE_FIELDS (type)),
-				    "original type declared here");
-			  inform (DECL_SOURCE_LOCATION (TREE_OPERAND (op, 1)),
-				  "field in mismatching type declared here");
-			  if (TYPE_NAME (TREE_TYPE (field))
-			      && (TREE_CODE (TYPE_NAME (TREE_TYPE (field)))
-				  == TYPE_DECL))
-			    inform (DECL_SOURCE_LOCATION
-				      (TYPE_NAME (TREE_TYPE (field))),
-				    "type of field declared here");
-			  if (closest_match
-			      && TYPE_NAME (TREE_TYPE (closest_match))
-			      && (TREE_CODE (TYPE_NAME
-				   (TREE_TYPE (closest_match))) == TYPE_DECL))
-			    inform (DECL_SOURCE_LOCATION
-				      (TYPE_NAME (TREE_TYPE (closest_match))),
-				    "type of mismatching field declared here");
-			}
-		      /* And finally fixup the types.  */
-		      TREE_OPERAND (op, 0)
-			= build1 (VIEW_CONVERT_EXPR, type,
-				  TREE_OPERAND (op, 0));
-		    }
-		  else
-		    TREE_OPERAND (op, 1) = tem;
-		}
-
-	      op = TREE_OPERAND (op, 0);
-	    }
-	}
-      if (is_gimple_call (stmt))
-	{
-	  if (gimple_call_internal_p (stmt))
-	    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));
-	}
-      break;
-
-    case GIMPLE_NOP:
-    case GIMPLE_PREDICT:
-      break;
-
-    default:
-      internal_error ("bytecode stream: unknown GIMPLE statement tag %s",
-		      lto_tag_name (tag));
-    }
-
-  /* Update the properties of symbols, SSA names and labels associated
-     with STMT.  */
-  if (code == GIMPLE_ASSIGN || code == GIMPLE_CALL)
-    {
-      tree lhs = gimple_get_lhs (stmt);
-      if (lhs && TREE_CODE (lhs) == SSA_NAME)
-	SSA_NAME_DEF_STMT (lhs) = stmt;
-    }
-  else if (code == GIMPLE_LABEL)
-    gcc_assert (emit_label_in_global_context_p (gimple_label_label (stmt))
-	        || DECL_CONTEXT (gimple_label_label (stmt)) == fn->decl);
-  else if (code == GIMPLE_ASM)
-    {
-      unsigned i;
-
-      for (i = 0; i < gimple_asm_noutputs (stmt); i++)
-	{
-	  tree op = TREE_VALUE (gimple_asm_output_op (stmt, i));
-	  if (TREE_CODE (op) == SSA_NAME)
-	    SSA_NAME_DEF_STMT (op) = stmt;
-	}
-    }
-
-  /* Reset alias information.  */
-  if (code == GIMPLE_CALL)
-    gimple_call_reset_alias_info (stmt);
-
-  /* Mark the statement modified so its operand vectors can be filled in.  */
-  gimple_set_modified (stmt, true);
-
-  return stmt;
-}
-
-
-/* Read a basic block with tag TAG from DATA_IN using input block IB.
-   FN is the function being processed.  */
-
-static void
-input_bb (struct lto_input_block *ib, enum LTO_tags tag,
-	  struct data_in *data_in, struct function *fn,
-	  int count_materialization_scale)
-{
-  unsigned int index;
-  basic_block bb;
-  gimple_stmt_iterator bsi;
-
-  /* This routine assumes that CFUN is set to FN, as it needs to call
-     basic GIMPLE routines that use CFUN.  */
-  gcc_assert (cfun == fn);
-
-  index = lto_input_uleb128 (ib);
-  bb = BASIC_BLOCK_FOR_FUNCTION (fn, index);
-
-  bb->count = (lto_input_sleb128 (ib) * count_materialization_scale
-	       + REG_BR_PROB_BASE / 2) / REG_BR_PROB_BASE;
-  bb->loop_depth = lto_input_sleb128 (ib);
-  bb->frequency = lto_input_sleb128 (ib);
-  bb->flags = lto_input_sleb128 (ib);
-
-  /* LTO_bb1 has statements.  LTO_bb0 does not.  */
-  if (tag == LTO_bb0)
-    return;
-
-  bsi = gsi_start_bb (bb);
-  tag = input_record_start (ib);
-  while (tag)
-    {
-      gimple stmt = input_gimple_stmt (ib, data_in, fn, tag);
-      if (!is_gimple_debug (stmt))
-	find_referenced_vars_in (stmt);
-      gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
-
-      /* After the statement, expect a 0 delimiter or the EH region
-	 that the previous statement belongs to.  */
-      tag = input_record_start (ib);
-      lto_tag_check_set (tag, 2, LTO_eh_region, LTO_null);
-
-      if (tag == LTO_eh_region)
-	{
-	  HOST_WIDE_INT region = lto_input_sleb128 (ib);
-	  gcc_assert (region == (int) region);
-	  add_stmt_to_eh_lp (stmt, region);
-	}
-
-      tag = input_record_start (ib);
-    }
-
-  tag = input_record_start (ib);
-  while (tag)
-    {
-      gimple phi = input_phi (ib, bb, data_in, fn);
-      find_referenced_vars_in (phi);
-      tag = input_record_start (ib);
-    }
-}
 
 /* Go through all NODE edges and fixup call_stmt pointers
    so they point to STMTS.  */
@@ -1525,994 +1044,13 @@ lto_input_constructors_and_inits (struct lto_file_decl_data *file_data,
 }
 
 
-/* Unpack all the non-pointer fields of the TS_BASE structure of
-   expression EXPR from bitpack BP.  */
-
-static void
-unpack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
-{
-  /* Note that the code for EXPR has already been unpacked to create EXPR in
-     lto_materialize_tree.  */
-  if (!TYPE_P (expr))
-    {
-      TREE_SIDE_EFFECTS (expr) = (unsigned) bp_unpack_value (bp, 1);
-      TREE_CONSTANT (expr) = (unsigned) bp_unpack_value (bp, 1);
-      TREE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1);
-
-      /* TREE_PUBLIC is used on types to indicate that the type
-	 has a TYPE_CACHED_VALUES vector.  This is not streamed out,
-	 so we skip it here.  */
-      TREE_PUBLIC (expr) = (unsigned) bp_unpack_value (bp, 1);
-    }
-  else
-    bp_unpack_value (bp, 4);
-  TREE_ADDRESSABLE (expr) = (unsigned) bp_unpack_value (bp, 1);
-  TREE_THIS_VOLATILE (expr) = (unsigned) bp_unpack_value (bp, 1);
-  if (DECL_P (expr))
-    DECL_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1);
-  else if (TYPE_P (expr))
-    TYPE_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1);
-  else
-    bp_unpack_value (bp, 1);
-  TREE_ASM_WRITTEN (expr) = (unsigned) bp_unpack_value (bp, 1);
-  if (TYPE_P (expr))
-    TYPE_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1);
-  else
-    TREE_NO_WARNING (expr) = (unsigned) bp_unpack_value (bp, 1);
-  TREE_USED (expr) = (unsigned) bp_unpack_value (bp, 1);
-  TREE_NOTHROW (expr) = (unsigned) bp_unpack_value (bp, 1);
-  TREE_STATIC (expr) = (unsigned) bp_unpack_value (bp, 1);
-  TREE_PRIVATE (expr) = (unsigned) bp_unpack_value (bp, 1);
-  TREE_PROTECTED (expr) = (unsigned) bp_unpack_value (bp, 1);
-  TREE_DEPRECATED (expr) = (unsigned) bp_unpack_value (bp, 1);
-  if (TYPE_P (expr))
-    TYPE_SATURATING (expr) = (unsigned) bp_unpack_value (bp, 1);
-  else if (TREE_CODE (expr) == SSA_NAME)
-    SSA_NAME_IS_DEFAULT_DEF (expr) = (unsigned) bp_unpack_value (bp, 1);
-  else
-    bp_unpack_value (bp, 1);
-}
-
-
-/* Unpack all the non-pointer fields of the TS_REAL_CST structure of
-   expression EXPR from bitpack BP.  */
-
-static void
-unpack_ts_real_cst_value_fields (struct bitpack_d *bp, tree expr)
-{
-  unsigned i;
-  REAL_VALUE_TYPE r;
-  REAL_VALUE_TYPE *rp;
-
-  r.cl = (unsigned) bp_unpack_value (bp, 2);
-  r.decimal = (unsigned) bp_unpack_value (bp, 1);
-  r.sign = (unsigned) bp_unpack_value (bp, 1);
-  r.signalling = (unsigned) bp_unpack_value (bp, 1);
-  r.canonical = (unsigned) bp_unpack_value (bp, 1);
-  r.uexp = (unsigned) bp_unpack_value (bp, EXP_BITS);
-  for (i = 0; i < SIGSZ; i++)
-    r.sig[i] = (unsigned long) bp_unpack_value (bp, HOST_BITS_PER_LONG);
-
-  rp = ggc_alloc_real_value ();
-  memcpy (rp, &r, sizeof (REAL_VALUE_TYPE));
-  TREE_REAL_CST_PTR (expr) = rp;
-}
-
-
-/* Unpack all the non-pointer fields of the TS_FIXED_CST structure of
-   expression EXPR from bitpack BP.  */
-
-static void
-unpack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
-{
-  struct fixed_value fv;
-
-  fv.mode = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
-  fv.data.low = bp_unpack_var_len_int (bp);
-  fv.data.high = bp_unpack_var_len_int (bp);
-  TREE_FIXED_CST (expr) = fv;
-}
-
-
-/* Unpack all the non-pointer fields of the TS_DECL_COMMON structure
-   of expression EXPR from bitpack BP.  */
-
-static void
-unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
-{
-  DECL_MODE (expr) = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
-  DECL_NONLOCAL (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_VIRTUAL_P (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_IGNORED_P (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_ABSTRACT (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_USER_ALIGN (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_PRESERVE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_DEBUG_EXPR_IS_FROM (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_EXTERNAL (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_GIMPLE_REG_P (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_ALIGN (expr) = (unsigned) bp_unpack_var_len_unsigned (bp);
-
-  if (TREE_CODE (expr) == LABEL_DECL)
-    {
-      DECL_ERROR_ISSUED (expr) = (unsigned) bp_unpack_value (bp, 1);
-      EH_LANDING_PAD_NR (expr) = (int) bp_unpack_var_len_unsigned (bp);
-
-      /* Always assume an initial value of -1 for LABEL_DECL_UID to
-	 force gimple_set_bb to recreate label_to_block_map.  */
-      LABEL_DECL_UID (expr) = -1;
-    }
-
-  if (TREE_CODE (expr) == FIELD_DECL)
-    {
-      DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
-      DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
-      expr->decl_common.off_align = bp_unpack_value (bp, 8);
-    }
-
-  if (TREE_CODE (expr) == RESULT_DECL
-      || TREE_CODE (expr) == PARM_DECL
-      || TREE_CODE (expr) == VAR_DECL)
-    {
-      DECL_BY_REFERENCE (expr) = (unsigned) bp_unpack_value (bp, 1);
-      if (TREE_CODE (expr) == VAR_DECL
-	  || TREE_CODE (expr) == PARM_DECL)
-	DECL_HAS_VALUE_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1);
-      DECL_RESTRICTED_P (expr) = (unsigned) bp_unpack_value (bp, 1);
-    }
-}
-
-
-/* Unpack all the non-pointer fields of the TS_DECL_WRTL structure
-   of expression EXPR from bitpack BP.  */
-
-static void
-unpack_ts_decl_wrtl_value_fields (struct bitpack_d *bp, tree expr)
-{
-  DECL_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1);
-}
-
-
-/* Unpack all the non-pointer fields of the TS_DECL_WITH_VIS structure
-   of expression EXPR from bitpack BP.  */
-
-static void
-unpack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
-{
-  DECL_DEFER_OUTPUT (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_COMMON (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_DLLIMPORT_P (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_WEAK (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_SEEN_IN_BIND_EXPR_P (expr) = (unsigned) bp_unpack_value (bp,  1);
-  DECL_COMDAT (expr) = (unsigned) bp_unpack_value (bp,  1);
-  DECL_VISIBILITY (expr) = (enum symbol_visibility) bp_unpack_value (bp,  2);
-  DECL_VISIBILITY_SPECIFIED (expr) = (unsigned) bp_unpack_value (bp,  1);
-
-  if (TREE_CODE (expr) == VAR_DECL)
-    {
-      DECL_HARD_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1);
-      DECL_IN_TEXT_SECTION (expr) = (unsigned) bp_unpack_value (bp, 1);
-      DECL_IN_CONSTANT_POOL (expr) = (unsigned) bp_unpack_value (bp, 1);
-      DECL_TLS_MODEL (expr) = (enum tls_model) bp_unpack_value (bp,  3);
-    }
-
-  if (VAR_OR_FUNCTION_DECL_P (expr))
-    {
-      priority_type p;
-      p = (priority_type) bp_unpack_var_len_unsigned (bp);
-      SET_DECL_INIT_PRIORITY (expr, p);
-    }
-}
-
-
-/* Unpack all the non-pointer fields of the TS_FUNCTION_DECL structure
-   of expression EXPR from bitpack BP.  */
-
-static void
-unpack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
-{
-  DECL_BUILT_IN_CLASS (expr) = bp_unpack_enum (bp, built_in_class,
-					       BUILT_IN_LAST);
-  DECL_STATIC_CONSTRUCTOR (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_STATIC_DESTRUCTOR (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_UNINLINABLE (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_POSSIBLY_INLINED (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_IS_NOVOPS (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_IS_RETURNS_TWICE (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_IS_MALLOC (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_IS_OPERATOR_NEW (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_DECLARED_INLINE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_STATIC_CHAIN (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_NO_INLINE_WARNING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr)
-    			= (unsigned) bp_unpack_value (bp, 1);
-  DECL_NO_LIMIT_STACK (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_DISREGARD_INLINE_LIMITS (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_LOOPING_CONST_OR_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
-  if (DECL_BUILT_IN_CLASS (expr) != NOT_BUILT_IN)
-    {
-      DECL_FUNCTION_CODE (expr) = (enum built_in_function) bp_unpack_value (bp, 11);
-      if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_NORMAL
-	  && DECL_FUNCTION_CODE (expr) >= END_BUILTINS)
-	fatal_error ("machine independent builtin code out of range");
-      else if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD)
-	{
-          tree result = targetm.builtin_decl (DECL_FUNCTION_CODE (expr), true);
-	  if (!result || result == error_mark_node)
-	    fatal_error ("target specific builtin not available");
-	}
-    }
-  if (DECL_STATIC_DESTRUCTOR (expr))
-    {
-      priority_type p;
-      p = (priority_type) bp_unpack_var_len_unsigned (bp);
-      SET_DECL_FINI_PRIORITY (expr, p);
-    }
-}
-
-
-/* Unpack all the non-pointer fields of the TS_TYPE_COMMON structure
-   of expression EXPR from bitpack BP.  */
+/* 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.  */
 
-static void
-unpack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
-{
-  enum machine_mode mode;
-
-  mode = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
-  SET_TYPE_MODE (expr, mode);
-  TYPE_STRING_FLAG (expr) = (unsigned) bp_unpack_value (bp, 1);
-  TYPE_NO_FORCE_BLK (expr) = (unsigned) bp_unpack_value (bp, 1);
-  TYPE_NEEDS_CONSTRUCTING (expr) = (unsigned) bp_unpack_value (bp, 1);
-  if (RECORD_OR_UNION_TYPE_P (expr))
-    TYPE_TRANSPARENT_AGGR (expr) = (unsigned) bp_unpack_value (bp, 1);
-  TYPE_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
-  TYPE_RESTRICT (expr) = (unsigned) bp_unpack_value (bp, 1);
-  TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr)
-    	= (unsigned) bp_unpack_value (bp, 2);
-  TYPE_USER_ALIGN (expr) = (unsigned) bp_unpack_value (bp, 1);
-  TYPE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1);
-  TYPE_PRECISION (expr) = bp_unpack_var_len_unsigned (bp);
-  TYPE_ALIGN (expr) = bp_unpack_var_len_unsigned (bp);
-  TYPE_ALIAS_SET (expr) = bp_unpack_var_len_int (bp);
-}
-
-
-/* Unpack all the non-pointer fields of the TS_BLOCK structure
-   of expression EXPR from bitpack BP.  */
-
-static void
-unpack_ts_block_value_fields (struct bitpack_d *bp, tree expr)
-{
-  BLOCK_ABSTRACT (expr) = (unsigned) bp_unpack_value (bp, 1);
-  /* BLOCK_NUMBER is recomputed.  */
-}
-
-/* Unpack all the non-pointer fields of the TS_TRANSLATION_UNIT_DECL
-   structure of expression EXPR from bitpack BP.  */
-
-static void
-unpack_ts_translation_unit_decl_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED, tree expr ATTRIBUTE_UNUSED)
-{
-}
-
-/* Unpack all the non-pointer fields in EXPR into a bit pack.  */
-
-static void
-unpack_value_fields (struct bitpack_d *bp, tree expr)
-{
-  enum tree_code code;
-
-  code = TREE_CODE (expr);
-
-  /* Note that all these functions are highly sensitive to changes in
-     the types and sizes of each of the fields being packed.  */
-  unpack_ts_base_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
-    unpack_ts_real_cst_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_FIXED_CST))
-    unpack_ts_fixed_cst_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
-    unpack_ts_decl_common_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL))
-    unpack_ts_decl_wrtl_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
-    unpack_ts_decl_with_vis_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
-    unpack_ts_function_decl_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
-    unpack_ts_type_common_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
-    unpack_ts_block_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
-    unpack_ts_translation_unit_decl_value_fields (bp, expr);
-
-  if (streamer_hooks.unpack_value_fields)
-    streamer_hooks.unpack_value_fields (bp, expr);
-}
-
-
-/* Materialize a new tree from input block IB using descriptors in
-   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
-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
-  HOST_WIDEST_INT orig_address_in_writer;
-#endif
-
-  result = NULL_TREE;
-
-#ifdef LTO_STREAMER_DEBUG
-  /* Read the word representing the memory address for the tree
-     as it was written by the writer.  This is useful when
-     debugging differences between the writer and reader.  */
-  orig_address_in_writer = lto_input_sleb128 (ib);
-  gcc_assert ((intptr_t) orig_address_in_writer == orig_address_in_writer);
-#endif
-
-  code = lto_tag_to_tree_code (tag);
-
-  /* We should never see an SSA_NAME tree.  Only the version numbers of
-     SSA names are ever written out.  See input_ssa_names.  */
-  gcc_assert (code != SSA_NAME);
-
-  /* Instantiate a new tree using the header data.  */
-  if (CODE_CONTAINS_STRUCT (code, TS_STRING))
-    result = input_string_cst (data_in, ib);
-  else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER))
-    result = input_identifier (data_in, ib);
-  else if (CODE_CONTAINS_STRUCT (code, TS_VEC))
-    {
-      HOST_WIDE_INT len = lto_input_sleb128 (ib);
-      result = make_tree_vec (len);
-    }
-  else if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
-    {
-      unsigned HOST_WIDE_INT len = lto_input_uleb128 (ib);
-      result = make_tree_binfo (len);
-    }
-  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
-	 make_node call.  */
-      if (result == NULL_TREE)
-	result = make_node (code);
-    }
-
-#ifdef LTO_STREAMER_DEBUG
-  /* Store the original address of the tree as seen by the writer
-     in RESULT's aux field.  This is useful when debugging streaming
-     problems.  This way, a debugging session can be started on
-     both writer and reader with a breakpoint using this address
-     value in both.  */
-  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;
-}
-
-
-/* Read all pointer fields in the TS_COMMON structure of EXPR from input
-   block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-
-static void
-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);
-}
-
-
-/* Read all pointer fields in the TS_VECTOR structure of EXPR from input
-   block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-static void
-lto_input_ts_vector_tree_pointers (struct lto_input_block *ib,
-				   struct data_in *data_in, tree expr)
-{
-  TREE_VECTOR_CST_ELTS (expr) = lto_input_chain (ib, data_in);
-}
-
-
-/* Read all pointer fields in the TS_COMPLEX structure of EXPR from input
-   block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-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);
-}
-
-
-/* Read all pointer fields in the TS_DECL_MINIMAL structure of EXPR
-   from input block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-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_SOURCE_LOCATION (expr) = lto_input_location (ib, data_in);
-}
-
-
-/* Read all pointer fields in the TS_DECL_COMMON structure of EXPR from
-   input block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-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);
-
-  /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
-     for early inlining so drop it on the floor instead of ICEing in
-     dwarf2out.c.  */
-
-  if (TREE_CODE (expr) == PARM_DECL)
-    TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
-
-  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));
-
-  if (TREE_CODE (expr) == VAR_DECL)
-    {
-      tree dexpr = lto_input_tree (ib, data_in);
-      if (dexpr)
-	SET_DECL_DEBUG_EXPR (expr, dexpr);
-    }
-}
-
-
-/* Read all pointer fields in the TS_DECL_NON_COMMON structure of
-   EXPR from input block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-static void
-lto_input_ts_decl_non_common_tree_pointers (struct lto_input_block *ib,
-					    struct data_in *data_in, tree expr)
-{
-  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_VINDEX (expr) = lto_input_tree (ib, data_in);
-}
-
-
-/* Read all pointer fields in the TS_DECL_WITH_VIS structure of EXPR
-   from input block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-static void
-lto_input_ts_decl_with_vis_tree_pointers (struct lto_input_block *ib,
-				          struct data_in *data_in, tree expr)
-{
-  tree id;
-
-  id = lto_input_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);
-}
-
-
-/* Read all pointer fields in the TS_FIELD_DECL structure of EXPR from
-   input block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-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);
-  TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
-}
-
-
-/* Read all pointer fields in the TS_FUNCTION_DECL structure of EXPR
-   from input block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-static void
-lto_input_ts_function_decl_tree_pointers (struct lto_input_block *ib,
-					  struct data_in *data_in, tree expr)
-{
-  /* 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);
-
-  /* If the file contains a function with an EH personality set,
-     then it was compiled with -fexceptions.  In that case, initialize
-     the backend EH machinery.  */
-  if (DECL_FUNCTION_PERSONALITY (expr))
-    lto_init_eh ();
-}
-
-
-/* Read all pointer fields in the TS_TYPE_COMMON structure of EXPR from
-   input block IB.  DATA_IN contains tables and descriptors for the file
-   being read.  */
-
-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);
-  /* 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_CANONICAL gets re-computed during type merging.  */
-  TYPE_CANONICAL (expr) = NULL_TREE;
-  TYPE_STUB_DECL (expr) = lto_input_tree (ib, data_in);
-}
-
-/* Read all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
-   from input block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-static void
-lto_input_ts_type_non_common_tree_pointers (struct lto_input_block *ib,
-					    struct data_in *data_in,
-					    tree expr)
-{
-  if (TREE_CODE (expr) == ENUMERAL_TYPE)
-    TYPE_VALUES (expr) = lto_input_tree (ib, data_in);
-  else if (TREE_CODE (expr) == ARRAY_TYPE)
-    TYPE_DOMAIN (expr) = lto_input_tree (ib, data_in);
-  else if (RECORD_OR_UNION_TYPE_P (expr))
-    TYPE_FIELDS (expr) = lto_input_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);
-
-  if (!POINTER_TYPE_P (expr))
-    TYPE_MINVAL (expr) = lto_input_tree (ib, data_in);
-  TYPE_MAXVAL (expr) = lto_input_tree (ib, data_in);
-  if (RECORD_OR_UNION_TYPE_P (expr))
-    TYPE_BINFO (expr) = lto_input_tree (ib, data_in);
-}
-
-
-/* Read all pointer fields in the TS_LIST structure of EXPR from input
-   block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-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_CHAIN (expr) = lto_input_chain (ib, data_in);
-}
-
-
-/* Read all pointer fields in the TS_VEC structure of EXPR from input
-   block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-static void
-lto_input_ts_vec_tree_pointers (struct lto_input_block *ib,
-				struct data_in *data_in, tree expr)
-{
-  int i;
-
-  /* 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);
-}
-
-
-/* Read all pointer fields in the TS_EXP structure of EXPR from input
-   block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-
-static void
-lto_input_ts_exp_tree_pointers (struct lto_input_block *ib,
-			        struct data_in *data_in, tree expr)
-{
-  int i, length;
-  location_t loc;
-
-  length = lto_input_sleb128 (ib);
-  gcc_assert (length == TREE_OPERAND_LENGTH (expr));
-
-  for (i = 0; i < length; i++)
-    TREE_OPERAND (expr, i) = lto_input_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);
-}
-
-
-/* Read all pointer fields in the TS_BLOCK structure of EXPR from input
-   block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-static void
-lto_input_ts_block_tree_pointers (struct lto_input_block *ib,
-				  struct data_in *data_in, tree expr)
-{
-  /* Do not stream BLOCK_SOURCE_LOCATION.  We cannot handle debug information
-     for early inlining so drop it on the floor instead of ICEing in
-     dwarf2out.c.  */
-  BLOCK_VARS (expr) = lto_input_chain (ib, data_in);
-
-  /* Do not stream BLOCK_NONLOCALIZED_VARS.  We cannot handle debug information
-     for early inlining so drop it on the floor instead of ICEing in
-     dwarf2out.c.  */
-
-  BLOCK_SUPERCONTEXT (expr) = lto_input_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);
-  /* We re-compute BLOCK_SUBBLOCKS of our parent here instead
-     of streaming it.  For non-BLOCK BLOCK_SUPERCONTEXTs we still
-     stream the child relationship explicitly.  */
-  if (BLOCK_SUPERCONTEXT (expr)
-      && TREE_CODE (BLOCK_SUPERCONTEXT (expr)) == BLOCK)
-    {
-      BLOCK_CHAIN (expr) = BLOCK_SUBBLOCKS (BLOCK_SUPERCONTEXT (expr));
-      BLOCK_SUBBLOCKS (BLOCK_SUPERCONTEXT (expr)) = expr;
-    }
-  /* The global block is rooted at the TU decl.  Hook it here to
-     avoid the need to stream in this block during WPA time.  */
-  else if (BLOCK_SUPERCONTEXT (expr)
-	   && TREE_CODE (BLOCK_SUPERCONTEXT (expr)) == TRANSLATION_UNIT_DECL)
-    DECL_INITIAL (BLOCK_SUPERCONTEXT (expr)) = expr;
-  /* The function-level block is connected at the time we read in
-     function bodies for the same reason.  */
-}
-
-
-/* Read all pointer fields in the TS_BINFO structure of EXPR from input
-   block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-static void
-lto_input_ts_binfo_tree_pointers (struct lto_input_block *ib,
-				  struct data_in *data_in, tree expr)
-{
-  unsigned i, len;
-  tree t;
-
-  /* Note that the number of slots in EXPR was read in
-     lto_materialize_tree when instantiating EXPR.  However, the
-     vector is empty so we cannot rely on VEC_length to know how many
-     elements to read.  So, this list is emitted as a 0-terminated
-     list on the writer side.  */
-  do
-    {
-      t = lto_input_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);
-
-  len = lto_input_uleb128 (ib);
-  if (len > 0)
-    {
-      VEC_reserve_exact (tree, gc, BINFO_BASE_ACCESSES (expr), len);
-      for (i = 0; i < len; i++)
-	{
-	  tree a = lto_input_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);
-}
-
-
-/* Read all pointer fields in the TS_CONSTRUCTOR structure of EXPR from
-   input block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
-
-static void
-lto_input_ts_constructor_tree_pointers (struct lto_input_block *ib,
-				        struct data_in *data_in, tree expr)
-{
-  unsigned i, len;
-
-  len = lto_input_uleb128 (ib);
-  for (i = 0; i < len; i++)
-    {
-      tree index, value;
-
-      index = lto_input_tree (ib, data_in);
-      value = lto_input_tree (ib, data_in);
-      CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (expr), index, value);
-    }
-}
-
-
-/* Input a TS_TARGET_OPTION tree from IB into EXPR.  */
-
-static void
-lto_input_ts_target_option (struct lto_input_block *ib, tree expr)
-{
-  unsigned i, len;
-  struct bitpack_d bp;
-  struct cl_target_option *t = TREE_TARGET_OPTION (expr);
-
-  bp = lto_input_bitpack (ib);
-  len = sizeof (struct cl_target_option);
-  for (i = 0; i < len; i++)
-    ((unsigned char *)t)[i] = bp_unpack_value (&bp, 8);
-  if (bp_unpack_value (&bp, 32) != 0x12345678)
-    fatal_error ("cl_target_option size mismatch in LTO reader and writer");
-}
-
-/* Input a TS_TRANSLATION_UNIT_DECL tree from IB and DATA_IN into EXPR.  */
-
-static void
-lto_input_ts_translation_unit_decl_tree_pointers (struct lto_input_block *ib,
-						  struct data_in *data_in,
-						  tree expr)
-{
-  TRANSLATION_UNIT_LANGUAGE (expr) = xstrdup (lto_input_string (data_in, 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.  */
-
-static void
-lto_input_tree_pointers (struct lto_input_block *ib, struct data_in *data_in,
-			 tree expr)
-{
-  enum tree_code code;
-
-  code = TREE_CODE (expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
-    lto_input_ts_common_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_VECTOR))
-    lto_input_ts_vector_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX))
-    lto_input_ts_complex_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL))
-    lto_input_ts_decl_minimal_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
-    lto_input_ts_decl_common_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
-    lto_input_ts_decl_non_common_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
-    lto_input_ts_decl_with_vis_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL))
-    lto_input_ts_field_decl_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
-    lto_input_ts_function_decl_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
-    lto_input_ts_type_common_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON))
-    lto_input_ts_type_non_common_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_LIST))
-    lto_input_ts_list_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_VEC))
-    lto_input_ts_vec_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_EXP))
-    lto_input_ts_exp_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
-    lto_input_ts_block_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
-    lto_input_ts_binfo_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
-    lto_input_ts_constructor_tree_pointers (ib, data_in, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
-    lto_input_ts_target_option (ib, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
-    lto_input_ts_translation_unit_decl_tree_pointers (ib, data_in, expr);
-}
-
-
-/* Read an index IX from input block IB and return the tree node at
-   DATA_IN->FILE_DATA->GLOBALS_INDEX[IX].  */
-
-static tree
-lto_get_pickled_tree (struct lto_input_block *ib, struct data_in *data_in)
-{
-  unsigned HOST_WIDE_INT ix;
-  tree result;
-  enum LTO_tags expected_tag;
-
-  ix = lto_input_uleb128 (ib);
-  expected_tag = lto_input_enum (ib, LTO_tags, LTO_NUM_TAGS);
-
-  result = lto_streamer_cache_get (data_in->reader_cache, ix);
-  gcc_assert (result
-              && TREE_CODE (result) == lto_tag_to_tree_code (expected_tag));
-
-  return result;
-}
-
-
-/* Read a code and class from input block IB and return the
-   corresponding builtin.  DATA_IN is as in lto_input_tree.  */
-
-static tree
-lto_get_builtin_tree (struct lto_input_block *ib, struct data_in *data_in)
-{
-  enum built_in_class fclass;
-  enum built_in_function fcode;
-  const char *asmname;
-  tree result;
-
-  fclass = lto_input_enum (ib, built_in_class, BUILT_IN_LAST);
-  gcc_assert (fclass == BUILT_IN_NORMAL || fclass == BUILT_IN_MD);
-
-  fcode = (enum built_in_function) lto_input_uleb128 (ib);
-
-  if (fclass == BUILT_IN_NORMAL)
-    {
-      if (fcode >= END_BUILTINS)
-	fatal_error ("machine independent builtin code out of range");
-      result = built_in_decls[fcode];
-      gcc_assert (result);
-    }
-  else if (fclass == BUILT_IN_MD)
-    {
-      result = targetm.builtin_decl (fcode, true);
-      if (!result || result == error_mark_node)
-	fatal_error ("target specific builtin not available");
-    }
-  else
-    gcc_unreachable ();
-
-  asmname = lto_input_string (data_in, ib);
-  if (asmname)
-    set_builtin_user_assembler_name (result, asmname);
-
-  lto_streamer_cache_append (data_in->reader_cache, result);
-
-  return result;
-}
-
-
-/* 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;
-}
-
-
-/* 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.  */
-
-void
-lto_streamer_read_tree (struct lto_input_block *ib, struct data_in *data_in,
-			tree expr)
+void
+lto_streamer_read_tree (struct lto_input_block *ib, struct data_in *data_in,
+			tree expr)
 {
   if (DECL_P (expr)
       && TREE_CODE (expr) != FUNCTION_DECL
@@ -2521,84 +1059,6 @@ lto_streamer_read_tree (struct lto_input_block *ib, struct data_in *data_in,
 }
 
 
-/* Read and INTEGER_CST node from input block IB using the per-file
-   context in DATA_IN.  */
-
-static 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);
-  overflow_p = (lto_input_1_unsigned (ib) != 0);
-  low = lto_input_uleb128 (ib);
-  high = lto_input_uleb128 (ib);
-  result = build_int_cst_wide (type, low, high);
-
-  /* If the original constant had overflown, build a replica of RESULT to
-     avoid modifying the shared constant returned by build_int_cst_wide.  */
-  if (overflow_p)
-    {
-      result = copy_node (result);
-      TREE_OVERFLOW (result) = 1;
-    }
-
-  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;
-}
-
-
 /* Initialization for the LTO reader.  */
 
 void
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index 6345d83..0b84b08 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -41,45 +41,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "vec.h"
 #include "lto-symtab.h"
 #include "lto-streamer.h"
-
-
-struct string_slot
-{
-  const char *s;
-  int len;
-  unsigned int slot_num;
-};
-
-
-/* Returns a hash code for P.  
-   Shamelessly stollen from libiberty.  */
-
-static hashval_t
-hash_string_slot_node (const void *p)
-{
-  const struct string_slot *ds = (const struct string_slot *) p;
-  hashval_t r = ds->len;
-  int i;
-
-  for (i = 0; i < ds->len; i++)
-     r = r * 67 + (unsigned)ds->s[i] - 113;
-  return r;
-}
-
-
-/* Returns nonzero if P1 and P2 are equal.  */
-
-static int
-eq_string_slot_node (const void *p1, const void *p2)
-{
-  const struct string_slot *ds1 = (const struct string_slot *) p1;
-  const struct string_slot *ds2 = (const struct string_slot *) p2;
-
-  if (ds1->len == ds2->len)
-    return memcmp (ds1->s, ds2->s, ds1->len) == 0;
-
-  return 0;
-}
+#include "data-streamer.h"
+#include "gimple-streamer.h"
+#include "tree-streamer.h"
+#include "streamer-hooks.h"
 
 
 /* Clear the line info stored in DATA_IN.  */
@@ -108,1331 +73,125 @@ create_output_block (enum lto_section_type section_type)
   ob->writer_cache = lto_streamer_cache_create ();
 
   if (section_type == LTO_section_function_body)
-    ob->cfg_stream = XCNEW (struct lto_output_stream);
-
-  clear_line_info (ob);
-
-  ob->string_hash_table = htab_create (37, hash_string_slot_node,
-				       eq_string_slot_node, NULL);
-  gcc_obstack_init (&ob->obstack);
-
-  return ob;
-}
-
-
-/* Destroy the output block OB.  */
-
-void
-destroy_output_block (struct output_block *ob)
-{
-  enum lto_section_type section_type = ob->section_type;
-
-  htab_delete (ob->string_hash_table);
-
-  free (ob->main_stream);
-  free (ob->string_stream);
-  if (section_type == LTO_section_function_body)
-    free (ob->cfg_stream);
-
-  lto_streamer_cache_delete (ob->writer_cache);
-  obstack_free (&ob->obstack, NULL);
-
-  free (ob);
-}
-
-/* Return index used to reference STRING of LEN characters in the string table
-   in OB.  The string might or might not include a trailing '\0'.
-   Then put the index onto the INDEX_STREAM.  
-   When PERSISTENT is set, the string S is supposed to not change during
-   duration of the OB and thus OB can keep pointer into it.  */
-
-static unsigned
-lto_string_index (struct output_block *ob,
-		  const char *s,
-		  unsigned int len,
-		  bool persistent)
-{
-  struct string_slot **slot;
-  struct string_slot s_slot;
-
-  s_slot.s = s;
-  s_slot.len = len;
-  s_slot.slot_num = 0;
-
-  slot = (struct string_slot **) htab_find_slot (ob->string_hash_table,
-						 &s_slot, INSERT);
-  if (*slot == NULL)
-    {
-      struct lto_output_stream *string_stream = ob->string_stream;
-      unsigned int start = string_stream->total_size;
-      struct string_slot *new_slot
-	= XOBNEW (&ob->obstack, struct string_slot);
-      const char *string;
-
-      if (!persistent)
-	{
-	  char *tmp;
-	  string = tmp = XOBNEWVEC (&ob->obstack, char, len);
-          memcpy (tmp, s, len);
-        }
-      else
-	string = s;
-
-      new_slot->s = string;
-      new_slot->len = len;
-      new_slot->slot_num = start;
-      *slot = new_slot;
-      lto_output_uleb128_stream (string_stream, len);
-      lto_output_data_stream (string_stream, string, len);
-      return start + 1;
-    }
-  else
-    {
-      struct string_slot *old_slot = *slot;
-      return old_slot->slot_num + 1;
-    }
-}
-
-
-/* Output STRING of LEN characters to the string
-   table in OB. The string might or might not include a trailing '\0'.
-   Then put the index onto the INDEX_STREAM. 
-   When PERSISTENT is set, the string S is supposed to not change during
-   duration of the OB and thus OB can keep pointer into it.  */
-
-static void
-lto_output_string_with_length (struct output_block *ob,
-			       struct lto_output_stream *index_stream,
-			       const char *s,
-			       unsigned int len,
-			       bool persistent)
-{
-  if (s)
-    lto_output_uleb128_stream (index_stream,
-			       lto_string_index (ob, s, len, persistent));
-  else
-    lto_output_1_stream (index_stream, 0);
-}
-
-/* Output the '\0' terminated STRING to the string
-   table in OB.  Then put the index onto the INDEX_STREAM.
-   When PERSISTENT is set, the string S is supposed to not change during
-   duration of the OB and thus OB can keep pointer into it.  */
-
-static void
-lto_output_string (struct output_block *ob,
-	           struct lto_output_stream *index_stream,
-	           const char *string,
-		   bool persistent)
-{
-  if (string)
-    lto_output_string_with_length (ob, index_stream, string,
-				   strlen (string) + 1,
-				   persistent);
-  else
-    lto_output_1_stream (index_stream, 0);
-}
-
-
-/* Output the STRING constant to the string
-   table in OB.  Then put the index onto the INDEX_STREAM.  */
-
-static void
-output_string_cst (struct output_block *ob,
-		   struct lto_output_stream *index_stream,
-		   tree string)
-{
-  lto_output_string_with_length (ob, index_stream,
-				 TREE_STRING_POINTER (string),
-				 TREE_STRING_LENGTH (string),
-				 true);
-}
-
-
-/* Output the identifier ID to the string
-   table in OB.  Then put the index onto the INDEX_STREAM.  */
-
-static void
-output_identifier (struct output_block *ob,
-		   struct lto_output_stream *index_stream,
-		   tree id)
-{
-  lto_output_string_with_length (ob, index_stream,
-				 IDENTIFIER_POINTER (id),
-				 IDENTIFIER_LENGTH (id),
-				 true);
-}
-
-
-/* Write a zero to the output stream.  */
-
-static void
-output_zero (struct output_block *ob)
-{
-  lto_output_1_stream (ob->main_stream, 0);
-}
-
-
-/* Output an unsigned LEB128 quantity to OB->main_stream.  */
-
-static void
-output_uleb128 (struct output_block *ob, unsigned HOST_WIDE_INT work)
-{
-  lto_output_uleb128_stream (ob->main_stream, work);
-}
-
-
-/* Output a signed LEB128 quantity to OB->main_stream.  */
-
-static void
-output_sleb128 (struct output_block *ob, HOST_WIDE_INT work)
-{
-  lto_output_sleb128_stream (ob->main_stream, work);
-}
-
-
-/* Output the start of a record with TAG to output block OB.  */
-
-static inline void
-output_record_start (struct output_block *ob, enum LTO_tags tag)
-{
-  lto_output_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS, tag);
-}
-
-
-/* Look up NODE in the type table and write the index for it to OB.  */
-
-static void
-output_type_ref (struct output_block *ob, tree node)
-{
-  output_record_start (ob, LTO_type_ref);
-  lto_output_type_ref_index (ob->decl_state, ob->main_stream, node);
-}
-
-
-/* Pack all the non-pointer fields of the TS_BASE structure of
-   expression EXPR into bitpack BP.  */
-
-static void
-pack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
-{
-  bp_pack_value (bp, TREE_CODE (expr), 16);
-  if (!TYPE_P (expr))
-    {
-      bp_pack_value (bp, TREE_SIDE_EFFECTS (expr), 1);
-      bp_pack_value (bp, TREE_CONSTANT (expr), 1);
-      bp_pack_value (bp, TREE_READONLY (expr), 1);
-
-      /* TREE_PUBLIC is used on types to indicate that the type
-	 has a TYPE_CACHED_VALUES vector.  This is not streamed out,
-	 so we skip it here.  */
-      bp_pack_value (bp, TREE_PUBLIC (expr), 1);
-    }
-  else
-    bp_pack_value (bp, 0, 4);
-  bp_pack_value (bp, TREE_ADDRESSABLE (expr), 1);
-  bp_pack_value (bp, TREE_THIS_VOLATILE (expr), 1);
-  if (DECL_P (expr))
-    bp_pack_value (bp, DECL_UNSIGNED (expr), 1);
-  else if (TYPE_P (expr))
-    bp_pack_value (bp, TYPE_UNSIGNED (expr), 1);
-  else
-    bp_pack_value (bp, 0, 1);
-  /* We write debug info two times, do not confuse the second one.  */
-  bp_pack_value (bp, TYPE_P (expr) ? 0 : TREE_ASM_WRITTEN (expr), 1);
-  if (TYPE_P (expr))
-    bp_pack_value (bp, TYPE_ARTIFICIAL (expr), 1);
-  else
-    bp_pack_value (bp, TREE_NO_WARNING (expr), 1);
-  bp_pack_value (bp, TREE_USED (expr), 1);
-  bp_pack_value (bp, TREE_NOTHROW (expr), 1);
-  bp_pack_value (bp, TREE_STATIC (expr), 1);
-  bp_pack_value (bp, TREE_PRIVATE (expr), 1);
-  bp_pack_value (bp, TREE_PROTECTED (expr), 1);
-  bp_pack_value (bp, TREE_DEPRECATED (expr), 1);
-  if (TYPE_P (expr))
-    bp_pack_value (bp, TYPE_SATURATING (expr), 1);
-  else if (TREE_CODE (expr) == SSA_NAME)
-    bp_pack_value (bp, SSA_NAME_IS_DEFAULT_DEF (expr), 1);
-  else
-    bp_pack_value (bp, 0, 1);
-}
-
-
-/* Pack all the non-pointer fields of the TS_REAL_CST structure of
-   expression EXPR into bitpack BP.  */
-
-static void
-pack_ts_real_cst_value_fields (struct bitpack_d *bp, tree expr)
-{
-  unsigned i;
-  REAL_VALUE_TYPE r;
-
-  r = TREE_REAL_CST (expr);
-  bp_pack_value (bp, r.cl, 2);
-  bp_pack_value (bp, r.decimal, 1);
-  bp_pack_value (bp, r.sign, 1);
-  bp_pack_value (bp, r.signalling, 1);
-  bp_pack_value (bp, r.canonical, 1);
-  bp_pack_value (bp, r.uexp, EXP_BITS);
-  for (i = 0; i < SIGSZ; i++)
-    bp_pack_value (bp, r.sig[i], HOST_BITS_PER_LONG);
-}
-
-
-/* Pack all the non-pointer fields of the TS_FIXED_CST structure of
-   expression EXPR into bitpack BP.  */
-
-static void
-pack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
-{
-  struct fixed_value fv = TREE_FIXED_CST (expr);
-  bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, fv.mode);
-  bp_pack_var_len_int (bp, fv.data.low);
-  bp_pack_var_len_int (bp, fv.data.high);
-}
-
-
-/* Pack all the non-pointer fields of the TS_DECL_COMMON structure
-   of expression EXPR into bitpack BP.  */
-
-static void
-pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
-{
-  bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, DECL_MODE (expr));
-  bp_pack_value (bp, DECL_NONLOCAL (expr), 1);
-  bp_pack_value (bp, DECL_VIRTUAL_P (expr), 1);
-  bp_pack_value (bp, DECL_IGNORED_P (expr), 1);
-  bp_pack_value (bp, DECL_ABSTRACT (expr), 1);
-  bp_pack_value (bp, DECL_ARTIFICIAL (expr), 1);
-  bp_pack_value (bp, DECL_USER_ALIGN (expr), 1);
-  bp_pack_value (bp, DECL_PRESERVE_P (expr), 1);
-  bp_pack_value (bp, DECL_DEBUG_EXPR_IS_FROM (expr), 1);
-  bp_pack_value (bp, DECL_EXTERNAL (expr), 1);
-  bp_pack_value (bp, DECL_GIMPLE_REG_P (expr), 1);
-  bp_pack_var_len_unsigned (bp, DECL_ALIGN (expr));
-
-  if (TREE_CODE (expr) == LABEL_DECL)
-    {
-      /* Note that we do not write LABEL_DECL_UID.  The reader will
-	 always assume an initial value of -1 so that the
-	 label_to_block_map is recreated by gimple_set_bb.  */
-      bp_pack_value (bp, DECL_ERROR_ISSUED (expr), 1);
-      bp_pack_var_len_unsigned (bp, EH_LANDING_PAD_NR (expr));
-    }
-
-  if (TREE_CODE (expr) == FIELD_DECL)
-    {
-      bp_pack_value (bp, DECL_PACKED (expr), 1);
-      bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
-      bp_pack_value (bp, expr->decl_common.off_align, 8);
-    }
-
-  if (TREE_CODE (expr) == RESULT_DECL
-      || TREE_CODE (expr) == PARM_DECL
-      || TREE_CODE (expr) == VAR_DECL)
-    {
-      bp_pack_value (bp, DECL_BY_REFERENCE (expr), 1);
-      if (TREE_CODE (expr) == VAR_DECL
-	  || TREE_CODE (expr) == PARM_DECL)
-	bp_pack_value (bp, DECL_HAS_VALUE_EXPR_P (expr), 1);
-      bp_pack_value (bp, DECL_RESTRICTED_P (expr), 1);
-    }
-}
-
-
-/* Pack all the non-pointer fields of the TS_DECL_WRTL structure
-   of expression EXPR into bitpack BP.  */
-
-static void
-pack_ts_decl_wrtl_value_fields (struct bitpack_d *bp, tree expr)
-{
-  bp_pack_value (bp, DECL_REGISTER (expr), 1);
-}
-
-
-/* Pack all the non-pointer fields of the TS_DECL_WITH_VIS structure
-   of expression EXPR into bitpack BP.  */
-
-static void
-pack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
-{
-  bp_pack_value (bp, DECL_DEFER_OUTPUT (expr), 1);
-  bp_pack_value (bp, DECL_COMMON (expr), 1);
-  bp_pack_value (bp, DECL_DLLIMPORT_P (expr), 1);
-  bp_pack_value (bp, DECL_WEAK (expr), 1);
-  bp_pack_value (bp, DECL_SEEN_IN_BIND_EXPR_P (expr),  1);
-  bp_pack_value (bp, DECL_COMDAT (expr),  1);
-  bp_pack_value (bp, DECL_VISIBILITY (expr),  2);
-  bp_pack_value (bp, DECL_VISIBILITY_SPECIFIED (expr),  1);
-
-  if (TREE_CODE (expr) == VAR_DECL)
-    {
-      bp_pack_value (bp, DECL_HARD_REGISTER (expr), 1);
-      bp_pack_value (bp, DECL_IN_TEXT_SECTION (expr), 1);
-      bp_pack_value (bp, DECL_IN_CONSTANT_POOL (expr), 1);
-      bp_pack_value (bp, DECL_TLS_MODEL (expr),  3);
-    }
-
-  if (VAR_OR_FUNCTION_DECL_P (expr))
-    bp_pack_var_len_unsigned (bp, DECL_INIT_PRIORITY (expr));
-}
-
-
-/* Pack all the non-pointer fields of the TS_FUNCTION_DECL structure
-   of expression EXPR into bitpack BP.  */
-
-static void
-pack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
-{
-  /* For normal/md builtins we only write the class and code, so they
-     should never be handled here.  */
-  gcc_assert (!lto_stream_as_builtin_p (expr));
-
-  bp_pack_enum (bp, built_in_class, BUILT_IN_LAST,
-		DECL_BUILT_IN_CLASS (expr));
-  bp_pack_value (bp, DECL_STATIC_CONSTRUCTOR (expr), 1);
-  bp_pack_value (bp, DECL_STATIC_DESTRUCTOR (expr), 1);
-  bp_pack_value (bp, DECL_UNINLINABLE (expr), 1);
-  bp_pack_value (bp, DECL_POSSIBLY_INLINED (expr), 1);
-  bp_pack_value (bp, DECL_IS_NOVOPS (expr), 1);
-  bp_pack_value (bp, DECL_IS_RETURNS_TWICE (expr), 1);
-  bp_pack_value (bp, DECL_IS_MALLOC (expr), 1);
-  bp_pack_value (bp, DECL_IS_OPERATOR_NEW (expr), 1);
-  bp_pack_value (bp, DECL_DECLARED_INLINE_P (expr), 1);
-  bp_pack_value (bp, DECL_STATIC_CHAIN (expr), 1);
-  bp_pack_value (bp, DECL_NO_INLINE_WARNING_P (expr), 1);
-  bp_pack_value (bp, DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr), 1);
-  bp_pack_value (bp, DECL_NO_LIMIT_STACK (expr), 1);
-  bp_pack_value (bp, DECL_DISREGARD_INLINE_LIMITS (expr), 1);
-  bp_pack_value (bp, DECL_PURE_P (expr), 1);
-  bp_pack_value (bp, DECL_LOOPING_CONST_OR_PURE_P (expr), 1);
-  if (DECL_BUILT_IN_CLASS (expr) != NOT_BUILT_IN)
-    bp_pack_value (bp, DECL_FUNCTION_CODE (expr), 11);
-  if (DECL_STATIC_DESTRUCTOR (expr))
-    bp_pack_var_len_unsigned (bp, DECL_FINI_PRIORITY (expr));
-}
-
-
-/* Pack all the non-pointer fields of the TS_TYPE_COMMON structure
-   of expression EXPR into bitpack BP.  */
-
-static void
-pack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
-{
-  bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, TYPE_MODE (expr));
-  bp_pack_value (bp, TYPE_STRING_FLAG (expr), 1);
-  bp_pack_value (bp, TYPE_NO_FORCE_BLK (expr), 1);
-  bp_pack_value (bp, TYPE_NEEDS_CONSTRUCTING (expr), 1);
-  if (RECORD_OR_UNION_TYPE_P (expr))
-    bp_pack_value (bp, TYPE_TRANSPARENT_AGGR (expr), 1);
-  bp_pack_value (bp, TYPE_PACKED (expr), 1);
-  bp_pack_value (bp, TYPE_RESTRICT (expr), 1);
-  bp_pack_value (bp, TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr), 2);
-  bp_pack_value (bp, TYPE_USER_ALIGN (expr), 1);
-  bp_pack_value (bp, TYPE_READONLY (expr), 1);
-  bp_pack_var_len_unsigned (bp, TYPE_PRECISION (expr));
-  bp_pack_var_len_unsigned (bp, TYPE_ALIGN (expr));
-  bp_pack_var_len_int (bp, TYPE_ALIAS_SET (expr) == 0 ? 0 : -1);
-}
-
-
-/* Pack all the non-pointer fields of the TS_BLOCK structure
-   of expression EXPR into bitpack BP.  */
-
-static void
-pack_ts_block_value_fields (struct bitpack_d *bp, tree expr)
-{
-  bp_pack_value (bp, BLOCK_ABSTRACT (expr), 1);
-  /* BLOCK_NUMBER is recomputed.  */
-}
-
-/* Pack all the non-pointer fields of the TS_TRANSLATION_UNIT_DECL structure
-   of expression EXPR into bitpack BP.  */
-
-static void
-pack_ts_translation_unit_decl_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED, tree expr ATTRIBUTE_UNUSED)
-{
-}
-
-/* Pack all the non-pointer fields in EXPR into a bit pack.  */
-
-static void
-pack_value_fields (struct bitpack_d *bp, tree expr)
-{
-  enum tree_code code;
-
-  code = TREE_CODE (expr);
-
-  /* Note that all these functions are highly sensitive to changes in
-     the types and sizes of each of the fields being packed.  */
-  pack_ts_base_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
-    pack_ts_real_cst_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_FIXED_CST))
-    pack_ts_fixed_cst_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
-    pack_ts_decl_common_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL))
-    pack_ts_decl_wrtl_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
-    pack_ts_decl_with_vis_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
-    pack_ts_function_decl_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
-    pack_ts_type_common_value_fields (bp, expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
-    pack_ts_block_value_fields (bp, 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);
-}
-
-
-/* Output info about new location into bitpack BP.
-   After outputting bitpack, lto_output_location_data has
-   to be done to output actual data.  */
-
-static inline void
-lto_output_location_bitpack (struct bitpack_d *bp,
-			     struct output_block *ob,
-			     location_t loc)
-{
-  expanded_location xloc;
-
-  bp_pack_value (bp, loc == UNKNOWN_LOCATION, 1);
-  if (loc == UNKNOWN_LOCATION)
-    return;
-
-  xloc = expand_location (loc);
-
-  bp_pack_value (bp, ob->current_file != xloc.file, 1);
-  if (ob->current_file != xloc.file)
-    bp_pack_var_len_unsigned (bp, lto_string_index (ob,
-					            xloc.file,
-						    strlen (xloc.file) + 1,
-						    true));
-  ob->current_file = xloc.file;
-
-  bp_pack_value (bp, ob->current_line != xloc.line, 1);
-  if (ob->current_line != xloc.line)
-    bp_pack_var_len_unsigned (bp, xloc.line);
-  ob->current_line = xloc.line;
-
-  bp_pack_value (bp, ob->current_col != xloc.column, 1);
-  if (ob->current_col != xloc.column)
-    bp_pack_var_len_unsigned (bp, xloc.column);
-  ob->current_col = xloc.column;
-}
-
-
-/* Emit location LOC to output block OB.
-   When bitpack is handy, it is more space effecient to call
-   lto_output_location_bitpack with existing bitpack.  */
-
-static void
-lto_output_location (struct output_block *ob, location_t loc)
-{
-  struct bitpack_d bp = bitpack_create (ob->main_stream);
-  lto_output_location_bitpack (&bp, ob, loc);
-  lto_output_bitpack (&bp);
-}
-
-
-/* Return true if tree node T is written to various tables.  For these
-   nodes, we sometimes want to write their phyiscal representation
-   (via lto_output_tree), and sometimes we need to emit an index
-   reference into a table (via lto_output_tree_ref).  */
-
-static bool
-tree_is_indexable (tree t)
-{
-  if (TREE_CODE (t) == PARM_DECL)
-    return false;
-  else if (TREE_CODE (t) == VAR_DECL && decl_function_context (t)
-	   && !TREE_STATIC (t))
-    return false;
-  else
-    return (TYPE_P (t) || DECL_P (t) || TREE_CODE (t) == SSA_NAME);
-}
-
-
-/* If EXPR is an indexable tree node, output a reference to it to
-   output block OB.  Otherwise, output the physical representation of
-   EXPR to OB.  */
-
-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);
-      return;
-    }
-
-  code = TREE_CODE (expr);
-  switch (code)
-    {
-    case SSA_NAME:
-      output_record_start (ob, LTO_ssa_name_ref);
-      output_uleb128 (ob, SSA_NAME_VERSION (expr));
-      break;
-
-    case FIELD_DECL:
-      output_record_start (ob, LTO_field_decl_ref);
-      lto_output_field_decl_index (ob->decl_state, ob->main_stream, expr);
-      break;
-
-    case FUNCTION_DECL:
-      output_record_start (ob, LTO_function_decl_ref);
-      lto_output_fn_decl_index (ob->decl_state, ob->main_stream, expr);
-      break;
-
-    case VAR_DECL:
-    case DEBUG_EXPR_DECL:
-      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;
-
-    case CONST_DECL:
-      output_record_start (ob, LTO_const_decl_ref);
-      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
-      break;
-
-    case IMPORTED_DECL:
-      gcc_assert (decl_function_context (expr) == NULL);
-      output_record_start (ob, LTO_imported_decl_ref);
-      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
-      break;
-
-    case TYPE_DECL:
-      output_record_start (ob, LTO_type_decl_ref);
-      lto_output_type_decl_index (ob->decl_state, ob->main_stream, expr);
-      break;
-
-    case NAMESPACE_DECL:
-      output_record_start (ob, LTO_namespace_decl_ref);
-      lto_output_namespace_decl_index (ob->decl_state, ob->main_stream, expr);
-      break;
-
-    case LABEL_DECL:
-      output_record_start (ob, LTO_label_decl_ref);
-      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
-      break;
-
-    case RESULT_DECL:
-      output_record_start (ob, LTO_result_decl_ref);
-      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
-      break;
-
-    case TRANSLATION_UNIT_DECL:
-      output_record_start (ob, LTO_translation_unit_decl_ref);
-      lto_output_var_decl_index (ob->decl_state, ob->main_stream, 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 ();
-	  }
-      }
-    }
-}
-
-
-/* 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);
-}
-
-
-/* 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.  */
-
-static void
-lto_output_chain (struct output_block *ob, tree t, bool ref_p)
-{
-  int i, count;
-
-  count = list_length (t);
-  output_sleb128 (ob, count);
-  for (i = 0; i < count; i++)
-    {
-      tree saved_chain;
-
-      /* Clear TREE_CHAIN to avoid blindly recursing into the rest
-	 of the list.  */
-      saved_chain = TREE_CHAIN (t);
-      TREE_CHAIN (t) = NULL_TREE;
-
-      lto_output_tree_or_ref (ob, t, ref_p);
-
-      TREE_CHAIN (t) = saved_chain;
-      t = TREE_CHAIN (t);
-    }
-}
-
-
-/* Write all pointer fields in the TS_COMMON structure of EXPR to output
-   block OB.  If REF_P is true, write a reference to EXPR's pointer
-   fields.  */
-
-static void
-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);
-}
-
-
-/* Write all pointer fields in the TS_VECTOR structure of EXPR to output
-   block OB.  If REF_P is true, write a reference to EXPR's pointer
-   fields.  */
-
-static void
-lto_output_ts_vector_tree_pointers (struct output_block *ob, tree expr,
-				    bool ref_p)
-{
-  lto_output_chain (ob, TREE_VECTOR_CST_ELTS (expr), ref_p);
-}
-
-
-/* Write all pointer fields in the TS_COMPLEX structure of EXPR to output
-   block OB.  If REF_P is true, write a reference to EXPR's pointer
-   fields.  */
-
-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);
-}
-
-
-/* Write all pointer fields in the TS_DECL_MINIMAL structure of EXPR
-   to output block OB.  If REF_P is true, write a reference to EXPR's
-   pointer fields.  */
-
-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);
-  lto_output_location (ob, DECL_SOURCE_LOCATION (expr));
-}
-
-
-/* Write all pointer fields in the TS_DECL_COMMON structure of EXPR to
-   output block OB.  If REF_P is true, write a reference to EXPR's
-   pointer fields.  */
-
-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);
-
-  /* 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);
-
-  /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
-     for early inlining so drop it on the floor instead of ICEing in
-     dwarf2out.c.  */
-
-  if (TREE_CODE (expr) == PARM_DECL)
-    lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
-
-  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);
-
-  if (TREE_CODE (expr) == VAR_DECL)
-    lto_output_tree_or_ref (ob, DECL_DEBUG_EXPR (expr), ref_p);
-}
-
-
-/* Write all pointer fields in the TS_DECL_NON_COMMON structure of
-   EXPR to output block OB.  If REF_P is true, write a reference to EXPR's
-   pointer fields.  */
-
-static void
-lto_output_ts_decl_non_common_tree_pointers (struct output_block *ob,
-					     tree expr, bool ref_p)
-{
-  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);
-    }
-  lto_output_tree_or_ref (ob, DECL_VINDEX (expr), ref_p);
-}
-
-
-/* Write all pointer fields in the TS_DECL_WITH_VIS structure of EXPR
-   to output block OB.  If REF_P is true, write a reference to EXPR's
-   pointer fields.  */
-
-static void
-lto_output_ts_decl_with_vis_tree_pointers (struct output_block *ob, tree expr,
-					   bool ref_p)
-{
-  /* 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);
-  else
-    output_record_start (ob, LTO_null);
-
-  lto_output_tree_or_ref (ob, DECL_SECTION_NAME (expr), ref_p);
-  lto_output_tree_or_ref (ob, DECL_COMDAT_GROUP (expr), ref_p);
-}
-
-
-/* Write all pointer fields in the TS_FIELD_DECL structure of EXPR to
-   output block OB.  If REF_P is true, write a reference to EXPR's
-   pointer fields.  */
-
-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);
-  lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
-}
-
-
-/* Write all pointer fields in the TS_FUNCTION_DECL structure of EXPR
-   to output block OB.  If REF_P is true, write a reference to EXPR's
-   pointer fields.  */
-
-static void
-lto_output_ts_function_decl_tree_pointers (struct output_block *ob, tree expr,
-					   bool ref_p)
-{
-  /* DECL_STRUCT_FUNCTION is handled by lto_output_function.  FIXME lto,
-     maybe it should be handled here?  */
-  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);
-}
-
-
-/* Write all pointer fields in the TS_TYPE_COMMON structure of EXPR to
-   output block OB.  If REF_P is true, write a reference to EXPR's
-   pointer fields.  */
-
-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);
-  /* 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);
-  /* 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);
-}
-
-/* Write all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
-   to output block OB.  If REF_P is true, write a reference to EXPR's
-   pointer fields.  */
-
-static void
-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);
-  else if (TREE_CODE (expr) == ARRAY_TYPE)
-    lto_output_tree_or_ref (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);
-  else if (TREE_CODE (expr) == FUNCTION_TYPE
-	   || TREE_CODE (expr) == METHOD_TYPE)
-    lto_output_tree_or_ref (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);
-  if (RECORD_OR_UNION_TYPE_P (expr))
-    lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p);
-}
-
-
-/* Write all pointer fields in the TS_LIST structure of EXPR to output
-   block OB.  If REF_P is true, write a reference to EXPR's pointer
-   fields.  */
-
-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);
-  lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
-}
-
-
-/* Write all pointer fields in the TS_VEC structure of EXPR to output
-   block OB.  If REF_P is true, write a reference to EXPR's pointer
-   fields.  */
-
-static void
-lto_output_ts_vec_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
-{
-  int i;
-
-  /* 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);
-}
-
-
-/* Write all pointer fields in the TS_EXP structure of EXPR to output
-   block OB.  If REF_P is true, write a reference to EXPR's pointer
-   fields.  */
-
-static void
-lto_output_ts_exp_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
-{
-  int i;
-
-  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);
-  lto_output_location (ob, EXPR_LOCATION (expr));
-  lto_output_tree_or_ref (ob, TREE_BLOCK (expr), ref_p);
-}
-
-
-/* Write all pointer fields in the TS_BLOCK structure of EXPR to output
-   block OB.  If REF_P is true, write a reference to EXPR's pointer
-   fields.  */
-
-static void
-lto_output_ts_block_tree_pointers (struct output_block *ob, tree expr,
-				   bool ref_p)
-{
-  /* Do not stream BLOCK_SOURCE_LOCATION.  We cannot handle debug information
-     for early inlining so drop it on the floor instead of ICEing in
-     dwarf2out.c.  */
-  lto_output_chain (ob, BLOCK_VARS (expr), ref_p);
-
-  /* Do not stream BLOCK_NONLOCALIZED_VARS.  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_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);
-  /* Do not output BLOCK_SUBBLOCKS.  Instead on streaming-in this
-     list is re-constructed from BLOCK_SUPERCONTEXT.  */
-}
-
-
-/* Write all pointer fields in the TS_BINFO structure of EXPR to output
-   block OB.  If REF_P is true, write a reference to EXPR's pointer
-   fields.  */
-
-static void
-lto_output_ts_binfo_tree_pointers (struct output_block *ob, tree expr,
-				   bool ref_p)
-{
-  unsigned i;
-  tree t;
-
-  /* Note that the number of BINFO slots has already been emitted in
-     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);
-
-  lto_output_tree_or_ref (ob, BINFO_OFFSET (expr), ref_p);
-  lto_output_tree_or_ref (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);
-
-  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);
-
-  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);
-}
-
-
-/* Write all pointer fields in the TS_CONSTRUCTOR structure of EXPR to
-   output block OB.  If REF_P is true, write a reference to EXPR's
-   pointer fields.  */
-
-static void
-lto_output_ts_constructor_tree_pointers (struct output_block *ob, tree expr,
-					 bool ref_p)
-{
-  unsigned i;
-  tree index, value;
-
-  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);
-    }
-}
-
-/* Write a TS_TARGET_OPTION tree in EXPR to OB.  */
-
-static void
-lto_output_ts_target_option (struct output_block *ob, tree expr)
-{
-  struct cl_target_option *t = TREE_TARGET_OPTION (expr);
-  struct bitpack_d bp;
-  unsigned i, len;
-
-  /* The cl_target_option is target specific and generated by the options
-     awk script, so we just recreate a byte-by-byte copy here. */
-
-  bp = bitpack_create (ob->main_stream);
-  len = sizeof (struct cl_target_option);
-  for (i = 0; i < len; i++)
-    bp_pack_value (&bp, ((unsigned char *)t)[i], 8);
-  /* Catch struct size mismatches between reader and writer. */
-  bp_pack_value (&bp, 0x12345678, 32);
-  lto_output_bitpack (&bp);
-}
-
-/* Write a TS_TRANSLATION_UNIT_DECL tree in EXPR to OB.  */
-
-static void
-lto_output_ts_translation_unit_decl_tree_pointers (struct output_block *ob,
-						   tree expr)
-{
-  lto_output_string (ob, ob->main_stream,
-		     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.  */
-
-static void
-lto_output_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
-{
-  enum tree_code code;
-
-  code = TREE_CODE (expr);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
-    lto_output_ts_common_tree_pointers (ob, expr, ref_p);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_VECTOR))
-    lto_output_ts_vector_tree_pointers (ob, expr, ref_p);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX))
-    lto_output_ts_complex_tree_pointers (ob, expr, ref_p);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL))
-    lto_output_ts_decl_minimal_tree_pointers (ob, expr, ref_p);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
-    lto_output_ts_decl_common_tree_pointers (ob, expr, ref_p);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
-    lto_output_ts_decl_non_common_tree_pointers (ob, expr, ref_p);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
-    lto_output_ts_decl_with_vis_tree_pointers (ob, expr, ref_p);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL))
-    lto_output_ts_field_decl_tree_pointers (ob, expr, ref_p);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
-    lto_output_ts_function_decl_tree_pointers (ob, expr, ref_p);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
-    lto_output_ts_type_common_tree_pointers (ob, expr, ref_p);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON))
-    lto_output_ts_type_non_common_tree_pointers (ob, expr, ref_p);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_LIST))
-    lto_output_ts_list_tree_pointers (ob, expr, ref_p);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_VEC))
-    lto_output_ts_vec_tree_pointers (ob, expr, ref_p);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_EXP))
-    lto_output_ts_exp_tree_pointers (ob, expr, ref_p);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
-    lto_output_ts_block_tree_pointers (ob, expr, ref_p);
-
-  if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
-    lto_output_ts_binfo_tree_pointers (ob, expr, ref_p);
+    ob->cfg_stream = XCNEW (struct lto_output_stream);
 
-  if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
-    lto_output_ts_constructor_tree_pointers (ob, expr, ref_p);
+  clear_line_info (ob);
 
-  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
-    lto_output_ts_target_option (ob, expr);
+  ob->string_hash_table = htab_create (37, hash_string_slot_node,
+				       eq_string_slot_node, NULL);
+  gcc_obstack_init (&ob->obstack);
 
-  if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
-    lto_output_ts_translation_unit_decl_tree_pointers (ob, expr);
+  return ob;
 }
 
 
-/* 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.  */
+/* Destroy the output block OB.  */
 
-static void
-lto_output_tree_header (struct output_block *ob, tree expr)
+void
+destroy_output_block (struct output_block *ob)
 {
-  enum LTO_tags tag;
-  enum tree_code code;
+  enum lto_section_type section_type = ob->section_type;
 
-  /* 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
-     EXPR on the reading side (such as the number of slots in
-     variable sized nodes).  */
-  tag = lto_tree_code_to_tag (code);
-  output_record_start (ob, tag);
+  htab_delete (ob->string_hash_table);
 
-  /* The following will cause bootstrap miscomparisons.  Enable with care.  */
-#ifdef LTO_STREAMER_DEBUG
-  /* This is used mainly for debugging purposes.  When the reader
-     and the writer do not agree on a streamed node, the pointer
-     value for EXPR can be used to track down the differences in
-     the debugger.  */
-  gcc_assert ((HOST_WIDEST_INT) (intptr_t) expr == (intptr_t) expr);
-  output_sleb128 (ob, (HOST_WIDEST_INT) (intptr_t) expr);
-#endif
+  free (ob->main_stream);
+  free (ob->string_stream);
+  if (section_type == LTO_section_function_body)
+    free (ob->cfg_stream);
+
+  lto_streamer_cache_delete (ob->writer_cache);
+  obstack_free (&ob->obstack, NULL);
 
-  /* The text in strings and identifiers are completely emitted in
-     the header.  */
-  if (CODE_CONTAINS_STRUCT (code, TS_STRING))
-    output_string_cst (ob, ob->main_stream, expr);
-  else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER))
-    output_identifier (ob, ob->main_stream, expr);
-  else if (CODE_CONTAINS_STRUCT (code, TS_VEC))
-    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);
+  free (ob);
 }
 
 
-/* Write the code and class of builtin EXPR to output block OB.  IX is
-   the index into the streamer cache where EXPR is stored.*/
+/* Look up NODE in the type table and write the index for it to OB.  */
 
 static void
-lto_output_builtin_tree (struct output_block *ob, tree expr)
+output_type_ref (struct output_block *ob, tree node)
 {
-  gcc_assert (lto_stream_as_builtin_p (expr));
+  output_record_start (ob, LTO_type_ref);
+  lto_output_type_ref_index (ob->decl_state, ob->main_stream, node);
+}
 
-  if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD
-      && !targetm.builtin_decl)
-    sorry ("gimple bytecode streams do not support machine specific builtin "
-	   "functions on this target");
 
-  output_record_start (ob, LTO_builtin_decl);
-  lto_output_enum (ob->main_stream, built_in_class, BUILT_IN_LAST,
-		   DECL_BUILT_IN_CLASS (expr));
-  output_uleb128 (ob, DECL_FUNCTION_CODE (expr));
+/* Return true if tree node T is written to various tables.  For these
+   nodes, we sometimes want to write their phyiscal representation
+   (via lto_output_tree), and sometimes we need to emit an index
+   reference into a table (via lto_output_tree_ref).  */
 
-  if (DECL_ASSEMBLER_NAME_SET_P (expr))
-    {
-      /* When the assembler name of a builtin gets a user name,
-	 the new name is always prefixed with '*' by
-	 set_builtin_user_assembler_name.  So, to prevent the
-	 reader side from adding a second '*', we omit it here.  */
-      const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (expr));
-      if (strlen (str) > 1 && str[0] == '*')
-	lto_output_string (ob, ob->main_stream, &str[1], true);
-      else
-	lto_output_string (ob, ob->main_stream, NULL, true);
-    }
+static bool
+tree_is_indexable (tree t)
+{
+  if (TREE_CODE (t) == PARM_DECL)
+    return false;
+  else if (TREE_CODE (t) == VAR_DECL && decl_function_context (t)
+	   && !TREE_STATIC (t))
+    return false;
   else
-    lto_output_string (ob, ob->main_stream, NULL, true);
+    return (TYPE_P (t) || DECL_P (t) || TREE_CODE (t) == SSA_NAME);
 }
 
 
-/* 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.  */
+/* Output info about new location into bitpack BP.
+   After outputting bitpack, lto_output_location_data has
+   to be done to output actual data.  */
 
-static void
-lto_write_tree (struct output_block *ob, tree expr, bool ref_p)
+static inline void
+lto_output_location_bitpack (struct bitpack_d *bp,
+			     struct output_block *ob,
+			     location_t loc)
 {
-  struct bitpack_d bp;
+  expanded_location xloc;
 
-  /* Write the header, containing everything needed to materialize
-     EXPR on the reading side.  */
-  lto_output_tree_header (ob, expr);
+  bp_pack_value (bp, loc == UNKNOWN_LOCATION, 1);
+  if (loc == UNKNOWN_LOCATION)
+    return;
 
-  /* 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);
+  xloc = expand_location (loc);
 
-  /* Write all the pointer fields in EXPR.  */
-  lto_output_tree_pointers (ob, expr, ref_p);
+  bp_pack_value (bp, ob->current_file != xloc.file, 1);
+  if (ob->current_file != xloc.file)
+    bp_pack_var_len_unsigned (bp, lto_string_index (ob,
+					            xloc.file,
+						    strlen (xloc.file) + 1,
+						    true));
+  ob->current_file = xloc.file;
 
-  /* 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);
+  bp_pack_value (bp, ob->current_line != xloc.line, 1);
+  if (ob->current_line != xloc.line)
+    bp_pack_var_len_unsigned (bp, xloc.line);
+  ob->current_line = xloc.line;
 
-  /* Mark the end of EXPR.  */
-  output_zero (ob);
+  bp_pack_value (bp, ob->current_col != xloc.column, 1);
+  if (ob->current_col != xloc.column)
+    bp_pack_var_len_unsigned (bp, xloc.column);
+  ob->current_col = xloc.column;
 }
 
 
-/* GIMPLE hook for writing GIMPLE-specific parts of trees.  OB, EXPR
-   and REF_P are as in lto_write_tree.  */
+/* Emit location LOC to output block OB.
+   When bitpack is handy, it is more space effecient to call
+   lto_output_location_bitpack with existing bitpack.  */
 
 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 integer constant CST to output block OB.  If REF_P is true,
-   CST's type will be emitted as a reference.  */
-
-static void
-lto_output_integer_cst (struct output_block *ob, tree cst, bool ref_p)
+lto_output_location (struct output_block *ob, location_t loc)
 {
-  output_record_start (ob, lto_tree_code_to_tag (INTEGER_CST));
-  lto_output_tree_or_ref (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));
+  struct bitpack_d bp = bitpack_create (ob->main_stream);
+  lto_output_location_bitpack (&bp, ob, loc);
+  lto_output_bitpack (&bp);
 }
 
 
-/* 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.  */
+/* If EXPR is an indexable tree node, output a reference to it to
+   output block OB.  Otherwise, output the physical representation of
+   EXPR to OB.  */
 
 void
-lto_output_tree (struct output_block *ob, tree expr, bool ref_p)
+lto_output_tree_ref (struct output_block *ob, tree expr)
 {
-  unsigned ix;
-  bool existed_p;
+  enum tree_code code;
 
   if (expr == NULL_TREE)
     {
@@ -1440,39 +199,99 @@ lto_output_tree (struct output_block *ob, tree expr, bool ref_p)
       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)
+  if (!tree_is_indexable (expr))
     {
-      lto_output_integer_cst (ob, expr, ref_p);
+      /* Even though we are emitting the physical representation of
+	 EXPR, its leaves must be emitted as references.  */
+      lto_output_tree (ob, expr, true);
       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))
+  if (TYPE_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);
+      output_type_ref (ob, expr);
+      return;
     }
-  else
+
+  code = TREE_CODE (expr);
+  switch (code)
     {
-      /* This is the first time we see EXPR, write its fields
-	 to OB.  */
-      lto_write_tree (ob, expr, ref_p);
+    case SSA_NAME:
+      output_record_start (ob, LTO_ssa_name_ref);
+      output_uleb128 (ob, SSA_NAME_VERSION (expr));
+      break;
+
+    case FIELD_DECL:
+      output_record_start (ob, LTO_field_decl_ref);
+      lto_output_field_decl_index (ob->decl_state, ob->main_stream, expr);
+      break;
+
+    case FUNCTION_DECL:
+      output_record_start (ob, LTO_function_decl_ref);
+      lto_output_fn_decl_index (ob->decl_state, ob->main_stream, expr);
+      break;
+
+    case VAR_DECL:
+    case DEBUG_EXPR_DECL:
+      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;
+
+    case CONST_DECL:
+      output_record_start (ob, LTO_const_decl_ref);
+      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
+      break;
+
+    case IMPORTED_DECL:
+      gcc_assert (decl_function_context (expr) == NULL);
+      output_record_start (ob, LTO_imported_decl_ref);
+      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
+      break;
+
+    case TYPE_DECL:
+      output_record_start (ob, LTO_type_decl_ref);
+      lto_output_type_decl_index (ob->decl_state, ob->main_stream, expr);
+      break;
+
+    case NAMESPACE_DECL:
+      output_record_start (ob, LTO_namespace_decl_ref);
+      lto_output_namespace_decl_index (ob->decl_state, ob->main_stream, expr);
+      break;
+
+    case LABEL_DECL:
+      output_record_start (ob, LTO_label_decl_ref);
+      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
+      break;
+
+    case RESULT_DECL:
+      output_record_start (ob, LTO_result_decl_ref);
+      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
+      break;
+
+    case TRANSLATION_UNIT_DECL:
+      output_record_start (ob, LTO_translation_unit_decl_ref);
+      lto_output_var_decl_index (ob->decl_state, ob->main_stream, 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 ();
+	  }
+      }
     }
 }
 
@@ -1722,190 +541,6 @@ output_cfg (struct output_block *ob, struct function *fn)
 }
 
 
-/* Output PHI function PHI to the main stream in OB.  */
-
-static void
-output_phi (struct output_block *ob, gimple phi)
-{
-  unsigned i, len = gimple_phi_num_args (phi);
-
-  output_record_start (ob, lto_gimple_code_to_tag (GIMPLE_PHI));
-  output_uleb128 (ob, SSA_NAME_VERSION (PHI_RESULT (phi)));
-
-  for (i = 0; i < len; i++)
-    {
-      lto_output_tree_ref (ob, gimple_phi_arg_def (phi, i));
-      output_uleb128 (ob, gimple_phi_arg_edge (phi, i)->src->index);
-      lto_output_location (ob, gimple_phi_arg_location (phi, i));
-    }
-}
-
-
-/* Emit statement STMT on the main stream of output block OB.  */
-
-static void
-output_gimple_stmt (struct output_block *ob, gimple stmt)
-{
-  unsigned i;
-  enum gimple_code code;
-  enum LTO_tags tag;
-  struct bitpack_d bp;
-
-  /* Emit identifying tag.  */
-  code = gimple_code (stmt);
-  tag = lto_gimple_code_to_tag (code);
-  output_record_start (ob, tag);
-
-  /* Emit the tuple header.  */
-  bp = bitpack_create (ob->main_stream);
-  bp_pack_var_len_unsigned (&bp, gimple_num_ops (stmt));
-  bp_pack_value (&bp, gimple_no_warning_p (stmt), 1);
-  if (is_gimple_assign (stmt))
-    bp_pack_value (&bp, gimple_assign_nontemporal_move_p (stmt), 1);
-  bp_pack_value (&bp, gimple_has_volatile_ops (stmt), 1);
-  bp_pack_var_len_unsigned (&bp, stmt->gsbase.subcode);
-  lto_output_bitpack (&bp);
-
-  /* Emit location information for the statement.  */
-  lto_output_location (ob, gimple_location (stmt));
-
-  /* Emit the lexical block holding STMT.  */
-  lto_output_tree (ob, gimple_block (stmt), true);
-
-  /* Emit the operands.  */
-  switch (gimple_code (stmt))
-    {
-    case GIMPLE_RESX:
-      output_sleb128 (ob, gimple_resx_region (stmt));
-      break;
-
-    case GIMPLE_EH_MUST_NOT_THROW:
-      lto_output_tree_ref (ob, gimple_eh_must_not_throw_fndecl (stmt));
-      break;
-
-    case GIMPLE_EH_DISPATCH:
-      output_sleb128 (ob, gimple_eh_dispatch_region (stmt));
-      break;
-
-    case GIMPLE_ASM:
-      lto_output_uleb128_stream (ob->main_stream, gimple_asm_ninputs (stmt));
-      lto_output_uleb128_stream (ob->main_stream, gimple_asm_noutputs (stmt));
-      lto_output_uleb128_stream (ob->main_stream, gimple_asm_nclobbers (stmt));
-      lto_output_uleb128_stream (ob->main_stream, gimple_asm_nlabels (stmt));
-      lto_output_string (ob, ob->main_stream, gimple_asm_string (stmt), true);
-      /* Fallthru  */
-
-    case GIMPLE_ASSIGN:
-    case GIMPLE_CALL:
-    case GIMPLE_RETURN:
-    case GIMPLE_SWITCH:
-    case GIMPLE_LABEL:
-    case GIMPLE_COND:
-    case GIMPLE_GOTO:
-    case GIMPLE_DEBUG:
-      for (i = 0; i < gimple_num_ops (stmt); i++)
-	{
-	  tree op = gimple_op (stmt, i);
-	  /* Wrap all uses of non-automatic variables inside MEM_REFs
-	     so that we do not have to deal with type mismatches on
-	     merged symbols during IL read in.  The first operand
-	     of GIMPLE_DEBUG must be a decl, not MEM_REF, though.  */
-	  if (op && (i || !is_gimple_debug (stmt)))
-	    {
-	      tree *basep = &op;
-	      while (handled_component_p (*basep))
-		basep = &TREE_OPERAND (*basep, 0);
-	      if (TREE_CODE (*basep) == VAR_DECL
-		  && !auto_var_in_fn_p (*basep, current_function_decl)
-		  && !DECL_REGISTER (*basep))
-		{
-		  bool volatilep = TREE_THIS_VOLATILE (*basep);
-		  *basep = build2 (MEM_REF, TREE_TYPE (*basep),
-				   build_fold_addr_expr (*basep),
-				   build_int_cst (build_pointer_type
-						  (TREE_TYPE (*basep)), 0));
-		  TREE_THIS_VOLATILE (*basep) = volatilep;
-		}
-	    }
-	  lto_output_tree_ref (ob, op);
-	}
-      if (is_gimple_call (stmt))
-	{
-	  if (gimple_call_internal_p (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));
-	}
-      break;
-
-    case GIMPLE_NOP:
-    case GIMPLE_PREDICT:
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-}
-
-
-/* Output a basic block BB to the main stream in OB for this FN.  */
-
-static void
-output_bb (struct output_block *ob, basic_block bb, struct function *fn)
-{
-  gimple_stmt_iterator bsi = gsi_start_bb (bb);
-
-  output_record_start (ob,
-		       (!gsi_end_p (bsi)) || phi_nodes (bb)
-		        ? LTO_bb1
-			: LTO_bb0);
-
-  output_uleb128 (ob, bb->index);
-  output_sleb128 (ob, bb->count);
-  output_sleb128 (ob, bb->loop_depth);
-  output_sleb128 (ob, bb->frequency);
-  output_sleb128 (ob, bb->flags);
-
-  if (!gsi_end_p (bsi) || phi_nodes (bb))
-    {
-      /* Output the statements.  The list of statements is terminated
-	 with a zero.  */
-      for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
-	{
-	  int region;
-	  gimple stmt = gsi_stmt (bsi);
-
-	  output_gimple_stmt (ob, stmt);
-
-	  /* Emit the EH region holding STMT.  */
-	  region = lookup_stmt_eh_lp_fn (fn, stmt);
-	  if (region != 0)
-	    {
-	      output_record_start (ob, LTO_eh_region);
-	      output_sleb128 (ob, region);
-	    }
-	  else
-	    output_record_start (ob, LTO_null);
-	}
-
-      output_record_start (ob, LTO_null);
-
-      for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
-	{
-	  gimple phi = gsi_stmt (bsi);
-
-	  /* Only emit PHIs for gimple registers.  PHI nodes for .MEM
-	     will be filled in on reading when the SSA form is
-	     updated.  */
-	  if (is_gimple_reg (gimple_phi_result (phi)))
-	    output_phi (ob, phi);
-	}
-
-      output_record_start (ob, LTO_null);
-    }
-}
-
 /* Create the header in the file using OB.  If the section type is for
    a function, set FN to the decl for that function.  */
 
diff --git a/gcc/lto-streamer.c b/gcc/lto-streamer.c
index 0608b33..328e654 100644
--- a/gcc/lto-streamer.c
+++ b/gcc/lto-streamer.c
@@ -32,14 +32,13 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-core.h"
 #include "bitmap.h"
 #include "vec.h"
+#include "tree-streamer.h"
 #include "lto-streamer.h"
+#include "streamer-hooks.h"
 
 /* Statistics gathered during LTO, WPA and LTRANS.  */
 struct lto_stats_d lto_stats;
 
-/* Streamer hooks.  */
-struct streamer_hooks streamer_hooks;
-
 /* LTO uses bitmaps with different life-times.  So use a seperate
    obstack for all LTO bitmaps.  */
 static bitmap_obstack lto_obstack;
@@ -258,226 +257,6 @@ print_lto_report (void)
 }
 
 
-/* Check that all the TS_* structures handled by the lto_output_* and
-   lto_input_* routines are exactly ALL the structures defined in
-   treestruct.def.  */
-
-static void
-check_handled_ts_structures (void)
-{
-  bool handled_p[LAST_TS_ENUM];
-  unsigned i;
-
-  memset (&handled_p, 0, sizeof (handled_p));
-
-  /* These are the TS_* structures that are either handled or
-     explicitly ignored by the streamer routines.  */
-  handled_p[TS_BASE] = true;
-  handled_p[TS_TYPED] = true;
-  handled_p[TS_COMMON] = true;
-  handled_p[TS_INT_CST] = true;
-  handled_p[TS_REAL_CST] = true;
-  handled_p[TS_FIXED_CST] = true;
-  handled_p[TS_VECTOR] = true;
-  handled_p[TS_STRING] = true;
-  handled_p[TS_COMPLEX] = true;
-  handled_p[TS_IDENTIFIER] = true;
-  handled_p[TS_DECL_MINIMAL] = true;
-  handled_p[TS_DECL_COMMON] = true;
-  handled_p[TS_DECL_WRTL] = true;
-  handled_p[TS_DECL_NON_COMMON] = true;
-  handled_p[TS_DECL_WITH_VIS] = true;
-  handled_p[TS_FIELD_DECL] = true;
-  handled_p[TS_VAR_DECL] = true;
-  handled_p[TS_PARM_DECL] = true;
-  handled_p[TS_LABEL_DECL] = true;
-  handled_p[TS_RESULT_DECL] = true;
-  handled_p[TS_CONST_DECL] = true;
-  handled_p[TS_TYPE_DECL] = true;
-  handled_p[TS_FUNCTION_DECL] = true;
-  handled_p[TS_TYPE_COMMON] = true;
-  handled_p[TS_TYPE_WITH_LANG_SPECIFIC] = true;
-  handled_p[TS_TYPE_NON_COMMON] = true;
-  handled_p[TS_LIST] = true;
-  handled_p[TS_VEC] = true;
-  handled_p[TS_EXP] = true;
-  handled_p[TS_SSA_NAME] = true;
-  handled_p[TS_BLOCK] = true;
-  handled_p[TS_BINFO] = true;
-  handled_p[TS_STATEMENT_LIST] = true;
-  handled_p[TS_CONSTRUCTOR] = true;
-  handled_p[TS_OMP_CLAUSE] = true;
-  handled_p[TS_OPTIMIZATION] = true;
-  handled_p[TS_TARGET_OPTION] = true;
-  handled_p[TS_TRANSLATION_UNIT_DECL] = true;
-
-  /* Anything not marked above will trigger the following assertion.
-     If this assertion triggers, it means that there is a new TS_*
-     structure that should be handled by the streamer.  */
-  for (i = 0; i < LAST_TS_ENUM; i++)
-    gcc_assert (handled_p[i]);
-}
-
-
-/* Helper for lto_streamer_cache_insert_1.  Add T to CACHE->NODES at
-   slot IX.  */
-
-static void
-lto_streamer_cache_add_to_node_array (struct lto_streamer_cache_d *cache,
-				      unsigned ix, tree t)
-{
-  /* Make sure we're either replacing an old element or
-     appending consecutively.  */
-  gcc_assert (ix <= VEC_length (tree, cache->nodes));
-
-  if (ix == VEC_length (tree, cache->nodes))
-    VEC_safe_push (tree, heap, cache->nodes, t);
-  else
-    VEC_replace (tree, cache->nodes, ix, t);
-}
-
-
-/* Helper for lto_streamer_cache_insert and lto_streamer_cache_insert_at.
-   CACHE, T, and IX_P are as in lto_streamer_cache_insert.
-
-   If INSERT_AT_NEXT_SLOT_P is true, T is inserted at the next available
-   slot in the cache.  Otherwise, T is inserted at the position indicated
-   in *IX_P.
-
-   If T already existed in CACHE, return true.  Otherwise,
-   return false.  */
-
-static bool
-lto_streamer_cache_insert_1 (struct lto_streamer_cache_d *cache,
-			     tree t, unsigned *ix_p,
-			     bool insert_at_next_slot_p)
-{
-  void **slot;
-  unsigned ix;
-  bool existed_p;
-
-  gcc_assert (t);
-
-  slot = pointer_map_insert (cache->node_map, t);
-  if (!*slot)
-    {
-      /* Determine the next slot to use in the cache.  */
-      if (insert_at_next_slot_p)
-	ix = VEC_length (tree, cache->nodes);
-      else
-	ix = *ix_p;
-       *slot = (void *)(size_t) (ix + 1);
-
-      lto_streamer_cache_add_to_node_array (cache, ix, t);
-
-      /* Indicate that the item was not present in the cache.  */
-      existed_p = false;
-    }
-  else
-    {
-      ix = (size_t) *slot - 1;
-
-      if (!insert_at_next_slot_p && ix != *ix_p)
-	{
-	  /* If the caller wants to insert T at a specific slot
-	     location, and ENTRY->TO does not match *IX_P, add T to
-	     the requested location slot.  */
-	  ix = *ix_p;
-	  lto_streamer_cache_add_to_node_array (cache, ix, t);
-	}
-
-      /* Indicate that T was already in the cache.  */
-      existed_p = true;
-    }
-
-  if (ix_p)
-    *ix_p = ix;
-
-  return existed_p;
-}
-
-
-/* Insert tree node T in CACHE.  If T already existed in the cache
-   return true.  Otherwise, return false.
-
-   If IX_P is non-null, update it with the index into the cache where
-   T has been stored.  */
-
-bool
-lto_streamer_cache_insert (struct lto_streamer_cache_d *cache, tree t,
-			   unsigned *ix_p)
-{
-  return lto_streamer_cache_insert_1 (cache, t, ix_p, true);
-}
-
-
-/* Insert tree node T in CACHE at slot IX.  If T already
-   existed in the cache return true.  Otherwise, return false.  */
-
-bool
-lto_streamer_cache_insert_at (struct lto_streamer_cache_d *cache,
-			      tree t, unsigned ix)
-{
-  return lto_streamer_cache_insert_1 (cache, t, &ix, false);
-}
-
-
-/* Appends tree node T to CACHE, even if T already existed in it.  */
-
-void
-lto_streamer_cache_append (struct lto_streamer_cache_d *cache, tree t)
-{
-  unsigned ix = VEC_length (tree, cache->nodes);
-  lto_streamer_cache_insert_1 (cache, t, &ix, false);
-}
-
-/* Return true if tree node T exists in CACHE, otherwise false.  If IX_P is
-   not NULL, write to *IX_P the index into the cache where T is stored
-   ((unsigned)-1 if T is not found).  */
-
-bool
-lto_streamer_cache_lookup (struct lto_streamer_cache_d *cache, tree t,
-			   unsigned *ix_p)
-{
-  void **slot;
-  bool retval;
-  unsigned ix;
-
-  gcc_assert (t);
-
-  slot = pointer_map_contains  (cache->node_map, t);
-  if (slot == NULL)
-    {
-      retval = false;
-      ix = -1;
-    }
-  else
-    {
-      retval = true;
-      ix = (size_t) *slot - 1;
-    }
-
-  if (ix_p)
-    *ix_p = ix;
-
-  return retval;
-}
-
-
-/* Return the tree node at slot IX in CACHE.  */
-
-tree
-lto_streamer_cache_get (struct lto_streamer_cache_d *cache, unsigned ix)
-{
-  gcc_assert (cache);
-
-  /* Make sure we're not requesting something we don't have.  */
-  gcc_assert (ix < VEC_length (tree, cache->nodes));
-
-  return VEC_index (tree, cache->nodes, ix);
-}
-
-
 /* Record NODE in CACHE.  */
 
 static void
@@ -557,39 +336,6 @@ lto_preload_common_nodes (struct lto_streamer_cache_d *cache)
       lto_record_common_node (cache, global_trees[i]);
 }
 
-/* Create a cache of pickled nodes.  */
-
-struct lto_streamer_cache_d *
-lto_streamer_cache_create (void)
-{
-  struct lto_streamer_cache_d *cache;
-
-  cache = XCNEW (struct lto_streamer_cache_d);
-
-  cache->node_map = pointer_map_create ();
-
-  /* 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);
-
-  return cache;
-}
-
-
-/* Delete the streamer cache C.  */
-
-void
-lto_streamer_cache_delete (struct lto_streamer_cache_d *c)
-{
-  if (c == NULL)
-    return;
-
-  pointer_map_destroy (c->node_map);
-  VEC_free (tree, heap, c->nodes);
-  free (c);
-}
-
 
 #ifdef LTO_STREAMER_DEBUG
 static htab_t tree_htab;
@@ -756,12 +502,3 @@ lto_streamer_hooks_init (void)
   streamer_hooks.write_tree = lto_streamer_write_tree;
   streamer_hooks.read_tree = lto_streamer_read_tree;
 }
-
-
-/* Initialize the current set of streamer hooks.  */
-
-void
-streamer_hooks_init (void)
-{
-  memset (&streamer_hooks, 0, sizeof (streamer_hooks));
-}
diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
index 157e5c0..230838b 100644
--- a/gcc/lto-streamer.h
+++ b/gcc/lto-streamer.h
@@ -32,12 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "vecprim.h"
 #include "alloc-pool.h"
 #include "gcov-io.h"
-
-/* Forward declarations to avoid including unnecessary headers.  */
-struct output_block;
-struct lto_input_block;
-struct data_in;
-struct bitpack_d;
+#include "diagnostic.h"
 
 /* Define when debugging the LTO streamer.  This causes the writer
    to output the numeric value for the memory address of the tree node
@@ -152,27 +147,6 @@ struct bitpack_d;
 typedef unsigned char	lto_decl_flags_t;
 
 
-/* Data structures used to pack values and bitflags into a vector of
-   words.  Used to stream values of a fixed number of bits in a space
-   efficient way.  */
-static unsigned const BITS_PER_BITPACK_WORD = HOST_BITS_PER_WIDE_INT;
-
-typedef unsigned HOST_WIDE_INT bitpack_word_t;
-DEF_VEC_I(bitpack_word_t);
-DEF_VEC_ALLOC_I(bitpack_word_t, heap);
-
-struct bitpack_d
-{
-  /* The position of the first unused or unconsumed bit in the word.  */
-  unsigned pos;
-
-  /* The current word we are (un)packing.  */
-  bitpack_word_t word;
-
-  /* The lto_output_stream or the lto_input_block we are streaming to/from.  */
-  void *stream;
-};
-
 /* Tags representing the various IL objects written to the bytecode file
    (GIMPLE statements, basic blocks, EH regions, tree nodes, etc).
 
@@ -332,33 +306,6 @@ typedef void (lto_free_section_data_f) (struct lto_file_decl_data *,
 					const char *,
 					size_t);
 
-/* Cache of pickled nodes.  Used to avoid writing the same node more
-   than once.  The first time a tree node is streamed out, it is
-   entered in this cache.  Subsequent references to the same node are
-   resolved by looking it up in this cache.
-
-   This is used in two ways:
-
-   - On the writing side, the first time T is added to STREAMER_CACHE,
-     a new reference index is created for T and T is emitted on the
-     stream.  If T needs to be emitted again to the stream, instead of
-     pickling it again, the reference index is emitted.
-
-   - On the reading side, the first time T is read from the stream, it
-     is reconstructed in memory and a new reference index created for
-     T.  The reconstructed T is inserted in some array so that when
-     the reference index for T is found in the input stream, it can be
-     used to look up into the array to get the reconstructed T.  */
-struct lto_streamer_cache_d
-{
-  /* The mapping between tree nodes and slots into the nodes array.  */
-  struct pointer_map_t *node_map;
-
-  /* The nodes pickled so far.  */
-  VEC(tree,heap) *nodes;
-};
-
-
 /* Structure used as buffer for reading an LTO file.  */
 struct lto_input_block
 {
@@ -747,86 +694,6 @@ struct data_in
 };
 
 
-/* Streamer hooks.  These functions do additional processing as
-   needed by the module.  There are two types of callbacks, those that
-   replace the default behavior and those that supplement it.
-
-   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.  */
-  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);
-};
-
-/* Streamer hooks.  */
-extern struct streamer_hooks streamer_hooks;
-
 /* In lto-section-in.c  */
 extern struct lto_input_block * lto_create_simple_input_block (
 			       struct lto_file_decl_data *,
@@ -864,10 +731,6 @@ extern void lto_section_overrun (struct lto_input_block *) ATTRIBUTE_NORETURN;
 extern void lto_value_range_error (const char *,
 				   HOST_WIDE_INT, HOST_WIDE_INT,
 				   HOST_WIDE_INT) ATTRIBUTE_NORETURN;
-extern void bp_pack_var_len_unsigned (struct bitpack_d *, unsigned HOST_WIDE_INT);
-extern void bp_pack_var_len_int (struct bitpack_d *, HOST_WIDE_INT);
-extern unsigned HOST_WIDE_INT bp_unpack_var_len_unsigned (struct bitpack_d *);
-extern HOST_WIDE_INT bp_unpack_var_len_int (struct bitpack_d *);
 
 /* In lto-section-out.c  */
 extern hashval_t lto_hash_decl_slot_node (const void *);
@@ -919,16 +782,6 @@ extern bitmap lto_bitmap_alloc (void);
 extern void lto_bitmap_free (bitmap);
 extern char *lto_get_section_name (int, const char *, struct lto_file_decl_data *);
 extern void print_lto_report (void);
-extern bool lto_streamer_cache_insert (struct lto_streamer_cache_d *, tree,
-				       unsigned *);
-extern bool lto_streamer_cache_insert_at (struct lto_streamer_cache_d *, tree,
-					  unsigned);
-extern void lto_streamer_cache_append (struct lto_streamer_cache_d *, tree);
-extern bool lto_streamer_cache_lookup (struct lto_streamer_cache_d *, tree,
-				       unsigned *);
-extern tree lto_streamer_cache_get (struct lto_streamer_cache_d *, unsigned);
-extern struct lto_streamer_cache_d *lto_streamer_cache_create (void);
-extern void lto_streamer_cache_delete (struct lto_streamer_cache_d *);
 extern void lto_streamer_init (void);
 extern bool gate_lto_out (void);
 #ifdef LTO_STREAMER_DEBUG
@@ -938,15 +791,10 @@ extern void lto_orig_address_remove (tree);
 #endif
 extern void lto_check_version (int, int);
 extern void lto_streamer_hooks_init (void);
-extern void lto_streamer_write_tree (struct output_block *, tree, bool);
-extern void lto_streamer_read_tree (struct lto_input_block *,
-				     struct data_in *, tree);
-extern void streamer_hooks_init (void);
 
 /* In lto-streamer-in.c */
 extern void lto_input_cgraph (struct lto_file_decl_data *, const char *);
 extern void lto_reader_init (void);
-extern tree lto_input_tree (struct lto_input_block *, struct data_in *);
 extern void lto_input_function_body (struct lto_file_decl_data *, tree,
 				     const char *);
 extern void lto_input_constructors_and_inits (struct lto_file_decl_data *,
@@ -955,9 +803,12 @@ extern struct data_in *lto_data_in_create (struct lto_file_decl_data *,
 				    const char *, unsigned,
 				    VEC(ld_plugin_symbol_resolution_t,heap) *);
 extern void lto_data_in_delete (struct data_in *);
-extern const char *lto_input_string (struct data_in *,
-				     struct lto_input_block *);
 extern void lto_input_data_block (struct lto_input_block *, void *, size_t);
+location_t lto_input_location (struct lto_input_block *, struct data_in *);
+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);
 
 
 /* In lto-streamer-out.c  */
@@ -971,6 +822,8 @@ 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);
 
 
 /* In lto-cgraph.c  */
@@ -1096,6 +949,28 @@ lto_tag_to_tree_code (enum LTO_tags tag)
   return (enum tree_code) ((unsigned) tag - 1);
 }
 
+/* Check that tag ACTUAL == EXPECTED.  */
+static inline void
+lto_tag_check (enum LTO_tags actual, enum LTO_tags expected)
+{
+  if (actual != expected)
+    internal_error ("bytecode stream: expected tag %s instead of %s",
+		    lto_tag_name (expected), lto_tag_name (actual));
+}
+
+/* Check that tag ACTUAL is in the range [TAG1, TAG2].  */
+static inline void
+lto_tag_check_range (enum LTO_tags actual, enum LTO_tags tag1,
+		     enum LTO_tags tag2)
+{
+  if (actual < tag1 || actual > tag2)
+    internal_error ("bytecode stream: tag %s is not in the expected range "
+		    "[%s, %s]",
+		    lto_tag_name (actual),
+		    lto_tag_name (tag1),
+		    lto_tag_name (tag2));
+}
+
 /* Initialize an lto_out_decl_buffer ENCODER.  */
 static inline void
 lto_init_tree_ref_encoder (struct lto_tree_ref_encoder *encoder,
@@ -1160,232 +1035,4 @@ DEFINE_DECL_STREAM_FUNCS (TYPE_DECL, type_decl)
 DEFINE_DECL_STREAM_FUNCS (NAMESPACE_DECL, namespace_decl)
 DEFINE_DECL_STREAM_FUNCS (LABEL_DECL, label_decl)
 
-/* Returns a new bit-packing context for bit-packing into S.  */
-static inline struct bitpack_d
-bitpack_create (struct lto_output_stream *s)
-{
-  struct bitpack_d bp;
-  bp.pos = 0;
-  bp.word = 0;
-  bp.stream = (void *)s;
-  return bp;
-}
-
-/* Pack the NBITS bit sized value VAL into the bit-packing context BP.  */
-static inline void
-bp_pack_value (struct bitpack_d *bp, bitpack_word_t val, unsigned nbits)
-{
-  bitpack_word_t word = bp->word;
-  int pos = bp->pos;
-
-  /* Verify that VAL fits in the NBITS.  */
-  gcc_checking_assert (nbits == BITS_PER_BITPACK_WORD
-		       || !(val & ~(((bitpack_word_t)1<<nbits)-1)));
-
-  /* If val does not fit into the current bitpack word switch to the
-     next one.  */
-  if (pos + nbits > BITS_PER_BITPACK_WORD)
-    {
-      lto_output_uleb128_stream ((struct lto_output_stream *) bp->stream, word);
-      word = val;
-      pos = nbits;
-    }
-  else
-    {
-      word |= val << pos;
-      pos += nbits;
-    }
-  bp->word = word;
-  bp->pos = pos;
-}
-
-/* Finishes bit-packing of BP.  */
-static inline void
-lto_output_bitpack (struct bitpack_d *bp)
-{
-  lto_output_uleb128_stream ((struct lto_output_stream *) bp->stream,
-			     bp->word);
-  bp->word = 0;
-  bp->pos = 0;
-}
-
-/* Returns a new bit-packing context for bit-unpacking from IB.  */
-static inline struct bitpack_d
-lto_input_bitpack (struct lto_input_block *ib)
-{
-  struct bitpack_d bp;
-  bp.word = lto_input_uleb128 (ib);
-  bp.pos = 0;
-  bp.stream = (void *)ib;
-  return bp;
-}
-
-/* Unpacks NBITS bits from the bit-packing context BP and returns them.  */
-static inline bitpack_word_t
-bp_unpack_value (struct bitpack_d *bp, unsigned nbits)
-{
-  bitpack_word_t mask, val;
-  int pos = bp->pos;
-
-  mask = (nbits == BITS_PER_BITPACK_WORD
-	  ? (bitpack_word_t) -1
-	  : ((bitpack_word_t) 1 << nbits) - 1);
-
-  /* If there are not continuous nbits in the current bitpack word
-     switch to the next one.  */
-  if (pos + nbits > BITS_PER_BITPACK_WORD)
-    {
-      bp->word = val = lto_input_uleb128 ((struct lto_input_block *)bp->stream);
-      bp->pos = nbits;
-      return val & mask;
-    }
-  val = bp->word;
-  val >>= pos;
-  bp->pos = pos + nbits;
-
-  return val & mask;
-}
-
-
-/* Write a character to the output block.  */
-
-static inline void
-lto_output_1_stream (struct lto_output_stream *obs, char c)
-{
-  /* No space left.  */
-  if (obs->left_in_block == 0)
-    lto_append_block (obs);
-
-  /* Write the actual character.  */
-  *obs->current_pointer = c;
-  obs->current_pointer++;
-  obs->total_size++;
-  obs->left_in_block--;
-}
-
-
-/* Read byte from the input block.  */
-
-static inline unsigned char
-lto_input_1_unsigned (struct lto_input_block *ib)
-{
-  if (ib->p >= ib->len)
-    lto_section_overrun (ib);
-  return (ib->data[ib->p++]);
-}
-
-/* Output VAL into OBS and verify it is in range MIN...MAX that is supposed
-   to be compile time constant.
-   Be host independent, limit range to 31bits.  */
-
-static inline void
-lto_output_int_in_range (struct lto_output_stream *obs,
-			 HOST_WIDE_INT min,
-			 HOST_WIDE_INT max,
-			 HOST_WIDE_INT val)
-{
-  HOST_WIDE_INT range = max - min;
-
-  gcc_checking_assert (val >= min && val <= max && range > 0
-		       && range < 0x7fffffff);
-
-  val -= min;
-  lto_output_1_stream (obs, val & 255);
-  if (range >= 0xff)
-    lto_output_1_stream (obs, (val >> 8) & 255);
-  if (range >= 0xffff)
-    lto_output_1_stream (obs, (val >> 16) & 255);
-  if (range >= 0xffffff)
-    lto_output_1_stream (obs, (val >> 24) & 255);
-}
-
-/* Input VAL into OBS and verify it is in range MIN...MAX that is supposed
-   to be compile time constant.  PURPOSE is used for error reporting.  */
-
-static inline HOST_WIDE_INT
-lto_input_int_in_range (struct lto_input_block *ib,
-			const char *purpose,
-			HOST_WIDE_INT min,
-			HOST_WIDE_INT max)
-{
-  HOST_WIDE_INT range = max - min;
-  HOST_WIDE_INT val = lto_input_1_unsigned (ib);
-
-  gcc_checking_assert (range > 0 && range < 0x7fffffff);
-
-  if (range >= 0xff)
-    val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 8;
-  if (range >= 0xffff)
-    val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 16;
-  if (range >= 0xffffff)
-    val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 24;
-  val += min;
-  if (val < min || val > max)
-    lto_value_range_error (purpose, val, min, max);
-  return val;
-}
-
-
-/* Output VAL into BP and verify it is in range MIN...MAX that is supposed
-   to be compile time constant.
-   Be host independent, limit range to 31bits.  */
-
-static inline void
-bp_pack_int_in_range (struct bitpack_d *bp,
-		      HOST_WIDE_INT min,
-		      HOST_WIDE_INT max,
-		      HOST_WIDE_INT val)
-{
-  HOST_WIDE_INT range = max - min;
-  int nbits = floor_log2 (range) + 1;
-
-  gcc_checking_assert (val >= min && val <= max && range > 0
-		       && range < 0x7fffffff);
-
-  val -= min;
-  bp_pack_value (bp, val, nbits);
-}
-
-/* Input VAL into BP and verify it is in range MIN...MAX that is supposed
-   to be compile time constant.  PURPOSE is used for error reporting.  */
-
-static inline HOST_WIDE_INT
-bp_unpack_int_in_range (struct bitpack_d *bp,
-		        const char *purpose,
-		        HOST_WIDE_INT min,
-		        HOST_WIDE_INT max)
-{
-  HOST_WIDE_INT range = max - min;
-  int nbits = floor_log2 (range) + 1;
-  HOST_WIDE_INT val = bp_unpack_value (bp, nbits);
-
-  gcc_checking_assert (range > 0 && range < 0x7fffffff);
-
-  if (val < min || val > max)
-    lto_value_range_error (purpose, val, min, max);
-  return val;
-}
-
-/* Output VAL of type "enum enum_name" into OBS.
-   Assume range 0...ENUM_LAST - 1.  */
-#define lto_output_enum(obs,enum_name,enum_last,val) \
-  lto_output_int_in_range ((obs), 0, (int)(enum_last) - 1, (int)(val))
-
-/* Input enum of type "enum enum_name" from IB.
-   Assume range 0...ENUM_LAST - 1.  */
-#define lto_input_enum(ib,enum_name,enum_last) \
-  (enum enum_name)lto_input_int_in_range ((ib), #enum_name, 0, \
-					  (int)(enum_last) - 1)
-
-/* Output VAL of type "enum enum_name" into BP.
-   Assume range 0...ENUM_LAST - 1.  */
-#define bp_pack_enum(bp,enum_name,enum_last,val) \
-  bp_pack_int_in_range ((bp), 0, (int)(enum_last) - 1, (int)(val))
-
-/* Input enum of type "enum enum_name" from BP.
-   Assume range 0...ENUM_LAST - 1.  */
-#define bp_unpack_enum(bp,enum_name,enum_last) \
-  (enum enum_name)bp_unpack_int_in_range ((bp), #enum_name, 0, \
-					(int)(enum_last) - 1)
-
 #endif /* GCC_LTO_STREAMER_H  */
diff --git a/gcc/lto/Make-lang.in b/gcc/lto/Make-lang.in
index d5a15f8..c48c8d2 100644
--- a/gcc/lto/Make-lang.in
+++ b/gcc/lto/Make-lang.in
@@ -86,7 +86,7 @@ lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \
 	langhooks.h $(VEC_H) $(BITMAP_H) pointer-set.h $(IPA_PROP_H) \
 	$(COMMON_H) debug.h $(TIMEVAR_H) $(GIMPLE_H) $(LTO_H) $(LTO_TREE_H) \
 	$(LTO_TAGS_H) $(LTO_STREAMER_H) $(SPLAY_TREE_H) gt-lto-lto.h $(PARAMS_H) \
-	ipa-inline.h $(IPA_UTILS_H)
+	ipa-inline.h $(IPA_UTILS_H) $(TREE_STREAMER_H)
 lto/lto-object.o: lto/lto-object.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
 	$(DIAGNOSTIC_CORE_H) $(LTO_H) $(TM_H) $(LTO_STREAMER_H) \
 	../include/simple-object.h
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 4323c4f..93ff805 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "lto.h"
 #include "lto-tree.h"
 #include "lto-streamer.h"
+#include "tree-streamer.h"
 #include "splay-tree.h"
 #include "params.h"
 #include "ipa-inline.h"
diff --git a/gcc/streamer-hooks.c b/gcc/streamer-hooks.c
new file mode 100644
index 0000000..ef5fee3
--- /dev/null
+++ b/gcc/streamer-hooks.c
@@ -0,0 +1,37 @@
+/* Streamer hooks.  Support for adding streamer-specific callbacks to
+   generic streaming routines.
+
+   Copyright 2011 Free Software Foundation, Inc.
+   Contributed by Diego Novillo <dnovillo@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "streamer-hooks.h"
+
+/* Streamer hooks.  */
+struct streamer_hooks streamer_hooks;
+
+/* Initialize the current set of streamer hooks.  */
+
+void
+streamer_hooks_init (void)
+{
+  memset (&streamer_hooks, 0, sizeof (streamer_hooks));
+}
diff --git a/gcc/streamer-hooks.h b/gcc/streamer-hooks.h
new file mode 100644
index 0000000..29a6591
--- /dev/null
+++ b/gcc/streamer-hooks.h
@@ -0,0 +1,118 @@
+/* Streamer hooks.  Support for adding streamer-specific callbacks to
+   generic streaming routines.
+
+   Copyright 2011 Free Software Foundation, Inc.
+   Contributed by Diego Novillo <dnovillo@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_STREAMER_HOOKS_H
+#define GCC_STREAMER_HOOKS_H
+
+#include "tree.h"
+
+/* Forward declarations to avoid including unnecessary headers.  */
+struct output_block;
+struct lto_input_block;
+struct data_in;
+struct bitpack_d;
+struct lto_streamer_cache_d;
+
+/* Streamer hooks.  These functions do additional processing as
+   needed by the module.  There are two types of callbacks, those that
+   replace the default behavior and those that supplement it.
+
+   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.  */
+  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);
+};
+
+/* Streamer hooks.  */
+extern struct streamer_hooks streamer_hooks;
+
+/* In streamer-hooks.c.  */
+void streamer_hooks_init (void);
+
+#endif  /* GCC_STREAMER_HOOKS_H  */
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
new file mode 100644
index 0000000..cd2f221
--- /dev/null
+++ b/gcc/tree-streamer-in.c
@@ -0,0 +1,1153 @@
+/* Routines for reading trees from a file stream.
+
+   Copyright 2011 Free Software Foundation, Inc.
+   Contributed by Diego Novillo <dnovillo@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostic.h"
+#include "tree.h"
+#include "tree-flow.h"
+#include "tree-streamer.h"
+#include "data-streamer.h"
+#include "streamer-hooks.h"
+#include "lto-streamer.h"
+
+/* Read a STRING_CST from the string table in DATA_IN using input
+   block IB.  */
+
+tree
+input_string_cst (struct data_in *data_in, struct lto_input_block *ib)
+{
+  unsigned int len;
+  const char * ptr;
+
+  ptr = input_string_internal (data_in, ib, &len);
+  if (!ptr)
+    return NULL;
+  return build_string (len, ptr);
+}
+
+
+/* Read an IDENTIFIER from the string table in DATA_IN using input
+   block IB.  */
+
+static tree
+input_identifier (struct data_in *data_in, struct lto_input_block *ib)
+{
+  unsigned int len;
+  const char *ptr;
+
+  ptr = input_string_internal (data_in, ib, &len);
+  if (!ptr)
+    return NULL;
+  return get_identifier_with_length (ptr, len);
+}
+
+
+/* Read a chain of tree nodes from input block IB. DATA_IN contains
+   tables and descriptors for the file being read.  */
+
+static tree
+lto_input_chain (struct lto_input_block *ib, struct data_in *data_in)
+{
+  int i, count;
+  tree first, prev, curr;
+
+  first = prev = NULL_TREE;
+  count = lto_input_sleb128 (ib);
+  for (i = 0; i < count; i++)
+    {
+      curr = lto_input_tree (ib, data_in);
+      if (prev)
+	TREE_CHAIN (prev) = curr;
+      else
+	first = curr;
+
+      TREE_CHAIN (curr) = NULL_TREE;
+      prev = curr;
+    }
+
+  return first;
+}
+
+
+/* Unpack all the non-pointer fields of the TS_BASE structure of
+   expression EXPR from bitpack BP.  */
+
+static void
+unpack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
+{
+  /* Note that the code for EXPR has already been unpacked to create EXPR in
+     lto_materialize_tree.  */
+  if (!TYPE_P (expr))
+    {
+      TREE_SIDE_EFFECTS (expr) = (unsigned) bp_unpack_value (bp, 1);
+      TREE_CONSTANT (expr) = (unsigned) bp_unpack_value (bp, 1);
+      TREE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1);
+
+      /* TREE_PUBLIC is used on types to indicate that the type
+	 has a TYPE_CACHED_VALUES vector.  This is not streamed out,
+	 so we skip it here.  */
+      TREE_PUBLIC (expr) = (unsigned) bp_unpack_value (bp, 1);
+    }
+  else
+    bp_unpack_value (bp, 4);
+  TREE_ADDRESSABLE (expr) = (unsigned) bp_unpack_value (bp, 1);
+  TREE_THIS_VOLATILE (expr) = (unsigned) bp_unpack_value (bp, 1);
+  if (DECL_P (expr))
+    DECL_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1);
+  else if (TYPE_P (expr))
+    TYPE_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1);
+  else
+    bp_unpack_value (bp, 1);
+  TREE_ASM_WRITTEN (expr) = (unsigned) bp_unpack_value (bp, 1);
+  if (TYPE_P (expr))
+    TYPE_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1);
+  else
+    TREE_NO_WARNING (expr) = (unsigned) bp_unpack_value (bp, 1);
+  TREE_USED (expr) = (unsigned) bp_unpack_value (bp, 1);
+  TREE_NOTHROW (expr) = (unsigned) bp_unpack_value (bp, 1);
+  TREE_STATIC (expr) = (unsigned) bp_unpack_value (bp, 1);
+  TREE_PRIVATE (expr) = (unsigned) bp_unpack_value (bp, 1);
+  TREE_PROTECTED (expr) = (unsigned) bp_unpack_value (bp, 1);
+  TREE_DEPRECATED (expr) = (unsigned) bp_unpack_value (bp, 1);
+  if (TYPE_P (expr))
+    TYPE_SATURATING (expr) = (unsigned) bp_unpack_value (bp, 1);
+  else if (TREE_CODE (expr) == SSA_NAME)
+    SSA_NAME_IS_DEFAULT_DEF (expr) = (unsigned) bp_unpack_value (bp, 1);
+  else
+    bp_unpack_value (bp, 1);
+}
+
+
+/* Unpack all the non-pointer fields of the TS_REAL_CST structure of
+   expression EXPR from bitpack BP.  */
+
+static void
+unpack_ts_real_cst_value_fields (struct bitpack_d *bp, tree expr)
+{
+  unsigned i;
+  REAL_VALUE_TYPE r;
+  REAL_VALUE_TYPE *rp;
+
+  r.cl = (unsigned) bp_unpack_value (bp, 2);
+  r.decimal = (unsigned) bp_unpack_value (bp, 1);
+  r.sign = (unsigned) bp_unpack_value (bp, 1);
+  r.signalling = (unsigned) bp_unpack_value (bp, 1);
+  r.canonical = (unsigned) bp_unpack_value (bp, 1);
+  r.uexp = (unsigned) bp_unpack_value (bp, EXP_BITS);
+  for (i = 0; i < SIGSZ; i++)
+    r.sig[i] = (unsigned long) bp_unpack_value (bp, HOST_BITS_PER_LONG);
+
+  rp = ggc_alloc_real_value ();
+  memcpy (rp, &r, sizeof (REAL_VALUE_TYPE));
+  TREE_REAL_CST_PTR (expr) = rp;
+}
+
+
+/* Unpack all the non-pointer fields of the TS_FIXED_CST structure of
+   expression EXPR from bitpack BP.  */
+
+static void
+unpack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
+{
+  struct fixed_value fv;
+
+  fv.mode = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
+  fv.data.low = bp_unpack_var_len_int (bp);
+  fv.data.high = bp_unpack_var_len_int (bp);
+  TREE_FIXED_CST (expr) = fv;
+}
+
+
+/* Unpack all the non-pointer fields of the TS_DECL_COMMON structure
+   of expression EXPR from bitpack BP.  */
+
+static void
+unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
+{
+  DECL_MODE (expr) = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
+  DECL_NONLOCAL (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_VIRTUAL_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_IGNORED_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_ABSTRACT (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_USER_ALIGN (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_PRESERVE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_DEBUG_EXPR_IS_FROM (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_EXTERNAL (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_GIMPLE_REG_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_ALIGN (expr) = (unsigned) bp_unpack_var_len_unsigned (bp);
+
+  if (TREE_CODE (expr) == LABEL_DECL)
+    {
+      DECL_ERROR_ISSUED (expr) = (unsigned) bp_unpack_value (bp, 1);
+      EH_LANDING_PAD_NR (expr) = (int) bp_unpack_var_len_unsigned (bp);
+
+      /* Always assume an initial value of -1 for LABEL_DECL_UID to
+	 force gimple_set_bb to recreate label_to_block_map.  */
+      LABEL_DECL_UID (expr) = -1;
+    }
+
+  if (TREE_CODE (expr) == FIELD_DECL)
+    {
+      DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
+      DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+      expr->decl_common.off_align = bp_unpack_value (bp, 8);
+    }
+
+  if (TREE_CODE (expr) == RESULT_DECL
+      || TREE_CODE (expr) == PARM_DECL
+      || TREE_CODE (expr) == VAR_DECL)
+    {
+      DECL_BY_REFERENCE (expr) = (unsigned) bp_unpack_value (bp, 1);
+      if (TREE_CODE (expr) == VAR_DECL
+	  || TREE_CODE (expr) == PARM_DECL)
+	DECL_HAS_VALUE_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+      DECL_RESTRICTED_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+    }
+}
+
+
+/* Unpack all the non-pointer fields of the TS_DECL_WRTL structure
+   of expression EXPR from bitpack BP.  */
+
+static void
+unpack_ts_decl_wrtl_value_fields (struct bitpack_d *bp, tree expr)
+{
+  DECL_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1);
+}
+
+
+/* Unpack all the non-pointer fields of the TS_DECL_WITH_VIS structure
+   of expression EXPR from bitpack BP.  */
+
+static void
+unpack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
+{
+  DECL_DEFER_OUTPUT (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_COMMON (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_DLLIMPORT_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_WEAK (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_SEEN_IN_BIND_EXPR_P (expr) = (unsigned) bp_unpack_value (bp,  1);
+  DECL_COMDAT (expr) = (unsigned) bp_unpack_value (bp,  1);
+  DECL_VISIBILITY (expr) = (enum symbol_visibility) bp_unpack_value (bp,  2);
+  DECL_VISIBILITY_SPECIFIED (expr) = (unsigned) bp_unpack_value (bp,  1);
+
+  if (TREE_CODE (expr) == VAR_DECL)
+    {
+      DECL_HARD_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1);
+      DECL_IN_TEXT_SECTION (expr) = (unsigned) bp_unpack_value (bp, 1);
+      DECL_IN_CONSTANT_POOL (expr) = (unsigned) bp_unpack_value (bp, 1);
+      DECL_TLS_MODEL (expr) = (enum tls_model) bp_unpack_value (bp,  3);
+    }
+
+  if (VAR_OR_FUNCTION_DECL_P (expr))
+    {
+      priority_type p;
+      p = (priority_type) bp_unpack_var_len_unsigned (bp);
+      SET_DECL_INIT_PRIORITY (expr, p);
+    }
+}
+
+
+/* Unpack all the non-pointer fields of the TS_FUNCTION_DECL structure
+   of expression EXPR from bitpack BP.  */
+
+static void
+unpack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
+{
+  DECL_BUILT_IN_CLASS (expr) = bp_unpack_enum (bp, built_in_class,
+					       BUILT_IN_LAST);
+  DECL_STATIC_CONSTRUCTOR (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_STATIC_DESTRUCTOR (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_UNINLINABLE (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_POSSIBLY_INLINED (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_IS_NOVOPS (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_IS_RETURNS_TWICE (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_IS_MALLOC (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_IS_OPERATOR_NEW (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_DECLARED_INLINE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_STATIC_CHAIN (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_NO_INLINE_WARNING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr)
+    			= (unsigned) bp_unpack_value (bp, 1);
+  DECL_NO_LIMIT_STACK (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_DISREGARD_INLINE_LIMITS (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_LOOPING_CONST_OR_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+  if (DECL_BUILT_IN_CLASS (expr) != NOT_BUILT_IN)
+    {
+      DECL_FUNCTION_CODE (expr) = (enum built_in_function) bp_unpack_value (bp,
+	                                                                    11);
+      if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_NORMAL
+	  && DECL_FUNCTION_CODE (expr) >= END_BUILTINS)
+	fatal_error ("machine independent builtin code out of range");
+      else if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD)
+	{
+          tree result = targetm.builtin_decl (DECL_FUNCTION_CODE (expr), true);
+	  if (!result || result == error_mark_node)
+	    fatal_error ("target specific builtin not available");
+	}
+    }
+  if (DECL_STATIC_DESTRUCTOR (expr))
+    {
+      priority_type p;
+      p = (priority_type) bp_unpack_var_len_unsigned (bp);
+      SET_DECL_FINI_PRIORITY (expr, p);
+    }
+}
+
+
+/* Unpack all the non-pointer fields of the TS_TYPE_COMMON structure
+   of expression EXPR from bitpack BP.  */
+
+static void
+unpack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
+{
+  enum machine_mode mode;
+
+  mode = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
+  SET_TYPE_MODE (expr, mode);
+  TYPE_STRING_FLAG (expr) = (unsigned) bp_unpack_value (bp, 1);
+  TYPE_NO_FORCE_BLK (expr) = (unsigned) bp_unpack_value (bp, 1);
+  TYPE_NEEDS_CONSTRUCTING (expr) = (unsigned) bp_unpack_value (bp, 1);
+  if (RECORD_OR_UNION_TYPE_P (expr))
+    TYPE_TRANSPARENT_AGGR (expr) = (unsigned) bp_unpack_value (bp, 1);
+  TYPE_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
+  TYPE_RESTRICT (expr) = (unsigned) bp_unpack_value (bp, 1);
+  TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr)
+    	= (unsigned) bp_unpack_value (bp, 2);
+  TYPE_USER_ALIGN (expr) = (unsigned) bp_unpack_value (bp, 1);
+  TYPE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1);
+  TYPE_PRECISION (expr) = bp_unpack_var_len_unsigned (bp);
+  TYPE_ALIGN (expr) = bp_unpack_var_len_unsigned (bp);
+  TYPE_ALIAS_SET (expr) = bp_unpack_var_len_int (bp);
+}
+
+
+/* Unpack all the non-pointer fields of the TS_BLOCK structure
+   of expression EXPR from bitpack BP.  */
+
+static void
+unpack_ts_block_value_fields (struct bitpack_d *bp, tree expr)
+{
+  BLOCK_ABSTRACT (expr) = (unsigned) bp_unpack_value (bp, 1);
+  /* BLOCK_NUMBER is recomputed.  */
+}
+
+/* Unpack all the non-pointer fields of the TS_TRANSLATION_UNIT_DECL
+   structure of expression EXPR from bitpack BP.  */
+
+static void
+unpack_ts_translation_unit_decl_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED, tree expr ATTRIBUTE_UNUSED)
+{
+}
+
+/* Unpack all the non-pointer fields in EXPR into a bit pack.  */
+
+static void
+unpack_value_fields (struct bitpack_d *bp, tree expr)
+{
+  enum tree_code code;
+
+  code = TREE_CODE (expr);
+
+  /* Note that all these functions are highly sensitive to changes in
+     the types and sizes of each of the fields being packed.  */
+  unpack_ts_base_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
+    unpack_ts_real_cst_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_FIXED_CST))
+    unpack_ts_fixed_cst_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
+    unpack_ts_decl_common_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL))
+    unpack_ts_decl_wrtl_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
+    unpack_ts_decl_with_vis_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
+    unpack_ts_function_decl_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
+    unpack_ts_type_common_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
+    unpack_ts_block_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
+    unpack_ts_translation_unit_decl_value_fields (bp, expr);
+
+  if (streamer_hooks.unpack_value_fields)
+    streamer_hooks.unpack_value_fields (bp, expr);
+}
+
+
+/* Materialize a new tree from input block IB using descriptors in
+   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
+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
+  HOST_WIDEST_INT orig_address_in_writer;
+#endif
+
+  result = NULL_TREE;
+
+#ifdef LTO_STREAMER_DEBUG
+  /* Read the word representing the memory address for the tree
+     as it was written by the writer.  This is useful when
+     debugging differences between the writer and reader.  */
+  orig_address_in_writer = lto_input_sleb128 (ib);
+  gcc_assert ((intptr_t) orig_address_in_writer == orig_address_in_writer);
+#endif
+
+  code = lto_tag_to_tree_code (tag);
+
+  /* We should never see an SSA_NAME tree.  Only the version numbers of
+     SSA names are ever written out.  See input_ssa_names.  */
+  gcc_assert (code != SSA_NAME);
+
+  /* Instantiate a new tree using the header data.  */
+  if (CODE_CONTAINS_STRUCT (code, TS_STRING))
+    result = input_string_cst (data_in, ib);
+  else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER))
+    result = input_identifier (data_in, ib);
+  else if (CODE_CONTAINS_STRUCT (code, TS_VEC))
+    {
+      HOST_WIDE_INT len = lto_input_sleb128 (ib);
+      result = make_tree_vec (len);
+    }
+  else if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
+    {
+      unsigned HOST_WIDE_INT len = lto_input_uleb128 (ib);
+      result = make_tree_binfo (len);
+    }
+  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
+	 make_node call.  */
+      if (result == NULL_TREE)
+	result = make_node (code);
+    }
+
+#ifdef LTO_STREAMER_DEBUG
+  /* Store the original address of the tree as seen by the writer
+     in RESULT's aux field.  This is useful when debugging streaming
+     problems.  This way, a debugging session can be started on
+     both writer and reader with a breakpoint using this address
+     value in both.  */
+  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;
+}
+
+
+/* Read all pointer fields in the TS_COMMON structure of EXPR from input
+   block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+
+static void
+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);
+}
+
+
+/* Read all pointer fields in the TS_VECTOR structure of EXPR from input
+   block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+static void
+lto_input_ts_vector_tree_pointers (struct lto_input_block *ib,
+				   struct data_in *data_in, tree expr)
+{
+  TREE_VECTOR_CST_ELTS (expr) = lto_input_chain (ib, data_in);
+}
+
+
+/* Read all pointer fields in the TS_COMPLEX structure of EXPR from input
+   block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+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);
+}
+
+
+/* Read all pointer fields in the TS_DECL_MINIMAL structure of EXPR
+   from input block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+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_SOURCE_LOCATION (expr) = lto_input_location (ib, data_in);
+}
+
+
+/* Read all pointer fields in the TS_DECL_COMMON structure of EXPR from
+   input block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+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);
+
+  /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
+     for early inlining so drop it on the floor instead of ICEing in
+     dwarf2out.c.  */
+
+  if (TREE_CODE (expr) == PARM_DECL)
+    TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
+
+  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));
+
+  if (TREE_CODE (expr) == VAR_DECL)
+    {
+      tree dexpr = lto_input_tree (ib, data_in);
+      if (dexpr)
+	SET_DECL_DEBUG_EXPR (expr, dexpr);
+    }
+}
+
+
+/* Read all pointer fields in the TS_DECL_NON_COMMON structure of
+   EXPR from input block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+static void
+lto_input_ts_decl_non_common_tree_pointers (struct lto_input_block *ib,
+					    struct data_in *data_in, tree expr)
+{
+  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_VINDEX (expr) = lto_input_tree (ib, data_in);
+}
+
+
+/* Read all pointer fields in the TS_DECL_WITH_VIS structure of EXPR
+   from input block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+static void
+lto_input_ts_decl_with_vis_tree_pointers (struct lto_input_block *ib,
+				          struct data_in *data_in, tree expr)
+{
+  tree id;
+
+  id = lto_input_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);
+}
+
+
+/* Read all pointer fields in the TS_FIELD_DECL structure of EXPR from
+   input block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+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);
+  TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
+}
+
+
+/* Read all pointer fields in the TS_FUNCTION_DECL structure of EXPR
+   from input block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+static void
+lto_input_ts_function_decl_tree_pointers (struct lto_input_block *ib,
+					  struct data_in *data_in, tree expr)
+{
+  /* 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);
+
+  /* If the file contains a function with an EH personality set,
+     then it was compiled with -fexceptions.  In that case, initialize
+     the backend EH machinery.  */
+  if (DECL_FUNCTION_PERSONALITY (expr))
+    lto_init_eh ();
+}
+
+
+/* Read all pointer fields in the TS_TYPE_COMMON structure of EXPR from
+   input block IB.  DATA_IN contains tables and descriptors for the file
+   being read.  */
+
+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);
+  /* 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_CANONICAL gets re-computed during type merging.  */
+  TYPE_CANONICAL (expr) = NULL_TREE;
+  TYPE_STUB_DECL (expr) = lto_input_tree (ib, data_in);
+}
+
+/* Read all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
+   from input block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+static void
+lto_input_ts_type_non_common_tree_pointers (struct lto_input_block *ib,
+					    struct data_in *data_in,
+					    tree expr)
+{
+  if (TREE_CODE (expr) == ENUMERAL_TYPE)
+    TYPE_VALUES (expr) = lto_input_tree (ib, data_in);
+  else if (TREE_CODE (expr) == ARRAY_TYPE)
+    TYPE_DOMAIN (expr) = lto_input_tree (ib, data_in);
+  else if (RECORD_OR_UNION_TYPE_P (expr))
+    TYPE_FIELDS (expr) = lto_input_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);
+
+  if (!POINTER_TYPE_P (expr))
+    TYPE_MINVAL (expr) = lto_input_tree (ib, data_in);
+  TYPE_MAXVAL (expr) = lto_input_tree (ib, data_in);
+  if (RECORD_OR_UNION_TYPE_P (expr))
+    TYPE_BINFO (expr) = lto_input_tree (ib, data_in);
+}
+
+
+/* Read all pointer fields in the TS_LIST structure of EXPR from input
+   block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+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_CHAIN (expr) = lto_input_chain (ib, data_in);
+}
+
+
+/* Read all pointer fields in the TS_VEC structure of EXPR from input
+   block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+static void
+lto_input_ts_vec_tree_pointers (struct lto_input_block *ib,
+				struct data_in *data_in, tree expr)
+{
+  int i;
+
+  /* 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);
+}
+
+
+/* Read all pointer fields in the TS_EXP structure of EXPR from input
+   block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+
+static void
+lto_input_ts_exp_tree_pointers (struct lto_input_block *ib,
+			        struct data_in *data_in, tree expr)
+{
+  int i, length;
+  location_t loc;
+
+  length = lto_input_sleb128 (ib);
+  gcc_assert (length == TREE_OPERAND_LENGTH (expr));
+
+  for (i = 0; i < length; i++)
+    TREE_OPERAND (expr, i) = lto_input_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);
+}
+
+
+/* Read all pointer fields in the TS_BLOCK structure of EXPR from input
+   block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+static void
+lto_input_ts_block_tree_pointers (struct lto_input_block *ib,
+				  struct data_in *data_in, tree expr)
+{
+  /* Do not stream BLOCK_SOURCE_LOCATION.  We cannot handle debug information
+     for early inlining so drop it on the floor instead of ICEing in
+     dwarf2out.c.  */
+  BLOCK_VARS (expr) = lto_input_chain (ib, data_in);
+
+  /* Do not stream BLOCK_NONLOCALIZED_VARS.  We cannot handle debug information
+     for early inlining so drop it on the floor instead of ICEing in
+     dwarf2out.c.  */
+
+  BLOCK_SUPERCONTEXT (expr) = lto_input_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);
+
+  /* We re-compute BLOCK_SUBBLOCKS of our parent here instead
+     of streaming it.  For non-BLOCK BLOCK_SUPERCONTEXTs we still
+     stream the child relationship explicitly.  */
+  if (BLOCK_SUPERCONTEXT (expr)
+      && TREE_CODE (BLOCK_SUPERCONTEXT (expr)) == BLOCK)
+    {
+      BLOCK_CHAIN (expr) = BLOCK_SUBBLOCKS (BLOCK_SUPERCONTEXT (expr));
+      BLOCK_SUBBLOCKS (BLOCK_SUPERCONTEXT (expr)) = expr;
+    }
+
+  /* The global block is rooted at the TU decl.  Hook it here to
+     avoid the need to stream in this block during WPA time.  */
+  else if (BLOCK_SUPERCONTEXT (expr)
+	   && TREE_CODE (BLOCK_SUPERCONTEXT (expr)) == TRANSLATION_UNIT_DECL)
+    DECL_INITIAL (BLOCK_SUPERCONTEXT (expr)) = expr;
+
+  /* The function-level block is connected at the time we read in
+     function bodies for the same reason.  */
+}
+
+
+/* Read all pointer fields in the TS_BINFO structure of EXPR from input
+   block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+static void
+lto_input_ts_binfo_tree_pointers (struct lto_input_block *ib,
+				  struct data_in *data_in, tree expr)
+{
+  unsigned i, len;
+  tree t;
+
+  /* Note that the number of slots in EXPR was read in
+     lto_materialize_tree when instantiating EXPR.  However, the
+     vector is empty so we cannot rely on VEC_length to know how many
+     elements to read.  So, this list is emitted as a 0-terminated
+     list on the writer side.  */
+  do
+    {
+      t = lto_input_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);
+
+  len = lto_input_uleb128 (ib);
+  if (len > 0)
+    {
+      VEC_reserve_exact (tree, gc, BINFO_BASE_ACCESSES (expr), len);
+      for (i = 0; i < len; i++)
+	{
+	  tree a = lto_input_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);
+}
+
+
+/* Read all pointer fields in the TS_CONSTRUCTOR structure of EXPR from
+   input block IB.  DATA_IN contains tables and descriptors for the
+   file being read.  */
+
+static void
+lto_input_ts_constructor_tree_pointers (struct lto_input_block *ib,
+				        struct data_in *data_in, tree expr)
+{
+  unsigned i, len;
+
+  len = lto_input_uleb128 (ib);
+  for (i = 0; i < len; i++)
+    {
+      tree index, value;
+
+      index = lto_input_tree (ib, data_in);
+      value = lto_input_tree (ib, data_in);
+      CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (expr), index, value);
+    }
+}
+
+
+/* Input a TS_TARGET_OPTION tree from IB into EXPR.  */
+
+static void
+lto_input_ts_target_option (struct lto_input_block *ib, tree expr)
+{
+  unsigned i, len;
+  struct bitpack_d bp;
+  struct cl_target_option *t = TREE_TARGET_OPTION (expr);
+
+  bp = lto_input_bitpack (ib);
+  len = sizeof (struct cl_target_option);
+  for (i = 0; i < len; i++)
+    ((unsigned char *)t)[i] = bp_unpack_value (&bp, 8);
+  if (bp_unpack_value (&bp, 32) != 0x12345678)
+    fatal_error ("cl_target_option size mismatch in LTO reader and writer");
+}
+
+/* Input a TS_TRANSLATION_UNIT_DECL tree from IB and DATA_IN into EXPR.  */
+
+static void
+lto_input_ts_translation_unit_decl_tree_pointers (struct lto_input_block *ib,
+						  struct data_in *data_in,
+						  tree expr)
+{
+  TRANSLATION_UNIT_LANGUAGE (expr) = xstrdup (lto_input_string (data_in, 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.  */
+
+static void
+lto_input_tree_pointers (struct lto_input_block *ib, struct data_in *data_in,
+			 tree expr)
+{
+  enum tree_code code;
+
+  code = TREE_CODE (expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
+    lto_input_ts_common_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_VECTOR))
+    lto_input_ts_vector_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX))
+    lto_input_ts_complex_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL))
+    lto_input_ts_decl_minimal_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
+    lto_input_ts_decl_common_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
+    lto_input_ts_decl_non_common_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
+    lto_input_ts_decl_with_vis_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL))
+    lto_input_ts_field_decl_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
+    lto_input_ts_function_decl_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
+    lto_input_ts_type_common_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON))
+    lto_input_ts_type_non_common_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_LIST))
+    lto_input_ts_list_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_VEC))
+    lto_input_ts_vec_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_EXP))
+    lto_input_ts_exp_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
+    lto_input_ts_block_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
+    lto_input_ts_binfo_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
+    lto_input_ts_constructor_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
+    lto_input_ts_target_option (ib, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
+    lto_input_ts_translation_unit_decl_tree_pointers (ib, data_in, expr);
+}
+
+
+/* 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
+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);
+  overflow_p = (lto_input_1_unsigned (ib) != 0);
+  low = lto_input_uleb128 (ib);
+  high = lto_input_uleb128 (ib);
+  result = build_int_cst_wide (type, low, high);
+
+  /* If the original constant had overflown, build a replica of RESULT to
+     avoid modifying the shared constant returned by build_int_cst_wide.  */
+  if (overflow_p)
+    {
+      result = copy_node (result);
+      TREE_OVERFLOW (result) = 1;
+    }
+
+  return result;
+}
+
+
+/* Read an index IX from input block IB and return the tree node at
+   DATA_IN->FILE_DATA->GLOBALS_INDEX[IX].  */
+
+static tree
+lto_get_pickled_tree (struct lto_input_block *ib, struct data_in *data_in)
+{
+  unsigned HOST_WIDE_INT ix;
+  tree result;
+  enum LTO_tags expected_tag;
+
+  ix = lto_input_uleb128 (ib);
+  expected_tag = lto_input_enum (ib, LTO_tags, LTO_NUM_TAGS);
+
+  result = lto_streamer_cache_get (data_in->reader_cache, ix);
+  gcc_assert (result
+              && TREE_CODE (result) == lto_tag_to_tree_code (expected_tag));
+
+  return result;
+}
+
+
+/* Read a code and class from input block IB and return the
+   corresponding builtin.  DATA_IN is as in lto_input_tree.  */
+
+static tree
+lto_get_builtin_tree (struct lto_input_block *ib, struct data_in *data_in)
+{
+  enum built_in_class fclass;
+  enum built_in_function fcode;
+  const char *asmname;
+  tree result;
+
+  fclass = lto_input_enum (ib, built_in_class, BUILT_IN_LAST);
+  gcc_assert (fclass == BUILT_IN_NORMAL || fclass == BUILT_IN_MD);
+
+  fcode = (enum built_in_function) lto_input_uleb128 (ib);
+
+  if (fclass == BUILT_IN_NORMAL)
+    {
+      if (fcode >= END_BUILTINS)
+	fatal_error ("machine independent builtin code out of range");
+      result = built_in_decls[fcode];
+      gcc_assert (result);
+    }
+  else if (fclass == BUILT_IN_MD)
+    {
+      result = targetm.builtin_decl (fcode, true);
+      if (!result || result == error_mark_node)
+	fatal_error ("target specific builtin not available");
+    }
+  else
+    gcc_unreachable ();
+
+  asmname = lto_input_string (data_in, ib);
+  if (asmname)
+    set_builtin_user_assembler_name (result, asmname);
+
+  lto_streamer_cache_append (data_in->reader_cache, result);
+
+  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
new file mode 100644
index 0000000..ace8430
--- /dev/null
+++ b/gcc/tree-streamer-out.c
@@ -0,0 +1,1045 @@
+/* Routines for emitting trees to a file stream.
+
+   Copyright 2011 Free Software Foundation, Inc.
+   Contributed by Diego Novillo <dnovillo@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostic.h"
+#include "tree.h"
+#include "tree-streamer.h"
+#include "data-streamer.h"
+#include "streamer-hooks.h"
+
+/* Output the STRING constant to the string
+   table in OB.  Then put the index onto the INDEX_STREAM.  */
+
+static void
+output_string_cst (struct output_block *ob,
+		   struct lto_output_stream *index_stream,
+		   tree string)
+{
+  lto_output_string_with_length (ob, index_stream,
+				 TREE_STRING_POINTER (string),
+				 TREE_STRING_LENGTH (string),
+				 true);
+}
+
+
+/* Output the identifier ID to the string
+   table in OB.  Then put the index onto the INDEX_STREAM.  */
+
+static void
+output_identifier (struct output_block *ob,
+		   struct lto_output_stream *index_stream,
+		   tree id)
+{
+  lto_output_string_with_length (ob, index_stream,
+				 IDENTIFIER_POINTER (id),
+				 IDENTIFIER_LENGTH (id),
+				 true);
+}
+
+
+/* Pack all the non-pointer fields of the TS_BASE structure of
+   expression EXPR into bitpack BP.  */
+
+static void
+pack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
+{
+  bp_pack_value (bp, TREE_CODE (expr), 16);
+  if (!TYPE_P (expr))
+    {
+      bp_pack_value (bp, TREE_SIDE_EFFECTS (expr), 1);
+      bp_pack_value (bp, TREE_CONSTANT (expr), 1);
+      bp_pack_value (bp, TREE_READONLY (expr), 1);
+
+      /* TREE_PUBLIC is used on types to indicate that the type
+	 has a TYPE_CACHED_VALUES vector.  This is not streamed out,
+	 so we skip it here.  */
+      bp_pack_value (bp, TREE_PUBLIC (expr), 1);
+    }
+  else
+    bp_pack_value (bp, 0, 4);
+  bp_pack_value (bp, TREE_ADDRESSABLE (expr), 1);
+  bp_pack_value (bp, TREE_THIS_VOLATILE (expr), 1);
+  if (DECL_P (expr))
+    bp_pack_value (bp, DECL_UNSIGNED (expr), 1);
+  else if (TYPE_P (expr))
+    bp_pack_value (bp, TYPE_UNSIGNED (expr), 1);
+  else
+    bp_pack_value (bp, 0, 1);
+  /* We write debug info two times, do not confuse the second one.  */
+  bp_pack_value (bp, TYPE_P (expr) ? 0 : TREE_ASM_WRITTEN (expr), 1);
+  if (TYPE_P (expr))
+    bp_pack_value (bp, TYPE_ARTIFICIAL (expr), 1);
+  else
+    bp_pack_value (bp, TREE_NO_WARNING (expr), 1);
+  bp_pack_value (bp, TREE_USED (expr), 1);
+  bp_pack_value (bp, TREE_NOTHROW (expr), 1);
+  bp_pack_value (bp, TREE_STATIC (expr), 1);
+  bp_pack_value (bp, TREE_PRIVATE (expr), 1);
+  bp_pack_value (bp, TREE_PROTECTED (expr), 1);
+  bp_pack_value (bp, TREE_DEPRECATED (expr), 1);
+  if (TYPE_P (expr))
+    bp_pack_value (bp, TYPE_SATURATING (expr), 1);
+  else if (TREE_CODE (expr) == SSA_NAME)
+    bp_pack_value (bp, SSA_NAME_IS_DEFAULT_DEF (expr), 1);
+  else
+    bp_pack_value (bp, 0, 1);
+}
+
+
+/* Pack all the non-pointer fields of the TS_REAL_CST structure of
+   expression EXPR into bitpack BP.  */
+
+static void
+pack_ts_real_cst_value_fields (struct bitpack_d *bp, tree expr)
+{
+  unsigned i;
+  REAL_VALUE_TYPE r;
+
+  r = TREE_REAL_CST (expr);
+  bp_pack_value (bp, r.cl, 2);
+  bp_pack_value (bp, r.decimal, 1);
+  bp_pack_value (bp, r.sign, 1);
+  bp_pack_value (bp, r.signalling, 1);
+  bp_pack_value (bp, r.canonical, 1);
+  bp_pack_value (bp, r.uexp, EXP_BITS);
+  for (i = 0; i < SIGSZ; i++)
+    bp_pack_value (bp, r.sig[i], HOST_BITS_PER_LONG);
+}
+
+
+/* Pack all the non-pointer fields of the TS_FIXED_CST structure of
+   expression EXPR into bitpack BP.  */
+
+static void
+pack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
+{
+  struct fixed_value fv = TREE_FIXED_CST (expr);
+  bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, fv.mode);
+  bp_pack_var_len_int (bp, fv.data.low);
+  bp_pack_var_len_int (bp, fv.data.high);
+}
+
+
+/* Pack all the non-pointer fields of the TS_DECL_COMMON structure
+   of expression EXPR into bitpack BP.  */
+
+static void
+pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
+{
+  bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, DECL_MODE (expr));
+  bp_pack_value (bp, DECL_NONLOCAL (expr), 1);
+  bp_pack_value (bp, DECL_VIRTUAL_P (expr), 1);
+  bp_pack_value (bp, DECL_IGNORED_P (expr), 1);
+  bp_pack_value (bp, DECL_ABSTRACT (expr), 1);
+  bp_pack_value (bp, DECL_ARTIFICIAL (expr), 1);
+  bp_pack_value (bp, DECL_USER_ALIGN (expr), 1);
+  bp_pack_value (bp, DECL_PRESERVE_P (expr), 1);
+  bp_pack_value (bp, DECL_DEBUG_EXPR_IS_FROM (expr), 1);
+  bp_pack_value (bp, DECL_EXTERNAL (expr), 1);
+  bp_pack_value (bp, DECL_GIMPLE_REG_P (expr), 1);
+  bp_pack_var_len_unsigned (bp, DECL_ALIGN (expr));
+
+  if (TREE_CODE (expr) == LABEL_DECL)
+    {
+      /* Note that we do not write LABEL_DECL_UID.  The reader will
+	 always assume an initial value of -1 so that the
+	 label_to_block_map is recreated by gimple_set_bb.  */
+      bp_pack_value (bp, DECL_ERROR_ISSUED (expr), 1);
+      bp_pack_var_len_unsigned (bp, EH_LANDING_PAD_NR (expr));
+    }
+
+  if (TREE_CODE (expr) == FIELD_DECL)
+    {
+      bp_pack_value (bp, DECL_PACKED (expr), 1);
+      bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
+      bp_pack_value (bp, expr->decl_common.off_align, 8);
+    }
+
+  if (TREE_CODE (expr) == RESULT_DECL
+      || TREE_CODE (expr) == PARM_DECL
+      || TREE_CODE (expr) == VAR_DECL)
+    {
+      bp_pack_value (bp, DECL_BY_REFERENCE (expr), 1);
+      if (TREE_CODE (expr) == VAR_DECL
+	  || TREE_CODE (expr) == PARM_DECL)
+	bp_pack_value (bp, DECL_HAS_VALUE_EXPR_P (expr), 1);
+      bp_pack_value (bp, DECL_RESTRICTED_P (expr), 1);
+    }
+}
+
+
+/* Pack all the non-pointer fields of the TS_DECL_WRTL structure
+   of expression EXPR into bitpack BP.  */
+
+static void
+pack_ts_decl_wrtl_value_fields (struct bitpack_d *bp, tree expr)
+{
+  bp_pack_value (bp, DECL_REGISTER (expr), 1);
+}
+
+
+/* Pack all the non-pointer fields of the TS_DECL_WITH_VIS structure
+   of expression EXPR into bitpack BP.  */
+
+static void
+pack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
+{
+  bp_pack_value (bp, DECL_DEFER_OUTPUT (expr), 1);
+  bp_pack_value (bp, DECL_COMMON (expr), 1);
+  bp_pack_value (bp, DECL_DLLIMPORT_P (expr), 1);
+  bp_pack_value (bp, DECL_WEAK (expr), 1);
+  bp_pack_value (bp, DECL_SEEN_IN_BIND_EXPR_P (expr),  1);
+  bp_pack_value (bp, DECL_COMDAT (expr),  1);
+  bp_pack_value (bp, DECL_VISIBILITY (expr),  2);
+  bp_pack_value (bp, DECL_VISIBILITY_SPECIFIED (expr),  1);
+
+  if (TREE_CODE (expr) == VAR_DECL)
+    {
+      bp_pack_value (bp, DECL_HARD_REGISTER (expr), 1);
+      bp_pack_value (bp, DECL_IN_TEXT_SECTION (expr), 1);
+      bp_pack_value (bp, DECL_IN_CONSTANT_POOL (expr), 1);
+      bp_pack_value (bp, DECL_TLS_MODEL (expr),  3);
+    }
+
+  if (VAR_OR_FUNCTION_DECL_P (expr))
+    bp_pack_var_len_unsigned (bp, DECL_INIT_PRIORITY (expr));
+}
+
+
+/* Pack all the non-pointer fields of the TS_FUNCTION_DECL structure
+   of expression EXPR into bitpack BP.  */
+
+static void
+pack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
+{
+  /* For normal/md builtins we only write the class and code, so they
+     should never be handled here.  */
+  gcc_assert (!lto_stream_as_builtin_p (expr));
+
+  bp_pack_enum (bp, built_in_class, BUILT_IN_LAST,
+		DECL_BUILT_IN_CLASS (expr));
+  bp_pack_value (bp, DECL_STATIC_CONSTRUCTOR (expr), 1);
+  bp_pack_value (bp, DECL_STATIC_DESTRUCTOR (expr), 1);
+  bp_pack_value (bp, DECL_UNINLINABLE (expr), 1);
+  bp_pack_value (bp, DECL_POSSIBLY_INLINED (expr), 1);
+  bp_pack_value (bp, DECL_IS_NOVOPS (expr), 1);
+  bp_pack_value (bp, DECL_IS_RETURNS_TWICE (expr), 1);
+  bp_pack_value (bp, DECL_IS_MALLOC (expr), 1);
+  bp_pack_value (bp, DECL_IS_OPERATOR_NEW (expr), 1);
+  bp_pack_value (bp, DECL_DECLARED_INLINE_P (expr), 1);
+  bp_pack_value (bp, DECL_STATIC_CHAIN (expr), 1);
+  bp_pack_value (bp, DECL_NO_INLINE_WARNING_P (expr), 1);
+  bp_pack_value (bp, DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr), 1);
+  bp_pack_value (bp, DECL_NO_LIMIT_STACK (expr), 1);
+  bp_pack_value (bp, DECL_DISREGARD_INLINE_LIMITS (expr), 1);
+  bp_pack_value (bp, DECL_PURE_P (expr), 1);
+  bp_pack_value (bp, DECL_LOOPING_CONST_OR_PURE_P (expr), 1);
+  if (DECL_BUILT_IN_CLASS (expr) != NOT_BUILT_IN)
+    bp_pack_value (bp, DECL_FUNCTION_CODE (expr), 11);
+  if (DECL_STATIC_DESTRUCTOR (expr))
+    bp_pack_var_len_unsigned (bp, DECL_FINI_PRIORITY (expr));
+}
+
+
+/* Pack all the non-pointer fields of the TS_TYPE_COMMON structure
+   of expression EXPR into bitpack BP.  */
+
+static void
+pack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
+{
+  bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, TYPE_MODE (expr));
+  bp_pack_value (bp, TYPE_STRING_FLAG (expr), 1);
+  bp_pack_value (bp, TYPE_NO_FORCE_BLK (expr), 1);
+  bp_pack_value (bp, TYPE_NEEDS_CONSTRUCTING (expr), 1);
+  if (RECORD_OR_UNION_TYPE_P (expr))
+    bp_pack_value (bp, TYPE_TRANSPARENT_AGGR (expr), 1);
+  bp_pack_value (bp, TYPE_PACKED (expr), 1);
+  bp_pack_value (bp, TYPE_RESTRICT (expr), 1);
+  bp_pack_value (bp, TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr), 2);
+  bp_pack_value (bp, TYPE_USER_ALIGN (expr), 1);
+  bp_pack_value (bp, TYPE_READONLY (expr), 1);
+  bp_pack_var_len_unsigned (bp, TYPE_PRECISION (expr));
+  bp_pack_var_len_unsigned (bp, TYPE_ALIGN (expr));
+  bp_pack_var_len_int (bp, TYPE_ALIAS_SET (expr) == 0 ? 0 : -1);
+}
+
+
+/* Pack all the non-pointer fields of the TS_BLOCK structure
+   of expression EXPR into bitpack BP.  */
+
+static void
+pack_ts_block_value_fields (struct bitpack_d *bp, tree expr)
+{
+  bp_pack_value (bp, BLOCK_ABSTRACT (expr), 1);
+  /* BLOCK_NUMBER is recomputed.  */
+}
+
+/* Pack all the non-pointer fields of the TS_TRANSLATION_UNIT_DECL structure
+   of expression EXPR into bitpack BP.  */
+
+static void
+pack_ts_translation_unit_decl_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED, tree expr ATTRIBUTE_UNUSED)
+{
+}
+
+/* Pack all the non-pointer fields in EXPR into a bit pack.  */
+
+static void
+pack_value_fields (struct bitpack_d *bp, tree expr)
+{
+  enum tree_code code;
+
+  code = TREE_CODE (expr);
+
+  /* Note that all these functions are highly sensitive to changes in
+     the types and sizes of each of the fields being packed.  */
+  pack_ts_base_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
+    pack_ts_real_cst_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_FIXED_CST))
+    pack_ts_fixed_cst_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
+    pack_ts_decl_common_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL))
+    pack_ts_decl_wrtl_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
+    pack_ts_decl_with_vis_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
+    pack_ts_function_decl_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
+    pack_ts_type_common_value_fields (bp, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
+    pack_ts_block_value_fields (bp, 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
+lto_output_builtin_tree (struct output_block *ob, tree expr)
+{
+  gcc_assert (lto_stream_as_builtin_p (expr));
+
+  if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD
+      && !targetm.builtin_decl)
+    sorry ("gimple bytecode streams do not support machine specific builtin "
+	   "functions on this target");
+
+  output_record_start (ob, LTO_builtin_decl);
+  lto_output_enum (ob->main_stream, built_in_class, BUILT_IN_LAST,
+		   DECL_BUILT_IN_CLASS (expr));
+  output_uleb128 (ob, DECL_FUNCTION_CODE (expr));
+
+  if (DECL_ASSEMBLER_NAME_SET_P (expr))
+    {
+      /* When the assembler name of a builtin gets a user name,
+	 the new name is always prefixed with '*' by
+	 set_builtin_user_assembler_name.  So, to prevent the
+	 reader side from adding a second '*', we omit it here.  */
+      const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (expr));
+      if (strlen (str) > 1 && str[0] == '*')
+	lto_output_string (ob, ob->main_stream, &str[1], true);
+      else
+	lto_output_string (ob, ob->main_stream, NULL, true);
+    }
+  else
+    lto_output_string (ob, ob->main_stream, NULL, true);
+}
+
+
+/* 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.  */
+
+static void
+lto_output_chain (struct output_block *ob, tree t, bool ref_p)
+{
+  int i, count;
+
+  count = list_length (t);
+  output_sleb128 (ob, count);
+  for (i = 0; i < count; i++)
+    {
+      tree saved_chain;
+
+      /* Clear TREE_CHAIN to avoid blindly recursing into the rest
+	 of the list.  */
+      saved_chain = TREE_CHAIN (t);
+      TREE_CHAIN (t) = NULL_TREE;
+
+      lto_output_tree_or_ref (ob, t, ref_p);
+
+      TREE_CHAIN (t) = saved_chain;
+      t = TREE_CHAIN (t);
+    }
+}
+
+
+/* Write all pointer fields in the TS_COMMON structure of EXPR to output
+   block OB.  If REF_P is true, write a reference to EXPR's pointer
+   fields.  */
+
+static void
+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);
+}
+
+
+/* Write all pointer fields in the TS_VECTOR structure of EXPR to output
+   block OB.  If REF_P is true, write a reference to EXPR's pointer
+   fields.  */
+
+static void
+lto_output_ts_vector_tree_pointers (struct output_block *ob, tree expr,
+				    bool ref_p)
+{
+  lto_output_chain (ob, TREE_VECTOR_CST_ELTS (expr), ref_p);
+}
+
+
+/* Write all pointer fields in the TS_COMPLEX structure of EXPR to output
+   block OB.  If REF_P is true, write a reference to EXPR's pointer
+   fields.  */
+
+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);
+}
+
+
+/* Write all pointer fields in the TS_DECL_MINIMAL structure of EXPR
+   to output block OB.  If REF_P is true, write a reference to EXPR's
+   pointer fields.  */
+
+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);
+  lto_output_location (ob, DECL_SOURCE_LOCATION (expr));
+}
+
+
+/* Write all pointer fields in the TS_DECL_COMMON structure of EXPR to
+   output block OB.  If REF_P is true, write a reference to EXPR's
+   pointer fields.  */
+
+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);
+
+  /* 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);
+
+  /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
+     for early inlining so drop it on the floor instead of ICEing in
+     dwarf2out.c.  */
+
+  if (TREE_CODE (expr) == PARM_DECL)
+    lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
+
+  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);
+
+  if (TREE_CODE (expr) == VAR_DECL)
+    lto_output_tree_or_ref (ob, DECL_DEBUG_EXPR (expr), ref_p);
+}
+
+
+/* Write all pointer fields in the TS_DECL_NON_COMMON structure of
+   EXPR to output block OB.  If REF_P is true, write a reference to EXPR's
+   pointer fields.  */
+
+static void
+lto_output_ts_decl_non_common_tree_pointers (struct output_block *ob,
+					     tree expr, bool ref_p)
+{
+  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);
+    }
+  lto_output_tree_or_ref (ob, DECL_VINDEX (expr), ref_p);
+}
+
+
+/* Write all pointer fields in the TS_DECL_WITH_VIS structure of EXPR
+   to output block OB.  If REF_P is true, write a reference to EXPR's
+   pointer fields.  */
+
+static void
+lto_output_ts_decl_with_vis_tree_pointers (struct output_block *ob, tree expr,
+					   bool ref_p)
+{
+  /* 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);
+  else
+    output_record_start (ob, LTO_null);
+
+  lto_output_tree_or_ref (ob, DECL_SECTION_NAME (expr), ref_p);
+  lto_output_tree_or_ref (ob, DECL_COMDAT_GROUP (expr), ref_p);
+}
+
+
+/* Write all pointer fields in the TS_FIELD_DECL structure of EXPR to
+   output block OB.  If REF_P is true, write a reference to EXPR's
+   pointer fields.  */
+
+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);
+  lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
+}
+
+
+/* Write all pointer fields in the TS_FUNCTION_DECL structure of EXPR
+   to output block OB.  If REF_P is true, write a reference to EXPR's
+   pointer fields.  */
+
+static void
+lto_output_ts_function_decl_tree_pointers (struct output_block *ob, tree expr,
+					   bool ref_p)
+{
+  /* DECL_STRUCT_FUNCTION is handled by lto_output_function.  FIXME lto,
+     maybe it should be handled here?  */
+  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);
+}
+
+
+/* Write all pointer fields in the TS_TYPE_COMMON structure of EXPR to
+   output block OB.  If REF_P is true, write a reference to EXPR's
+   pointer fields.  */
+
+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);
+  /* 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);
+  /* 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);
+}
+
+/* Write all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
+   to output block OB.  If REF_P is true, write a reference to EXPR's
+   pointer fields.  */
+
+static void
+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);
+  else if (TREE_CODE (expr) == ARRAY_TYPE)
+    lto_output_tree_or_ref (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);
+  else if (TREE_CODE (expr) == FUNCTION_TYPE
+	   || TREE_CODE (expr) == METHOD_TYPE)
+    lto_output_tree_or_ref (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);
+  if (RECORD_OR_UNION_TYPE_P (expr))
+    lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p);
+}
+
+
+/* Write all pointer fields in the TS_LIST structure of EXPR to output
+   block OB.  If REF_P is true, write a reference to EXPR's pointer
+   fields.  */
+
+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);
+  lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
+}
+
+
+/* Write all pointer fields in the TS_VEC structure of EXPR to output
+   block OB.  If REF_P is true, write a reference to EXPR's pointer
+   fields.  */
+
+static void
+lto_output_ts_vec_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
+{
+  int i;
+
+  /* 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);
+}
+
+
+/* Write all pointer fields in the TS_EXP structure of EXPR to output
+   block OB.  If REF_P is true, write a reference to EXPR's pointer
+   fields.  */
+
+static void
+lto_output_ts_exp_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
+{
+  int i;
+
+  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);
+  lto_output_location (ob, EXPR_LOCATION (expr));
+  lto_output_tree_or_ref (ob, TREE_BLOCK (expr), ref_p);
+}
+
+
+/* Write all pointer fields in the TS_BLOCK structure of EXPR to output
+   block OB.  If REF_P is true, write a reference to EXPR's pointer
+   fields.  */
+
+static void
+lto_output_ts_block_tree_pointers (struct output_block *ob, tree expr,
+				   bool ref_p)
+{
+  /* Do not stream BLOCK_SOURCE_LOCATION.  We cannot handle debug information
+     for early inlining so drop it on the floor instead of ICEing in
+     dwarf2out.c.  */
+  lto_output_chain (ob, BLOCK_VARS (expr), ref_p);
+
+  /* Do not stream BLOCK_NONLOCALIZED_VARS.  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_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);
+  /* Do not output BLOCK_SUBBLOCKS.  Instead on streaming-in this
+     list is re-constructed from BLOCK_SUPERCONTEXT.  */
+}
+
+
+/* Write all pointer fields in the TS_BINFO structure of EXPR to output
+   block OB.  If REF_P is true, write a reference to EXPR's pointer
+   fields.  */
+
+static void
+lto_output_ts_binfo_tree_pointers (struct output_block *ob, tree expr,
+				   bool ref_p)
+{
+  unsigned i;
+  tree t;
+
+  /* Note that the number of BINFO slots has already been emitted in
+     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);
+
+  lto_output_tree_or_ref (ob, BINFO_OFFSET (expr), ref_p);
+  lto_output_tree_or_ref (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);
+
+  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);
+
+  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);
+}
+
+
+/* Write all pointer fields in the TS_CONSTRUCTOR structure of EXPR to
+   output block OB.  If REF_P is true, write a reference to EXPR's
+   pointer fields.  */
+
+static void
+lto_output_ts_constructor_tree_pointers (struct output_block *ob, tree expr,
+					 bool ref_p)
+{
+  unsigned i;
+  tree index, value;
+
+  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);
+    }
+}
+
+/* Write a TS_TARGET_OPTION tree in EXPR to OB.  */
+
+static void
+lto_output_ts_target_option (struct output_block *ob, tree expr)
+{
+  struct cl_target_option *t = TREE_TARGET_OPTION (expr);
+  struct bitpack_d bp;
+  unsigned i, len;
+
+  /* The cl_target_option is target specific and generated by the options
+     awk script, so we just recreate a byte-by-byte copy here. */
+
+  bp = bitpack_create (ob->main_stream);
+  len = sizeof (struct cl_target_option);
+  for (i = 0; i < len; i++)
+    bp_pack_value (&bp, ((unsigned char *)t)[i], 8);
+  /* Catch struct size mismatches between reader and writer. */
+  bp_pack_value (&bp, 0x12345678, 32);
+  lto_output_bitpack (&bp);
+}
+
+/* Write a TS_TRANSLATION_UNIT_DECL tree in EXPR to OB.  */
+
+static void
+lto_output_ts_translation_unit_decl_tree_pointers (struct output_block *ob,
+						   tree expr)
+{
+  lto_output_string (ob, ob->main_stream,
+		     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.  */
+
+static void
+lto_output_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
+{
+  enum tree_code code;
+
+  code = TREE_CODE (expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
+    lto_output_ts_common_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_VECTOR))
+    lto_output_ts_vector_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX))
+    lto_output_ts_complex_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL))
+    lto_output_ts_decl_minimal_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
+    lto_output_ts_decl_common_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
+    lto_output_ts_decl_non_common_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
+    lto_output_ts_decl_with_vis_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL))
+    lto_output_ts_field_decl_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
+    lto_output_ts_function_decl_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
+    lto_output_ts_type_common_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON))
+    lto_output_ts_type_non_common_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_LIST))
+    lto_output_ts_list_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_VEC))
+    lto_output_ts_vec_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_EXP))
+    lto_output_ts_exp_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
+    lto_output_ts_block_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
+    lto_output_ts_binfo_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
+    lto_output_ts_constructor_tree_pointers (ob, expr, ref_p);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
+    lto_output_ts_target_option (ob, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
+    lto_output_ts_translation_unit_decl_tree_pointers (ob, expr);
+}
+
+
+/* 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.  */
+
+static void
+lto_output_tree_header (struct output_block *ob, tree expr)
+{
+  enum LTO_tags tag;
+  enum tree_code code;
+
+  /* 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
+     EXPR on the reading side (such as the number of slots in
+     variable sized nodes).  */
+  tag = lto_tree_code_to_tag (code);
+  output_record_start (ob, tag);
+
+  /* The following will cause bootstrap miscomparisons.  Enable with care.  */
+#ifdef LTO_STREAMER_DEBUG
+  /* This is used mainly for debugging purposes.  When the reader
+     and the writer do not agree on a streamed node, the pointer
+     value for EXPR can be used to track down the differences in
+     the debugger.  */
+  gcc_assert ((HOST_WIDEST_INT) (intptr_t) expr == (intptr_t) expr);
+  output_sleb128 (ob, (HOST_WIDEST_INT) (intptr_t) expr);
+#endif
+
+  /* The text in strings and identifiers are completely emitted in
+     the header.  */
+  if (CODE_CONTAINS_STRUCT (code, TS_STRING))
+    output_string_cst (ob, ob->main_stream, expr);
+  else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER))
+    output_identifier (ob, ob->main_stream, expr);
+  else if (CODE_CONTAINS_STRUCT (code, TS_VEC))
+    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);
+}
+
+
+/* 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
+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);
+  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)
+    {
+      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
new file mode 100644
index 0000000..d5fe93a
--- /dev/null
+++ b/gcc/tree-streamer.c
@@ -0,0 +1,279 @@
+/* Miscellaneous utilities for tree streaming.  Things that are used
+   in both input and output are here.
+
+   Copyright 2011 Free Software Foundation, Inc.
+   Contributed by Diego Novillo <dnovillo@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "streamer-hooks.h"
+#include "tree-streamer.h"
+
+/* Check that all the TS_* structures handled by the lto_output_* and
+   lto_input_* routines are exactly ALL the structures defined in
+   treestruct.def.  */
+
+void
+check_handled_ts_structures (void)
+{
+  bool handled_p[LAST_TS_ENUM];
+  unsigned i;
+
+  memset (&handled_p, 0, sizeof (handled_p));
+
+  /* These are the TS_* structures that are either handled or
+     explicitly ignored by the streamer routines.  */
+  handled_p[TS_BASE] = true;
+  handled_p[TS_TYPED] = true;
+  handled_p[TS_COMMON] = true;
+  handled_p[TS_INT_CST] = true;
+  handled_p[TS_REAL_CST] = true;
+  handled_p[TS_FIXED_CST] = true;
+  handled_p[TS_VECTOR] = true;
+  handled_p[TS_STRING] = true;
+  handled_p[TS_COMPLEX] = true;
+  handled_p[TS_IDENTIFIER] = true;
+  handled_p[TS_DECL_MINIMAL] = true;
+  handled_p[TS_DECL_COMMON] = true;
+  handled_p[TS_DECL_WRTL] = true;
+  handled_p[TS_DECL_NON_COMMON] = true;
+  handled_p[TS_DECL_WITH_VIS] = true;
+  handled_p[TS_FIELD_DECL] = true;
+  handled_p[TS_VAR_DECL] = true;
+  handled_p[TS_PARM_DECL] = true;
+  handled_p[TS_LABEL_DECL] = true;
+  handled_p[TS_RESULT_DECL] = true;
+  handled_p[TS_CONST_DECL] = true;
+  handled_p[TS_TYPE_DECL] = true;
+  handled_p[TS_FUNCTION_DECL] = true;
+  handled_p[TS_TYPE_COMMON] = true;
+  handled_p[TS_TYPE_WITH_LANG_SPECIFIC] = true;
+  handled_p[TS_TYPE_NON_COMMON] = true;
+  handled_p[TS_LIST] = true;
+  handled_p[TS_VEC] = true;
+  handled_p[TS_EXP] = true;
+  handled_p[TS_SSA_NAME] = true;
+  handled_p[TS_BLOCK] = true;
+  handled_p[TS_BINFO] = true;
+  handled_p[TS_STATEMENT_LIST] = true;
+  handled_p[TS_CONSTRUCTOR] = true;
+  handled_p[TS_OMP_CLAUSE] = true;
+  handled_p[TS_OPTIMIZATION] = true;
+  handled_p[TS_TARGET_OPTION] = true;
+  handled_p[TS_TRANSLATION_UNIT_DECL] = true;
+
+  /* Anything not marked above will trigger the following assertion.
+     If this assertion triggers, it means that there is a new TS_*
+     structure that should be handled by the streamer.  */
+  for (i = 0; i < LAST_TS_ENUM; i++)
+    gcc_assert (handled_p[i]);
+}
+
+
+/* Helper for lto_streamer_cache_insert_1.  Add T to CACHE->NODES at
+   slot IX.  */
+
+static void
+lto_streamer_cache_add_to_node_array (struct lto_streamer_cache_d *cache,
+				      unsigned ix, tree t)
+{
+  /* Make sure we're either replacing an old element or
+     appending consecutively.  */
+  gcc_assert (ix <= VEC_length (tree, cache->nodes));
+
+  if (ix == VEC_length (tree, cache->nodes))
+    VEC_safe_push (tree, heap, cache->nodes, t);
+  else
+    VEC_replace (tree, cache->nodes, ix, t);
+}
+
+
+/* Helper for lto_streamer_cache_insert and lto_streamer_cache_insert_at.
+   CACHE, T, and IX_P are as in lto_streamer_cache_insert.
+
+   If INSERT_AT_NEXT_SLOT_P is true, T is inserted at the next available
+   slot in the cache.  Otherwise, T is inserted at the position indicated
+   in *IX_P.
+
+   If T already existed in CACHE, return true.  Otherwise,
+   return false.  */
+
+static bool
+lto_streamer_cache_insert_1 (struct lto_streamer_cache_d *cache,
+			     tree t, unsigned *ix_p,
+			     bool insert_at_next_slot_p)
+{
+  void **slot;
+  unsigned ix;
+  bool existed_p;
+
+  gcc_assert (t);
+
+  slot = pointer_map_insert (cache->node_map, t);
+  if (!*slot)
+    {
+      /* Determine the next slot to use in the cache.  */
+      if (insert_at_next_slot_p)
+	ix = VEC_length (tree, cache->nodes);
+      else
+	ix = *ix_p;
+       *slot = (void *)(size_t) (ix + 1);
+
+      lto_streamer_cache_add_to_node_array (cache, ix, t);
+
+      /* Indicate that the item was not present in the cache.  */
+      existed_p = false;
+    }
+  else
+    {
+      ix = (size_t) *slot - 1;
+
+      if (!insert_at_next_slot_p && ix != *ix_p)
+	{
+	  /* If the caller wants to insert T at a specific slot
+	     location, and ENTRY->TO does not match *IX_P, add T to
+	     the requested location slot.  */
+	  ix = *ix_p;
+	  lto_streamer_cache_add_to_node_array (cache, ix, t);
+	}
+
+      /* Indicate that T was already in the cache.  */
+      existed_p = true;
+    }
+
+  if (ix_p)
+    *ix_p = ix;
+
+  return existed_p;
+}
+
+
+/* Insert tree node T in CACHE.  If T already existed in the cache
+   return true.  Otherwise, return false.
+
+   If IX_P is non-null, update it with the index into the cache where
+   T has been stored.  */
+
+bool
+lto_streamer_cache_insert (struct lto_streamer_cache_d *cache, tree t,
+			   unsigned *ix_p)
+{
+  return lto_streamer_cache_insert_1 (cache, t, ix_p, true);
+}
+
+
+/* Insert tree node T in CACHE at slot IX.  If T already
+   existed in the cache return true.  Otherwise, return false.  */
+
+bool
+lto_streamer_cache_insert_at (struct lto_streamer_cache_d *cache,
+			      tree t, unsigned ix)
+{
+  return lto_streamer_cache_insert_1 (cache, t, &ix, false);
+}
+
+
+/* Appends tree node T to CACHE, even if T already existed in it.  */
+
+void
+lto_streamer_cache_append (struct lto_streamer_cache_d *cache, tree t)
+{
+  unsigned ix = VEC_length (tree, cache->nodes);
+  lto_streamer_cache_insert_1 (cache, t, &ix, false);
+}
+
+/* Return true if tree node T exists in CACHE, otherwise false.  If IX_P is
+   not NULL, write to *IX_P the index into the cache where T is stored
+   ((unsigned)-1 if T is not found).  */
+
+bool
+lto_streamer_cache_lookup (struct lto_streamer_cache_d *cache, tree t,
+			   unsigned *ix_p)
+{
+  void **slot;
+  bool retval;
+  unsigned ix;
+
+  gcc_assert (t);
+
+  slot = pointer_map_contains  (cache->node_map, t);
+  if (slot == NULL)
+    {
+      retval = false;
+      ix = -1;
+    }
+  else
+    {
+      retval = true;
+      ix = (size_t) *slot - 1;
+    }
+
+  if (ix_p)
+    *ix_p = ix;
+
+  return retval;
+}
+
+
+/* Return the tree node at slot IX in CACHE.  */
+
+tree
+lto_streamer_cache_get (struct lto_streamer_cache_d *cache, unsigned ix)
+{
+  gcc_assert (cache);
+
+  /* Make sure we're not requesting something we don't have.  */
+  gcc_assert (ix < VEC_length (tree, cache->nodes));
+
+  return VEC_index (tree, cache->nodes, ix);
+}
+
+/* Create a cache of pickled nodes.  */
+
+struct lto_streamer_cache_d *
+lto_streamer_cache_create (void)
+{
+  struct lto_streamer_cache_d *cache;
+
+  cache = XCNEW (struct lto_streamer_cache_d);
+
+  cache->node_map = pointer_map_create ();
+
+  /* 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);
+
+  return cache;
+}
+
+
+/* Delete the streamer cache C.  */
+
+void
+lto_streamer_cache_delete (struct lto_streamer_cache_d *c)
+{
+  if (c == NULL)
+    return;
+
+  pointer_map_destroy (c->node_map);
+  VEC_free (tree, heap, c->nodes);
+  free (c);
+}
diff --git a/gcc/tree-streamer.h b/gcc/tree-streamer.h
new file mode 100644
index 0000000..9d4740f
--- /dev/null
+++ b/gcc/tree-streamer.h
@@ -0,0 +1,76 @@
+/* Data structures and functions for streaming trees.
+
+   Copyright 2011 Free Software Foundation, Inc.
+   Contributed by Diego Novillo <dnovillo@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_TREE_STREAMER_H
+#define GCC_TREE_STREAMER_H
+
+#include "tree.h"
+#include "lto-streamer.h"
+
+/* Cache of pickled nodes.  Used to avoid writing the same node more
+   than once.  The first time a tree node is streamed out, it is
+   entered in this cache.  Subsequent references to the same node are
+   resolved by looking it up in this cache.
+
+   This is used in two ways:
+
+   - On the writing side, the first time T is added to STREAMER_CACHE,
+     a new reference index is created for T and T is emitted on the
+     stream.  If T needs to be emitted again to the stream, instead of
+     pickling it again, the reference index is emitted.
+
+   - On the reading side, the first time T is read from the stream, it
+     is reconstructed in memory and a new reference index created for
+     T.  The reconstructed T is inserted in some array so that when
+     the reference index for T is found in the input stream, it can be
+     used to look up into the array to get the reconstructed T.  */
+struct lto_streamer_cache_d
+{
+  /* The mapping between tree nodes and slots into the nodes array.  */
+  struct pointer_map_t *node_map;
+
+  /* The nodes pickled so far.  */
+  VEC(tree,heap) *nodes;
+};
+
+/* 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);
+
+/* In tree-streamer-out.c.  */
+void lto_streamer_write_tree (struct output_block *, tree, bool);
+
+/* In tree-streamer.c.  */
+void check_handled_ts_structures (void);
+bool lto_streamer_cache_insert (struct lto_streamer_cache_d *, tree,
+ 			        unsigned *);
+bool lto_streamer_cache_insert_at (struct lto_streamer_cache_d *, tree,
+ 				   unsigned);
+void lto_streamer_cache_append (struct lto_streamer_cache_d *, tree);
+bool lto_streamer_cache_lookup (struct lto_streamer_cache_d *, tree,
+ 			        unsigned *);
+tree lto_streamer_cache_get (struct lto_streamer_cache_d *, unsigned);
+struct lto_streamer_cache_d *lto_streamer_cache_create (void);
+void lto_streamer_cache_delete (struct lto_streamer_cache_d *);
+
+#endif  /* GCC_TREE_STREAMER_H  */

--
This patch is available for review at http://codereview.appspot.com/4809083

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [lto] Refactor streamer (1/N) (issue4809083)
  2011-08-08 14:37 [lto] Refactor streamer (1/N) (issue4809083) Diego Novillo
@ 2011-08-08 14:52 ` Jack Howarth
  2011-08-08 15:17   ` Diego Novillo
  2011-08-08 14:59 ` Michael Matz
  1 sibling, 1 reply; 11+ messages in thread
From: Jack Howarth @ 2011-08-08 14:52 UTC (permalink / raw)
  To: Diego Novillo; +Cc: reply, rguenther, jh, matz, gcc-patches

On Mon, Aug 08, 2011 at 10:23:34AM -0400, Diego Novillo wrote:
> 
> This is the first patch in a series of refactoring patches to cleanup
> the API for the LTO streamer.  I need this cleanup so I can change the
> way things like caching and external references work in PPH.  With the
> current code, I would need to introduce even more streamer hooks.  But
> if we simplify the API and create smaller low-level streaming
> functions, then we can have the LTO and PPH streamer use these
> functions without having to resort to a lot of callbacks.

Diego,
   While you are cleaning up the streamer can you also take a look at..

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49992

to see if these duplicate symbols also exist on linux in a non-fatal manner?
The change in r177358 broke the ability to do a lto-bootstrap on darwin.
While the lto-bootstrap appears to still work on linux (from the gcc-testresults
postings), it is unclear if any of these is using the lto-streamer instead
of the lto linker plugin. I think this should be fixed ASP since darwin is
probably one of the last targets to still use the lto-streamer instead of
the linker plugin.
            Jack

> 
> With these patches I'd like to:
> 
> 1 Create independent facilities to stream trees, gimple and other
>   data structures independently of LTO.  This first patch creates
>   the files data-streamer*.[ch], tree-streamer*.[ch] and
>   gimple-streamer*.[ch]. There are no other changes yet.  This simply
>   moves functions out of lto-streamer*[ch], but no functions or data
>   structures have been renamed.  This comes in a separate patch.
> 
> 2 Make the naming scheme consistent.  We use a mix of names to mean
>   the same thing (_out_, _output_, _write_, etc).  We have lto_
>   prefixes for functions that are actually generic.  And we still have
>   references to dwarf names (uleb, sleb, etc).
> 
> 3 Abstract the LTO data structures.  The buffering and
>   descriptor data structures used for LTO are somewhat confusing.  The
>   generic streaming routines should simply work on bytecode buffers
>   that are independent of LTO, PPH or other streamers we may want to
>   create in the future.
> 
> 4 Reduce the number of callbacks.  Ideally, I'd like to eliminate them
>   completely.  The API we need to use from PPH is more settled now, so
>   it should be easier to decide what needs a callback and what can be
>   exposed.
> 
> Richard, Michael, Jan, how does this plan sound?  Other cleanups or
> changes?  This patch implements #1.  There are no functional changes.
> The only minor change I made as to unify the string hashing structure
> and functions that we were using in two different files.
> 
> Bootstrapped with LTO profiledbootstrap on x86_64.  I will commit it
> in the next few days, unless there are objections.
> 
> 
> Diego.
> 
> 	* Makefile.in (LTO_STREAMER_H): Add DIAGNOSTIC_H.
> 	(DATA_STREAMER_H): New.
> 	(GIMPLE_STREAMER_H): New.
> 	(TREE_STREAMER_H): New.
> 	(STREAMER_HOOKS_H): New.
> 	(OBJS): Add data-streamer.o, data-streamer-in.o, data-streamer-out.o,
> 	gimple-streamer-in.o, gimple-streamer-out.o, streamer-hooks.o,
> 	tree-streamer.o, tree-streamer-in.o and tree-streamer-out.o.
> 	(data-streamer.o): New.
> 	(data-streamer-in.o): New.
> 	(data-streamer-out.o): New.
> 	(gimple-streamer-in.o): New.
> 	(gimple-streamer-out.o): New.
> 	(streamer-hooks.o): New.
> 	(tree-streamer.o): New.
> 	(tree-streamer-in.o): New.
> 	(tree-streamer-out.o): New.
> 	(lto-cgraph.o): Add dependency on DATA_STREAMER_H and
> 	TREE_STREAMER_H.
> 	(lto-streamer-in.o): Add dependency on DATA_STREAMER_H,
> 	GIMPLE_STREAMER_H and TREE_STREAMER_H.
> 	(lto-streamer-out.o): Add dependency on DATA_STREAMER_H,
> 	GIMPLE_STREAMER_H and TREE_STREAMER_H.
> 	(lto-streamer.o): Add dependency on STREAMER_HOOKS_H.
> 	(ipa-prop.o): Add dependency on DATA_STREAMER_H and
> 	TREE_STREAMER_H.
> 	(ipa-inline-analysis.o): Likewise.
> 	(ipa-pure-const.o): Likewise.
> 	* data-streamer-in.c: New.
> 	* data-streamer-out.c: New.
> 	* data-streamer.c: New.
> 	* data-streamer.h: New.
> 	* gimple-streamer-in.c: New.
> 	* gimple-streamer-out.c: New.
> 	* gimple-streamer.h: New.
> 	* ipa-inline-analysis.c: Include data-streamer.h.
> 	* ipa-prop.c: Include data-streamer.h.
> 	* ipa-pure-const.c: Include data-streamer.h.
> 	* lto-cgraph.c: Include data-streamer.h.
> 	* lto-section-in.c (lto_input_uleb128): Move to data-streamer-in.c.
> 	(lto_input_widest_uint_uleb128): Likewise.
> 	(lto_input_sleb128): Likewise.
> 	(bp_unpack_var_len_unsigned): Likewise.
> 	(bp_unpack_var_len_int): Likewise.
> 	* lto-section-out.c (lto_output_uleb128_stream): Move to
> 	data-streamer-out.c.
> 	(lto_output_widest_uint_uleb128_stream): Likewise.
> 	(lto_output_sleb128_stream): Likewise.
> 	(bp_pack_var_len_unsigned): Likewise.
> 	(bp_pack_var_len_int): Likewise.
> 	* lto-streamer-in.c: Include data-streamer.h and
> 	gimple-streamer.h.
> 	(struct string_slot): Remove.  Update all users.
> 	(lto_tag_check_set): Make extern.
> 	(lto_tag_check_range): Move to lto-streamer.h.
> 	(lto_tag_check): Likewise.
> 	(hash_string_slot_node): Remove.  Update all users.
> 	(eq_string_slot_node): Remove.  Update all users.
> 	(string_for_index): Move to data-streamer-in.c
> 	(input_string_internal): Likewise.
> 	(input_string_cst): Move to tree-streamer-in.c.
> 	(input_identifier): Likewise.
> 	(lto_input_string): Move to data-streamer-in.c
> 	(input_record_start): Move to data-streamer.h
> 	(canon_file_name): Use new definition of struct string_slot
> 	from data-streamer.h.
> 	Set S_SLOT.LEN.
> 	(lto_input_location): Make extern.
> 	(lto_input_chain): Move to tree-streamer-in.c.
> 	(lto_init_eh): Make extern.
> 	(input_phi): Move to gimple-streamer-in.c.
> 	(input_gimple_stmt): Likewise.
> 	(input_bb): Likewise.
> 	(unpack_ts_base_value_fields): Move to tree-streamer-in.c.
> 	(unpack_ts_real_cst_value_fields): Likewise.
> 	(unpack_ts_fixed_cst_value_fields): Likewise.
> 	(unpack_ts_decl_common_value_fields): Likewise.
> 	(unpack_ts_decl_wrtl_value_fields): Likewise.
> 	(unpack_ts_decl_with_vis_value_fields): Likewise.
> 	(unpack_ts_function_decl_value_fields): Likewise.
> 	(unpack_ts_type_common_value_fields): Likewise.
> 	(unpack_ts_block_value_fields): Likewise.
> 	(unpack_ts_translation_unit_decl_value_fields): Likewise.
> 	(unpack_value_fields): Likewise.
> 	(lto_materialize_tree): Likewise.
> 	(lto_input_ts_common_tree_pointers): Likewise.
> 	(lto_input_ts_vector_tree_pointers): Likewise.
> 	(lto_input_ts_complex_tree_pointers): Likewise.
> 	(lto_input_ts_decl_minimal_tree_pointers): Likewise.
> 	(lto_input_ts_decl_common_tree_pointers): Likewise.
> 	(lto_input_ts_decl_non_common_tree_pointers): Likewise.
> 	(lto_input_ts_decl_with_vis_tree_pointers): Likewise.
> 	(lto_input_ts_field_decl_tree_pointers): Likewise.
> 	(lto_input_ts_function_decl_tree_pointers): Likewise.
> 	(lto_input_ts_type_common_tree_pointers): Likewise.
> 	(lto_input_ts_type_non_common_tree_pointers): Likewise.
> 	(lto_input_ts_list_tree_pointers): Likewise.
> 	(lto_input_ts_vec_tree_pointers): Likewise.
> 	(lto_input_ts_exp_tree_pointers): Likewise.
> 	(lto_input_ts_block_tree_pointers): Likewise.
> 	(lto_input_ts_binfo_tree_pointers): Likewise.
> 	(lto_input_ts_constructor_tree_pointers): Likewise.
> 	(lto_input_ts_target_option): Likewise.
> 	(lto_input_ts_translation_unit_decl_tree_pointers): Likewise.
> 	(lto_input_tree_pointers): Likewise.
> 	(lto_get_pickled_tree): Likewise.
> 	(lto_get_builtin_tree): Likewise.
> 	(lto_read_tree): Likewise.
> 	(lto_input_integer_cst): Likewise.
> 	(lto_input_tree): Likewise.
> 	* lto-streamer-out.c: Include data-streamer.h,
> 	gimple-streamer.h and streamer-hooks.h.
> 	(struct string_slot): Move to data-streamer.h.
> 	(hash_string_slot_node): Likewise.
> 	(eq_string_slot_node): Likewise.
> 	(lto_string_index): Move to data-streamer-out.c.
> 	(lto_output_string_with_length): Likewise.
> 	(lto_output_string): Likewise.
> 	(output_string_cst): Move to tree-streamer-out.c.
> 	(output_identifier): Likewise.
> 	(output_zero): Move to data-streamer-out.c
> 	(output_uleb128): Likewise.
> 	(output_sleb128): Likewise.
> 	(output_record_start): Move to data-streamer.h
> 	(pack_ts_base_value_fields): Move to tree-streamer-out.c.
> 	(pack_ts_real_cst_value_fields): Likewise.
> 	(pack_ts_fixed_cst_value_fields): Likewise.
> 	(pack_ts_decl_common_value_fields): Likewise.
> 	(pack_ts_decl_wrtl_value_fields): Likewise.
> 	(pack_ts_decl_with_vis_value_fields): Likewise.
> 	(pack_ts_function_decl_value_fields): Likewise.
> 	(pack_ts_type_common_value_fields): Likewise.
> 	(pack_ts_block_value_fields): Likewise.
> 	(pack_ts_translation_unit_decl_value_fields): Likewise.
> 	(pack_value_fields): Likewise.
> 	(lto_output_chain): Likewise.
> 	(lto_output_ts_common_tree_pointers): Likewise.
> 	(lto_output_ts_vector_tree_pointers): Likewise.
> 	(lto_output_ts_complex_tree_pointers): Likewise.
> 	(lto_output_ts_decl_minimal_tree_pointers): Likewise.
> 	(lto_output_ts_decl_common_tree_pointers): Likewise.
> 	(lto_output_ts_decl_non_common_tree_pointers): Likewise.
> 	(lto_output_ts_decl_with_vis_tree_pointers): Likewise.
> 	(lto_output_ts_field_decl_tree_pointers): Likewise.
> 	(lto_output_ts_function_decl_tree_pointers): Likewise.
> 	(lto_output_ts_type_common_tree_pointers): Likewise.
> 	(lto_output_ts_type_non_common_tree_pointers): Likewise.
> 	(lto_output_ts_list_tree_pointers): Likewise.
> 	(lto_output_ts_vec_tree_pointers): Likewise.
> 	(lto_output_ts_exp_tree_pointers): Likewise.
> 	(lto_output_ts_block_tree_pointers): Likewise.
> 	(lto_output_ts_binfo_tree_pointers): Likewise.
> 	(lto_output_ts_constructor_tree_pointers): Likewise.
> 	(lto_output_ts_target_option): Likewise.
> 	(lto_output_ts_translation_unit_decl_tree_pointers): Likewise.
> 	(lto_output_tree_pointers): Likewise.
> 	(lto_output_tree_header): Likewise.
> 	(lto_output_builtin_tree): Likewise.
> 	(lto_write_tree): Likewise.
> 	(lto_output_integer_cst): Likewise.
> 	(lto_output_tree): Likewise.
> 	(output_phi): Move to gimple-streamer-out.c.
> 	(output_gimple_stmt): Likewise.
> 	(output_bb): Likewise.
> 	* lto-streamer.c: Include tree-streamer.h and streamer-hooks.h.
> 	(streamer_hooks): Move to streamer-hooks.c.
> 	(check_handled_ts_structures): Move to tree-streamer.c
> 	(lto_streamer_cache_add_to_node_array): Likewise.
> 	(lto_streamer_cache_insert_1): Likewise.
> 	(lto_streamer_cache_insert): Likewise.
> 	(lto_streamer_cache_insert_at): Likewise.
> 	(lto_streamer_cache_append): Likewise.
> 	(lto_streamer_cache_lookup): Likewise.
> 	(lto_streamer_cache_get): Likewise.
> 	(lto_record_common_node): Likewise.
> 	(lto_preload_common_nodes): Likewise.
> 	(lto_streamer_cache_create): Likewise.
> 	(lto_streamer_cache_delete): Likewise.
> 	(streamer_hooks_init): Move to streamer-hooks.c.
> 	* lto-streamer.h: Include diagnostic.h
> 	(struct output_block, struct lto_input_block,
> 	struct data_in, struct bitpack_d): Remove forward
> 	declarations.
> 	(struct bitpack_d): Move to data-streamer.h.
> 	(struct lto_streamer_cache_d): Move to tree-streamer.h.
> 	(struct streamer_hooks): Move to streamer-hooks.h.
> 	(bp_pack_var_len_unsigned): Move to data-streamer.h.
> 	(bp_pack_var_len_int): Likewise.
> 	(bp_unpack_var_len_unsigned): Likewise.
> 	(bp_unpack_var_len_int): Likewise.
> 	(lto_input_location): Declare.
> 	(lto_tag_check_set): Declare.
> 	(lto_init_eh): Declare.
> 	(lto_output_tree_ref): Declare.
> 	(lto_output_location): Declare.
> 	(bitpack_create): Move to data-streamer.h.
> 	(bp_pack_value): Likewise.
> 	(lto_output_bitpack): Likewise.
> 	(lto_input_bitpack): Likewise.
> 	(bp_unpack_value): Likewise.
> 	(lto_output_1_stream): Likewise.
> 	(lto_input_1_unsigned): Likewise.
> 	(lto_output_int_in_range): Likewise.
> 	(lto_input_int_in_range): Likewise.
> 	(bp_pack_int_in_range): Likewise.
> 	(bp_unpack_int_in_range): Likewise.
> 	(lto_output_enum): Likewise.
> 	(lto_input_enum): Likewise.
> 	(bp_pack_enum): Likewise.
> 	(bp_unpack_enum): Likewise.
> 	* streamer-hooks.c: New.
> 	* streamer-hooks.h: New.
> 	* tree-streamer-in.c: New.
> 	* tree-streamer-out.c: New.
> 	* tree-streamer.c: New.
> 	* tree-streamer.h: New.
> 
> lto/ChangeLog
> 
> 	* Make-lang.in (lto/lto.o): Add TREE_STREAMER_H.
> 	* lto.c: Include tree-streamer.h.
> 
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index ed96672..9fc4f05 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -992,7 +992,12 @@ DBGCNT_H = dbgcnt.h dbgcnt.def
>  EBITMAP_H = ebitmap.h sbitmap.h
>  LTO_STREAMER_H = lto-streamer.h $(LINKER_PLUGIN_API_H) $(TARGET_H) \
>  		$(CGRAPH_H) $(VEC_H) vecprim.h $(TREE_H) $(GIMPLE_H) \
> -		$(GCOV_IO_H)
> +		$(GCOV_IO_H) $(DIAGNOSTIC_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)
> +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
>  GSTAB_H = gstab.h stab.def
> @@ -1236,6 +1241,9 @@ OBJS = \
>  	cprop.o \
>  	cse.o \
>  	cselib.o \
> +	data-streamer.o \
> +	data-streamer-in.o \
> +	data-streamer-out.o \
>  	dbxout.o \
>  	dbgcnt.o \
>  	dce.o \
> @@ -1272,6 +1280,8 @@ OBJS = \
>  	gimple-fold.o \
>  	gimple-low.o \
>  	gimple-pretty-print.o \
> +	gimple-streamer-in.o \
> +	gimple-streamer-out.o \
>  	gimplify.o \
>  	godump.o \
>  	graph.o \
> @@ -1327,13 +1337,13 @@ OBJS = \
>  	loop-unswitch.o \
>  	lower-subreg.o \
>  	lto-cgraph.o \
> +	lto-streamer.o \
>  	lto-streamer-in.o \
>  	lto-streamer-out.o \
>  	lto-section-in.o \
>  	lto-section-out.o \
>  	lto-symtab.o \
>  	lto-opts.o \
> -	lto-streamer.o \
>  	lto-compress.o \
>  	matrix-reorg.o \
>  	mcf.o \
> @@ -1388,6 +1398,7 @@ OBJS = \
>  	stmt.o \
>  	stor-layout.o \
>  	store-motion.o \
> +	streamer-hooks.o \
>  	stringpool.o \
>  	target-globals.o \
>  	targhooks.o \
> @@ -1464,6 +1475,9 @@ OBJS = \
>  	tree-ssa.o \
>  	tree-ssanames.o \
>  	tree-stdarg.o \
> +	tree-streamer.o \
> +	tree-streamer-in.o \
> +	tree-streamer-out.o \
>  	tree-tailcall.o \
>  	tree-vect-generic.o \
>  	tree-vect-patterns.o \
> @@ -2276,22 +2290,47 @@ lto-compress.o: lto-compress.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
>  	$(TREE_H) langhooks.h $(LTO_STREAMER_H) $(LTO_SECTION_H) \
>  	lto-compress.h $(DIAGNOSTIC_CORE_H) $(DIAGNOSTIC_CORE_H)
>  	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(ZLIBINC) $< $(OUTPUT_OPTION)
> -
> +data-streamer-in.o: data-streamer-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
> +    $(DATA_STREAMER_H) $(DIAGNOSTIC_H)
> +data-streamer-out.o: data-streamer-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
> +    $(DATA_STREAMER_H)
> +data-streamer.o: data-streamer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
> +    $(DATA_STREAMER_H)
> +gimple-streamer-in.o: gimple-streamer-in.c $(CONFIG_H) $(SYSTEM_H) \
> +    coretypes.h $(GIMPLE_STREAMER_H) $(TREE_FLOW_H) $(DATA_STREAMER_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)
> +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) \
> +    coretypes.h $(DIAGNOSTIC_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_STREAMER_H) \
> +    $(DATA_STREAMER_H) $(STREAMER_HOOKS_H) $(LTO_STREAMER_H)
> +tree-streamer-out.o: tree-streamer-out.c $(CONFIG_H) $(SYSTEM_H) \
> +    coretypes.h $(DIAGNOSTIC_H) $(TREE_STREAMER_H) $(DATA_STREAMER_H) \
> +    $(STREAMER_HOOKS_H)
> +streamer-hooks.o: streamer-hooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
> +    $(STREAMER_HOOKS_H)
>  lto-cgraph.o: lto-cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h   \
>     $(TM_H) $(DIAGNOSTIC_CORE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
>     $(HASHTAB_H) langhooks.h $(BASIC_BLOCK_H) \
>     $(TREE_FLOW_H) $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_CORE_H) \
> -   $(EXCEPT_H) $(TIMEVAR_H) output.h pointer-set.h $(LTO_STREAMER_H) $(GCOV_IO_H)
> +   $(EXCEPT_H) $(TIMEVAR_H) output.h pointer-set.h $(LTO_STREAMER_H) \
> +   $(GCOV_IO_H) $(DATA_STREAMER_H) $(TREE_STREAMER_H)
>  lto-streamer-in.o: lto-streamer-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
>     $(TM_H) toplev.h $(DIAGNOSTIC_CORE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
>     $(HASHTAB_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(TREE_PASS_H) $(CGRAPH_H) \
>     $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) $(LIBFUNCS_H) $(EXCEPT_H) debug.h \
> -   $(TIMEVAR_H) output.h $(IPA_UTILS_H) $(LTO_STREAMER_H) toplev.h
> +   $(TIMEVAR_H) output.h $(IPA_UTILS_H) $(LTO_STREAMER_H) toplev.h \
> +   $(DATA_STREAMER_H) $(GIMPLE_STREAMER_H) $(TREE_STREAMER_H)
>  lto-streamer-out.o : lto-streamer-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
>     $(TM_H) $(DIAGNOSTIC_CORE_H) $(TREE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
>     $(HASHTAB_H) $(BASIC_BLOCK_H) tree-iterator.h \
>     $(TREE_FLOW_H) $(TREE_PASS_H) $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) \
> -   $(DIAGNOSTIC_CORE_H) $(EXCEPT_H) $(LTO_STREAMER_H) $(DIAGNOSTIC_CORE_H)
> +   $(DIAGNOSTIC_CORE_H) $(EXCEPT_H) $(LTO_STREAMER_H) $(DIAGNOSTIC_CORE_H) \
> +   $(DATA_STREAMER_H) $(STREAMER_HOOKS_H) $(GIMPLE_STREAMER_H) \
> +   $(TREE_STREAMER_H)
>  lto-section-in.o: lto-section-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
>     $(DIAGNOSTIC_CORE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
>     $(HASHTAB_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(CGRAPH_H) $(FUNCTION_H) \
> @@ -2310,7 +2349,8 @@ lto-opts.o: lto-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
>     $(COMMON_TARGET_H) $(DIAGNOSTIC_H) $(LTO_STREAMER_H)
>  lto-streamer.o: lto-streamer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h   \
>     $(TM_H) $(TREE_H) $(GIMPLE_H) $(BITMAP_H) $(LTO_STREAMER_H) $(FLAGS_H) \
> -   $(TREE_FLOW_H) $(DIAGNOSTIC_CORE_H) $(LTO_SYMTAB_H) toplev.h $(DIAGNOSTIC_CORE_H)
> +   $(TREE_FLOW_H) $(DIAGNOSTIC_CORE_H) $(LTO_SYMTAB_H) toplev.h \
> +   $(DIAGNOSTIC_CORE_H) $(STREAMER_HOOKS_H)
>  langhooks.o : langhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
>     $(TREE_H) toplev.h $(DIAGNOSTIC_CORE_H) $(TREE_INLINE_H) $(RTL_H) insn-config.h $(INTEGRATE_H) \
>     langhooks.h $(TARGET_H) $(LANGHOOKS_DEF_H) $(FLAGS_H) $(GGC_H) $(DIAGNOSTIC_H) \
> @@ -2990,7 +3030,8 @@ ipa-prop.o : ipa-prop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
>     langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H) $(IPA_PROP_H) $(DIAGNOSTIC_H) \
>     $(TREE_FLOW_H) $(TM_H) $(TREE_PASS_H) $(FLAGS_H) $(TREE_H) \
>     $(TREE_INLINE_H) $(GIMPLE_H) $(TIMEVAR_H) \
> -   tree-pretty-print.h gimple-pretty-print.h $(LTO_STREAMER_H)
> +   tree-pretty-print.h gimple-pretty-print.h $(LTO_STREAMER_H) \
> +   $(DATA_STREAMER_H) $(TREE_STREAMER_H)
>  ipa-ref.o : ipa-ref.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
>     langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H)  $(TREE_H) $(TARGET_H) \
>     $(TREE_FLOW_H) $(TM_H) $(TREE_PASS_H) $(FLAGS_H) $(TREE_H) $(GGC_H) 
> @@ -3018,7 +3059,8 @@ ipa-inline-analysis.o : ipa-inline-analysis.c $(CONFIG_H) $(SYSTEM_H) coretypes.
>     $(TREE_H) langhooks.h $(TREE_INLINE_H) $(FLAGS_H) $(CGRAPH_H) intl.h \
>     $(DIAGNOSTIC_H) $(PARAMS_H) $(TIMEVAR_H) $(TREE_PASS_H) \
>     $(HASHTAB_H) $(COVERAGE_H) $(GGC_H) $(TREE_FLOW_H) $(IPA_PROP_H) \
> -   gimple-pretty-print.h ipa-inline.h $(LTO_STREAMER_H)
> +   gimple-pretty-print.h ipa-inline.h $(LTO_STREAMER_H) $(DATA_STREAMER_H) \
> +   $(TREE_STREAMER_H)
>  ipa-inline-transform.o : ipa-inline-transform.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
>     $(TREE_H) langhooks.h $(TREE_INLINE_H) $(FLAGS_H) $(CGRAPH_H) intl.h \
>     $(DIAGNOSTIC_H) $(PARAMS_H) $(TIMEVAR_H) $(TREE_PASS_H) \
> @@ -3038,7 +3080,7 @@ ipa-pure-const.o : ipa-pure-const.c $(CONFIG_H) $(SYSTEM_H) \
>     pointer-set.h $(GGC_H) $(IPA_UTILS_H) $(TARGET_H) \
>     $(GIMPLE_H) $(CGRAPH_H) output.h $(FLAGS_H) $(TREE_PASS_H) $(TIMEVAR_H) \
>     $(DIAGNOSTIC_H) $(CFGLOOP_H) $(SCEV_H) $(LTO_STREAMER_H) \
> -   gimple-pretty-print.h
> +   gimple-pretty-print.h $(DATA_STREAMER_H) $(TREE_STREAMER_H)
>  coverage.o : coverage.c $(GCOV_IO_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h \
>     $(TM_H) $(RTL_H) $(TREE_H) $(FLAGS_H) output.h $(REGS_H) $(EXPR_H) \
>     $(FUNCTION_H) $(BASIC_BLOCK_H) toplev.h $(DIAGNOSTIC_CORE_H) $(GGC_H) langhooks.h $(COVERAGE_H) \
> diff --git a/gcc/data-streamer-in.c b/gcc/data-streamer-in.c
> new file mode 100644
> index 0000000..5e366b1
> --- /dev/null
> +++ b/gcc/data-streamer-in.c
> @@ -0,0 +1,152 @@
> +/* Routines for restoring various data types from a file stream.  This deals
> +   with various data types like strings, integers, enums, etc.
> +
> +   Copyright 2011 Free Software Foundation, Inc.
> +   Contributed by Diego Novillo <dnovillo@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "diagnostic.h"
> +#include "data-streamer.h"
> +
> +/* Read a string from the string table in DATA_IN using input block
> +   IB.  Write the length to RLEN.  */
> +
> +const char *
> +string_for_index (struct data_in *data_in, unsigned int loc, unsigned int *rlen)
> +{
> +  struct lto_input_block str_tab;
> +  unsigned int len;
> +  const char *result;
> +
> +  if (!loc)
> +    {
> +      *rlen = 0;
> +      return NULL;
> +    }
> +
> +  /* Get the string stored at location LOC in DATA_IN->STRINGS.  */
> +  LTO_INIT_INPUT_BLOCK (str_tab, data_in->strings, loc - 1,
> +			data_in->strings_len);
> +  len = lto_input_uleb128 (&str_tab);
> +  *rlen = len;
> +
> +  if (str_tab.p + len > data_in->strings_len)
> +    internal_error ("bytecode stream: string too long for the string table");
> +
> +  result = (const char *)(data_in->strings + str_tab.p);
> +
> +  return result;
> +}
> +
> +
> +/* Read a string from the string table in DATA_IN using input block
> +   IB.  Write the length to RLEN.  */
> +
> +const char *
> +input_string_internal (struct data_in *data_in, struct lto_input_block *ib,
> +		       unsigned int *rlen)
> +{
> +  return string_for_index (data_in, lto_input_uleb128 (ib), rlen);
> +}
> +
> +
> +/* Read a NULL terminated string from the string table in DATA_IN.  */
> +
> +const char *
> +lto_input_string (struct data_in *data_in, struct lto_input_block *ib)
> +{
> +  unsigned int len;
> +  const char *ptr;
> +
> +  ptr = input_string_internal (data_in, ib, &len);
> +  if (!ptr)
> +    return NULL;
> +  if (ptr[len - 1] != '\0')
> +    internal_error ("bytecode stream: found non-null terminated string");
> +
> +  return ptr;
> +}
> +
> +
> +/* Read an ULEB128 Number of IB.  */
> +
> +unsigned HOST_WIDE_INT
> +lto_input_uleb128 (struct lto_input_block *ib)
> +{
> +  unsigned HOST_WIDE_INT result = 0;
> +  int shift = 0;
> +  unsigned HOST_WIDE_INT byte;
> +
> +  while (true)
> +    {
> +      byte = lto_input_1_unsigned (ib);
> +      result |= (byte & 0x7f) << shift;
> +      shift += 7;
> +      if ((byte & 0x80) == 0)
> +	return result;
> +    }
> +}
> +
> +
> +/* HOST_WIDEST_INT version of lto_input_uleb128.  IB is as in
> +   lto_input_uleb128.  */
> +
> +unsigned HOST_WIDEST_INT
> +lto_input_widest_uint_uleb128 (struct lto_input_block *ib)
> +{
> +  unsigned HOST_WIDEST_INT result = 0;
> +  int shift = 0;
> +  unsigned HOST_WIDEST_INT byte;
> +
> +  while (true)
> +    {
> +      byte = lto_input_1_unsigned (ib);
> +      result |= (byte & 0x7f) << shift;
> +      shift += 7;
> +      if ((byte & 0x80) == 0)
> +	return result;
> +    }
> +}
> +
> +
> +/* Read an SLEB128 Number of IB.  */
> +
> +HOST_WIDE_INT
> +lto_input_sleb128 (struct lto_input_block *ib)
> +{
> +  HOST_WIDE_INT result = 0;
> +  int shift = 0;
> +  unsigned HOST_WIDE_INT byte;
> +
> +  while (true)
> +    {
> +      byte = lto_input_1_unsigned (ib);
> +      result |= (byte & 0x7f) << shift;
> +      shift += 7;
> +      if ((byte & 0x80) == 0)
> +	{
> +	  if ((shift < HOST_BITS_PER_WIDE_INT) && (byte & 0x40))
> +	    result |= - ((HOST_WIDE_INT)1 << shift);
> +
> +	  return result;
> +	}
> +    }
> +}
> diff --git a/gcc/data-streamer-out.c b/gcc/data-streamer-out.c
> new file mode 100644
> index 0000000..07d5b35
> --- /dev/null
> +++ b/gcc/data-streamer-out.c
> @@ -0,0 +1,207 @@
> +/* Routines for saving various data types to a file stream.  This deals
> +   with various data types like strings, integers, enums, etc.
> +
> +   Copyright 2011 Free Software Foundation, Inc.
> +   Contributed by Diego Novillo <dnovillo@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "data-streamer.h"
> +
> +/* Return index used to reference STRING of LEN characters in the string table
> +   in OB.  The string might or might not include a trailing '\0'.
> +   Then put the index onto the INDEX_STREAM.  
> +   When PERSISTENT is set, the string S is supposed to not change during
> +   duration of the OB and thus OB can keep pointer into it.  */
> +
> +unsigned
> +lto_string_index (struct output_block *ob, const char *s, unsigned int len,
> +		  bool persistent)
> +{
> +  struct string_slot **slot;
> +  struct string_slot s_slot;
> +
> +  s_slot.s = s;
> +  s_slot.len = len;
> +  s_slot.slot_num = 0;
> +
> +  slot = (struct string_slot **) htab_find_slot (ob->string_hash_table,
> +						 &s_slot, INSERT);
> +  if (*slot == NULL)
> +    {
> +      struct lto_output_stream *string_stream = ob->string_stream;
> +      unsigned int start = string_stream->total_size;
> +      struct string_slot *new_slot = XOBNEW (&ob->obstack, struct string_slot);
> +      const char *string;
> +
> +      if (!persistent)
> +	{
> +	  char *tmp;
> +	  string = tmp = XOBNEWVEC (&ob->obstack, char, len);
> +          memcpy (tmp, s, len);
> +        }
> +      else
> +	string = s;
> +
> +      new_slot->s = string;
> +      new_slot->len = len;
> +      new_slot->slot_num = start;
> +      *slot = new_slot;
> +      lto_output_uleb128_stream (string_stream, len);
> +      lto_output_data_stream (string_stream, string, len);
> +      return start + 1;
> +    }
> +  else
> +    {
> +      struct string_slot *old_slot = *slot;
> +      return old_slot->slot_num + 1;
> +    }
> +}
> +
> +
> +/* Output STRING of LEN characters to the string table in OB. The
> +   string might or might not include a trailing '\0'. Then put the
> +   index onto the INDEX_STREAM. 
> +   When PERSISTENT is set, the string S is supposed to not change during
> +   duration of the OB and thus OB can keep pointer into it.  */
> +
> +void
> +lto_output_string_with_length (struct output_block *ob,
> +			       struct lto_output_stream *index_stream,
> +			       const char *s, unsigned int len, bool persistent)
> +{
> +  if (s)
> +    lto_output_uleb128_stream (index_stream,
> +			       lto_string_index (ob, s, len, persistent));
> +  else
> +    lto_output_1_stream (index_stream, 0);
> +}
> +
> +
> +/* Output the '\0' terminated STRING to the string
> +   table in OB.  Then put the index onto the INDEX_STREAM.
> +   When PERSISTENT is set, the string S is supposed to not change during
> +   duration of the OB and thus OB can keep pointer into it.  */
> +
> +void
> +lto_output_string (struct output_block *ob,
> +	           struct lto_output_stream *index_stream,
> +	           const char *string, bool persistent)
> +{
> +  if (string)
> +    lto_output_string_with_length (ob, index_stream, string,
> +				   strlen (string) + 1,
> +				   persistent);
> +  else
> +    lto_output_1_stream (index_stream, 0);
> +}
> +
> +
> +/* Write a zero to the output stream.  */
> +
> +void
> +output_zero (struct output_block *ob)
> +{
> +  lto_output_1_stream (ob->main_stream, 0);
> +}
> +
> +
> +/* Output an unsigned LEB128 quantity to OB->main_stream.  */
> +
> +void
> +output_uleb128 (struct output_block *ob, unsigned HOST_WIDE_INT work)
> +{
> +  lto_output_uleb128_stream (ob->main_stream, work);
> +}
> +
> +
> +/* Output a signed LEB128 quantity to OB->main_stream.  */
> +
> +void
> +output_sleb128 (struct output_block *ob, HOST_WIDE_INT work)
> +{
> +  lto_output_sleb128_stream (ob->main_stream, work);
> +}
> +
> +
> +/* Output an unsigned LEB128 quantity to OBS.  */
> +
> +void
> +lto_output_uleb128_stream (struct lto_output_stream *obs,
> +			   unsigned HOST_WIDE_INT work)
> +{
> +  do
> +    {
> +      unsigned int byte = (work & 0x7f);
> +      work >>= 7;
> +      if (work != 0)
> +	/* More bytes to follow.  */
> +	byte |= 0x80;
> +
> +      lto_output_1_stream (obs, byte);
> +    }
> +  while (work != 0);
> +}
> +
> +
> +/* Identical to output_uleb128_stream above except using unsigned
> +   HOST_WIDEST_INT type.  For efficiency on host where unsigned HOST_WIDEST_INT
> +   is not native, we only use this if we know that HOST_WIDE_INT is not wide
> +   enough.  */
> +
> +void
> +lto_output_widest_uint_uleb128_stream (struct lto_output_stream *obs,
> +				       unsigned HOST_WIDEST_INT work)
> +{
> +  do
> +    {
> +      unsigned int byte = (work & 0x7f);
> +      work >>= 7;
> +      if (work != 0)
> +	/* More bytes to follow.  */
> +	byte |= 0x80;
> +
> +      lto_output_1_stream (obs, byte);
> +    }
> +  while (work != 0);
> +}
> +
> +
> +/* Output a signed LEB128 quantity.  */
> +
> +void
> +lto_output_sleb128_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
> +{
> +  int more, byte;
> +
> +  do
> +    {
> +      byte = (work & 0x7f);
> +      /* arithmetic shift */
> +      work >>= 7;
> +      more = !((work == 0 && (byte & 0x40) == 0)
> +	       || (work == -1 && (byte & 0x40) != 0));
> +      if (more)
> +	byte |= 0x80;
> +
> +      lto_output_1_stream (obs, byte);
> +    }
> +  while (more);
> +}
> diff --git a/gcc/data-streamer.c b/gcc/data-streamer.c
> new file mode 100644
> index 0000000..5eaacfc
> --- /dev/null
> +++ b/gcc/data-streamer.c
> @@ -0,0 +1,111 @@
> +/* Generic streaming support for basic data types.
> +
> +   Copyright 2011 Free Software Foundation, Inc.
> +   Contributed by Diego Novillo <dnovillo@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "data-streamer.h"
> +
> +/* Pack WORK into BP in a variant of uleb format.  */
> +
> +void
> +bp_pack_var_len_unsigned (struct bitpack_d *bp, unsigned HOST_WIDE_INT work)
> +{
> +  do
> +    {
> +      unsigned int half_byte = (work & 0x7);
> +      work >>= 3;
> +      if (work != 0)
> +	/* More half_bytes to follow.  */
> +	half_byte |= 0x8;
> +
> +      bp_pack_value (bp, half_byte, 4);
> +    }
> +  while (work != 0);
> +}
> +
> +
> +/* Pack WORK into BP in a variant of sleb format.  */
> +
> +void
> +bp_pack_var_len_int (struct bitpack_d *bp, HOST_WIDE_INT work)
> +{
> +  int more, half_byte;
> +
> +  do
> +    {
> +      half_byte = (work & 0x7);
> +      /* arithmetic shift */
> +      work >>= 3;
> +      more = !((work == 0 && (half_byte & 0x4) == 0)
> +	       || (work == -1 && (half_byte & 0x4) != 0));
> +      if (more)
> +	half_byte |= 0x8;
> +
> +      bp_pack_value (bp, half_byte, 4);
> +    }
> +  while (more);
> +}
> +
> +
> +/* Unpack VAL from BP in a variant of uleb format.  */
> +
> +unsigned HOST_WIDE_INT
> +bp_unpack_var_len_unsigned (struct bitpack_d *bp)
> +{
> +  unsigned HOST_WIDE_INT result = 0;
> +  int shift = 0;
> +  unsigned HOST_WIDE_INT half_byte;
> +
> +  while (true)
> +    {
> +      half_byte = bp_unpack_value (bp, 4);
> +      result |= (half_byte & 0x7) << shift;
> +      shift += 3;
> +      if ((half_byte & 0x8) == 0)
> +	return result;
> +    }
> +}
> +
> +
> +/* Unpack VAL from BP in a variant of sleb format.  */
> +
> +HOST_WIDE_INT
> +bp_unpack_var_len_int (struct bitpack_d *bp)
> +{
> +  HOST_WIDE_INT result = 0;
> +  int shift = 0;
> +  unsigned HOST_WIDE_INT half_byte;
> +
> +  while (true)
> +    {
> +      half_byte = bp_unpack_value (bp, 4);
> +      result |= (half_byte & 0x7) << shift;
> +      shift += 3;
> +      if ((half_byte & 0x8) == 0)
> +	{
> +	  if ((shift < HOST_BITS_PER_WIDE_INT) && (half_byte & 0x4))
> +	    result |= - ((HOST_WIDE_INT)1 << shift);
> +
> +	  return result;
> +	}
> +    }
> +}
> diff --git a/gcc/data-streamer.h b/gcc/data-streamer.h
> new file mode 100644
> index 0000000..c2f6fa8
> --- /dev/null
> +++ b/gcc/data-streamer.h
> @@ -0,0 +1,355 @@
> +/* Generic streaming support for various data types.
> +
> +   Copyright 2011 Free Software Foundation, Inc.
> +   Contributed by Diego Novillo <dnovillo@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GCC_DATA_STREAMER_H
> +#define GCC_DATA_STREAMER_H
> +
> +#include "vec.h"
> +#include "lto-streamer.h"
> +
> +/* Data structures used to pack values and bitflags into a vector of
> +   words.  Used to stream values of a fixed number of bits in a space
> +   efficient way.  */
> +static unsigned const BITS_PER_BITPACK_WORD = HOST_BITS_PER_WIDE_INT;
> +
> +typedef unsigned HOST_WIDE_INT bitpack_word_t;
> +DEF_VEC_I(bitpack_word_t);
> +DEF_VEC_ALLOC_I(bitpack_word_t, heap);
> +
> +struct bitpack_d
> +{
> +  /* The position of the first unused or unconsumed bit in the word.  */
> +  unsigned pos;
> +
> +  /* The current word we are (un)packing.  */
> +  bitpack_word_t word;
> +
> +  /* The lto_output_stream or the lto_input_block we are streaming to/from.  */
> +  void *stream;
> +};
> +
> +
> +/* String hashing.  */
> +struct string_slot
> +{
> +  const char *s;
> +  int len;
> +  unsigned int slot_num;
> +};
> +
> +
> +/* Returns a hash code for P.  Adapted from libiberty's htab_hash_string
> +   to support strings that may not end in '\0'.  */
> +
> +static inline hashval_t
> +hash_string_slot_node (const void *p)
> +{
> +  const struct string_slot *ds = (const struct string_slot *) p;
> +  hashval_t r = ds->len;
> +  int i;
> +
> +  for (i = 0; i < ds->len; i++)
> +     r = r * 67 + (unsigned)ds->s[i] - 113;
> +  return r;
> +}
> +
> +/* Returns nonzero if P1 and P2 are equal.  */
> +
> +static inline int
> +eq_string_slot_node (const void *p1, const void *p2)
> +{
> +  const struct string_slot *ds1 = (const struct string_slot *) p1;
> +  const struct string_slot *ds2 = (const struct string_slot *) p2;
> +
> +  if (ds1->len == ds2->len)
> +    return memcmp (ds1->s, ds2->s, ds1->len) == 0;
> +
> +  return 0;
> +}
> +
> +/* Returns a new bit-packing context for bit-packing into S.  */
> +static inline struct bitpack_d
> +bitpack_create (struct lto_output_stream *s)
> +{
> +  struct bitpack_d bp;
> +  bp.pos = 0;
> +  bp.word = 0;
> +  bp.stream = (void *)s;
> +  return bp;
> +}
> +
> +/* Pack the NBITS bit sized value VAL into the bit-packing context BP.  */
> +static inline void
> +bp_pack_value (struct bitpack_d *bp, bitpack_word_t val, unsigned nbits)
> +{
> +  bitpack_word_t word = bp->word;
> +  int pos = bp->pos;
> +
> +  /* Verify that VAL fits in the NBITS.  */
> +  gcc_checking_assert (nbits == BITS_PER_BITPACK_WORD
> +		       || !(val & ~(((bitpack_word_t)1<<nbits)-1)));
> +
> +  /* If val does not fit into the current bitpack word switch to the
> +     next one.  */
> +  if (pos + nbits > BITS_PER_BITPACK_WORD)
> +    {
> +      lto_output_uleb128_stream ((struct lto_output_stream *) bp->stream, word);
> +      word = val;
> +      pos = nbits;
> +    }
> +  else
> +    {
> +      word |= val << pos;
> +      pos += nbits;
> +    }
> +  bp->word = word;
> +  bp->pos = pos;
> +}
> +
> +/* Finishes bit-packing of BP.  */
> +static inline void
> +lto_output_bitpack (struct bitpack_d *bp)
> +{
> +  lto_output_uleb128_stream ((struct lto_output_stream *) bp->stream,
> +			     bp->word);
> +  bp->word = 0;
> +  bp->pos = 0;
> +}
> +
> +/* Returns a new bit-packing context for bit-unpacking from IB.  */
> +static inline struct bitpack_d
> +lto_input_bitpack (struct lto_input_block *ib)
> +{
> +  struct bitpack_d bp;
> +  bp.word = lto_input_uleb128 (ib);
> +  bp.pos = 0;
> +  bp.stream = (void *)ib;
> +  return bp;
> +}
> +
> +/* Unpacks NBITS bits from the bit-packing context BP and returns them.  */
> +static inline bitpack_word_t
> +bp_unpack_value (struct bitpack_d *bp, unsigned nbits)
> +{
> +  bitpack_word_t mask, val;
> +  int pos = bp->pos;
> +
> +  mask = (nbits == BITS_PER_BITPACK_WORD
> +	  ? (bitpack_word_t) -1
> +	  : ((bitpack_word_t) 1 << nbits) - 1);
> +
> +  /* If there are not continuous nbits in the current bitpack word
> +     switch to the next one.  */
> +  if (pos + nbits > BITS_PER_BITPACK_WORD)
> +    {
> +      bp->word = val = lto_input_uleb128 ((struct lto_input_block *)bp->stream);
> +      bp->pos = nbits;
> +      return val & mask;
> +    }
> +  val = bp->word;
> +  val >>= pos;
> +  bp->pos = pos + nbits;
> +
> +  return val & mask;
> +}
> +
> +
> +/* Write a character to the output block.  */
> +
> +static inline void
> +lto_output_1_stream (struct lto_output_stream *obs, char c)
> +{
> +  /* No space left.  */
> +  if (obs->left_in_block == 0)
> +    lto_append_block (obs);
> +
> +  /* Write the actual character.  */
> +  *obs->current_pointer = c;
> +  obs->current_pointer++;
> +  obs->total_size++;
> +  obs->left_in_block--;
> +}
> +
> +
> +/* Read byte from the input block.  */
> +
> +static inline unsigned char
> +lto_input_1_unsigned (struct lto_input_block *ib)
> +{
> +  if (ib->p >= ib->len)
> +    lto_section_overrun (ib);
> +  return (ib->data[ib->p++]);
> +}
> +
> +/* Output VAL into OBS and verify it is in range MIN...MAX that is supposed
> +   to be compile time constant.
> +   Be host independent, limit range to 31bits.  */
> +
> +static inline void
> +lto_output_int_in_range (struct lto_output_stream *obs,
> +			 HOST_WIDE_INT min,
> +			 HOST_WIDE_INT max,
> +			 HOST_WIDE_INT val)
> +{
> +  HOST_WIDE_INT range = max - min;
> +
> +  gcc_checking_assert (val >= min && val <= max && range > 0
> +		       && range < 0x7fffffff);
> +
> +  val -= min;
> +  lto_output_1_stream (obs, val & 255);
> +  if (range >= 0xff)
> +    lto_output_1_stream (obs, (val >> 8) & 255);
> +  if (range >= 0xffff)
> +    lto_output_1_stream (obs, (val >> 16) & 255);
> +  if (range >= 0xffffff)
> +    lto_output_1_stream (obs, (val >> 24) & 255);
> +}
> +
> +/* Input VAL into OBS and verify it is in range MIN...MAX that is supposed
> +   to be compile time constant.  PURPOSE is used for error reporting.  */
> +
> +static inline HOST_WIDE_INT
> +lto_input_int_in_range (struct lto_input_block *ib,
> +			const char *purpose,
> +			HOST_WIDE_INT min,
> +			HOST_WIDE_INT max)
> +{
> +  HOST_WIDE_INT range = max - min;
> +  HOST_WIDE_INT val = lto_input_1_unsigned (ib);
> +
> +  gcc_checking_assert (range > 0 && range < 0x7fffffff);
> +
> +  if (range >= 0xff)
> +    val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 8;
> +  if (range >= 0xffff)
> +    val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 16;
> +  if (range >= 0xffffff)
> +    val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 24;
> +  val += min;
> +  if (val < min || val > max)
> +    lto_value_range_error (purpose, val, min, max);
> +  return val;
> +}
> +
> +/* Output VAL into BP and verify it is in range MIN...MAX that is supposed
> +   to be compile time constant.
> +   Be host independent, limit range to 31bits.  */
> +
> +static inline void
> +bp_pack_int_in_range (struct bitpack_d *bp,
> +		      HOST_WIDE_INT min,
> +		      HOST_WIDE_INT max,
> +		      HOST_WIDE_INT val)
> +{
> +  HOST_WIDE_INT range = max - min;
> +  int nbits = floor_log2 (range) + 1;
> +
> +  gcc_checking_assert (val >= min && val <= max && range > 0
> +		       && range < 0x7fffffff);
> +
> +  val -= min;
> +  bp_pack_value (bp, val, nbits);
> +}
> +
> +/* Input VAL into BP and verify it is in range MIN...MAX that is supposed
> +   to be compile time constant.  PURPOSE is used for error reporting.  */
> +
> +static inline HOST_WIDE_INT
> +bp_unpack_int_in_range (struct bitpack_d *bp,
> +		        const char *purpose,
> +		        HOST_WIDE_INT min,
> +		        HOST_WIDE_INT max)
> +{
> +  HOST_WIDE_INT range = max - min;
> +  int nbits = floor_log2 (range) + 1;
> +  HOST_WIDE_INT val = bp_unpack_value (bp, nbits);
> +
> +  gcc_checking_assert (range > 0 && range < 0x7fffffff);
> +
> +  if (val < min || val > max)
> +    lto_value_range_error (purpose, val, min, max);
> +  return val;
> +}
> +
> +/* Output VAL of type "enum enum_name" into OBS.
> +   Assume range 0...ENUM_LAST - 1.  */
> +#define lto_output_enum(obs,enum_name,enum_last,val) \
> +  lto_output_int_in_range ((obs), 0, (int)(enum_last) - 1, (int)(val))
> +
> +/* Input enum of type "enum enum_name" from IB.
> +   Assume range 0...ENUM_LAST - 1.  */
> +#define lto_input_enum(ib,enum_name,enum_last) \
> +  (enum enum_name)lto_input_int_in_range ((ib), #enum_name, 0, \
> +					  (int)(enum_last) - 1)
> +
> +/* Output VAL of type "enum enum_name" into BP.
> +   Assume range 0...ENUM_LAST - 1.  */
> +#define bp_pack_enum(bp,enum_name,enum_last,val) \
> +  bp_pack_int_in_range ((bp), 0, (int)(enum_last) - 1, (int)(val))
> +
> +/* Input enum of type "enum enum_name" from BP.
> +   Assume range 0...ENUM_LAST - 1.  */
> +#define bp_unpack_enum(bp,enum_name,enum_last) \
> +  (enum enum_name)bp_unpack_int_in_range ((bp), #enum_name, 0, \
> +					(int)(enum_last) - 1)
> +
> +/* Output the start of a record with TAG to output block OB.  */
> +
> +static inline void
> +output_record_start (struct output_block *ob, enum LTO_tags tag)
> +{
> +  lto_output_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS, tag);
> +}
> +
> +/* Return the next tag in the input block IB.  */
> +
> +static inline enum LTO_tags
> +input_record_start (struct lto_input_block *ib)
> +{
> +  return lto_input_enum (ib, LTO_tags, LTO_NUM_TAGS);
> +}
> +
> +/* In data-streamer.c  */
> +void bp_pack_var_len_unsigned (struct bitpack_d *, unsigned HOST_WIDE_INT);
> +void bp_pack_var_len_int (struct bitpack_d *, HOST_WIDE_INT);
> +unsigned HOST_WIDE_INT bp_unpack_var_len_unsigned (struct bitpack_d *);
> +HOST_WIDE_INT bp_unpack_var_len_int (struct bitpack_d *);
> +
> +/* In data-streamer-out.c  */
> +void output_zero (struct output_block *);
> +void output_uleb128 (struct output_block *, unsigned HOST_WIDE_INT);
> +void output_sleb128 (struct output_block *, HOST_WIDE_INT);
> +void lto_output_string (struct output_block *, struct lto_output_stream *,
> +			const char *, bool);
> +unsigned lto_string_index (struct output_block *, const char *, unsigned int,
> +			   bool);
> +void lto_output_string_with_length (struct output_block *,
> +				    struct lto_output_stream *,
> +				    const char *, unsigned int, bool);
> +const char *input_string_internal (struct data_in *, struct lto_input_block *,
> +				   unsigned int *);
> +
> +/* In data-streamer-in.c  */
> +const char *string_for_index (struct data_in *, unsigned int, unsigned int *);
> +const char *lto_input_string (struct data_in *, struct lto_input_block *);
> +
> +#endif  /* GCC_DATA_STREAMER_H  */
> diff --git a/gcc/gimple-streamer-in.c b/gcc/gimple-streamer-in.c
> new file mode 100644
> index 0000000..dd91c73
> --- /dev/null
> +++ b/gcc/gimple-streamer-in.c
> @@ -0,0 +1,333 @@
> +/* Routines for reading GIMPLE from a file stream.
> +
> +   Copyright 2011 Free Software Foundation, Inc.
> +   Contributed by Diego Novillo <dnovillo@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "diagnostic.h"
> +#include "tree.h"
> +#include "tree-flow.h"
> +#include "data-streamer.h"
> +#include "tree-streamer.h"
> +#include "gimple-streamer.h"
> +
> +/* Read a PHI function for basic block BB in function FN.  DATA_IN is
> +   the file being read.  IB is the input block to use for reading.  */
> +
> +static gimple
> +input_phi (struct lto_input_block *ib, basic_block bb, struct data_in *data_in,
> +	   struct function *fn)
> +{
> +  unsigned HOST_WIDE_INT ix;
> +  tree phi_result;
> +  int i, len;
> +  gimple result;
> +
> +  ix = lto_input_uleb128 (ib);
> +  phi_result = VEC_index (tree, SSANAMES (fn), ix);
> +  len = EDGE_COUNT (bb->preds);
> +  result = create_phi_node (phi_result, bb);
> +  SSA_NAME_DEF_STMT (phi_result) = result;
> +
> +  /* We have to go through a lookup process here because the preds in the
> +     reconstructed graph are generally in a different order than they
> +     were in the original program.  */
> +  for (i = 0; i < len; i++)
> +    {
> +      tree def = lto_input_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);
> +
> +      edge e = NULL;
> +      int j;
> +
> +      for (j = 0; j < len; j++)
> +	if (EDGE_PRED (bb, j)->src == sbb)
> +	  {
> +	    e = EDGE_PRED (bb, j);
> +	    break;
> +	  }
> +
> +      add_phi_arg (result, def, e, arg_loc);
> +    }
> +
> +  return result;
> +}
> +
> +
> +/* Read a statement with tag TAG in function FN from block IB using
> +   descriptors in DATA_IN.  */
> +
> +static gimple
> +input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
> +		   struct function *fn, enum LTO_tags tag)
> +{
> +  gimple stmt;
> +  enum gimple_code code;
> +  unsigned HOST_WIDE_INT num_ops;
> +  size_t i;
> +  struct bitpack_d bp;
> +
> +  code = lto_tag_to_gimple_code (tag);
> +
> +  /* Read the tuple header.  */
> +  bp = lto_input_bitpack (ib);
> +  num_ops = bp_unpack_var_len_unsigned (&bp);
> +  stmt = gimple_alloc (code, num_ops);
> +  stmt->gsbase.no_warning = bp_unpack_value (&bp, 1);
> +  if (is_gimple_assign (stmt))
> +    stmt->gsbase.nontemporal_move = bp_unpack_value (&bp, 1);
> +  stmt->gsbase.has_volatile_ops = bp_unpack_value (&bp, 1);
> +  stmt->gsbase.subcode = bp_unpack_var_len_unsigned (&bp);
> +
> +  /* Read location information.  */
> +  gimple_set_location (stmt, lto_input_location (ib, data_in));
> +
> +  /* Read lexical block reference.  */
> +  gimple_set_block (stmt, lto_input_tree (ib, data_in));
> +
> +  /* Read in all the operands.  */
> +  switch (code)
> +    {
> +    case GIMPLE_RESX:
> +      gimple_resx_set_region (stmt, lto_input_sleb128 (ib));
> +      break;
> +
> +    case GIMPLE_EH_MUST_NOT_THROW:
> +      gimple_eh_must_not_throw_set_fndecl (stmt, lto_input_tree (ib, data_in));
> +      break;
> +
> +    case GIMPLE_EH_DISPATCH:
> +      gimple_eh_dispatch_set_region (stmt, lto_input_sleb128 (ib));
> +      break;
> +
> +    case GIMPLE_ASM:
> +      {
> +	/* FIXME lto.  Move most of this into a new gimple_asm_set_string().  */
> +	tree str;
> +	stmt->gimple_asm.ni = lto_input_uleb128 (ib);
> +	stmt->gimple_asm.no = lto_input_uleb128 (ib);
> +	stmt->gimple_asm.nc = lto_input_uleb128 (ib);
> +	stmt->gimple_asm.nl = lto_input_uleb128 (ib);
> +	str = input_string_cst (data_in, ib);
> +	stmt->gimple_asm.string = TREE_STRING_POINTER (str);
> +      }
> +      /* Fallthru  */
> +
> +    case GIMPLE_ASSIGN:
> +    case GIMPLE_CALL:
> +    case GIMPLE_RETURN:
> +    case GIMPLE_SWITCH:
> +    case GIMPLE_LABEL:
> +    case GIMPLE_COND:
> +    case GIMPLE_GOTO:
> +    case GIMPLE_DEBUG:
> +      for (i = 0; i < num_ops; i++)
> +	{
> +	  tree op = lto_input_tree (ib, data_in);
> +	  gimple_set_op (stmt, i, op);
> +	  if (!op)
> +	    continue;
> +
> +	  /* Fixup FIELD_DECLs in COMPONENT_REFs, they are not handled
> +	     by decl merging.  */
> +	  if (TREE_CODE (op) == ADDR_EXPR)
> +	    op = TREE_OPERAND (op, 0);
> +	  while (handled_component_p (op))
> +	    {
> +	      if (TREE_CODE (op) == COMPONENT_REF)
> +		{
> +		  tree field, type, tem;
> +		  tree closest_match = NULL_TREE;
> +		  field = TREE_OPERAND (op, 1);
> +		  type = DECL_CONTEXT (field);
> +		  for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
> +		    {
> +		      if (tem == field)
> +			break;
> +		      if (DECL_NONADDRESSABLE_P (tem)
> +			  == DECL_NONADDRESSABLE_P (field)
> +			  && gimple_compare_field_offset (tem, field))
> +			{
> +			  if (types_compatible_p (TREE_TYPE (tem),
> +						  TREE_TYPE (field)))
> +			    break;
> +			  else
> +			    closest_match = tem;
> +			}
> +		    }
> +		  /* In case of type mismatches across units we can fail
> +		     to unify some types and thus not find a proper
> +		     field-decl here.  */
> +		  if (tem == NULL_TREE)
> +		    {
> +		      /* Thus, emit a ODR violation warning.  */
> +		      if (warning_at (gimple_location (stmt), 0,
> +				      "use of type %<%E%> with two mismatching "
> +				      "declarations at field %<%E%>",
> +				      type, TREE_OPERAND (op, 1)))
> +			{
> +			  if (TYPE_FIELDS (type))
> +			    inform (DECL_SOURCE_LOCATION (TYPE_FIELDS (type)),
> +				    "original type declared here");
> +			  inform (DECL_SOURCE_LOCATION (TREE_OPERAND (op, 1)),
> +				  "field in mismatching type declared here");
> +			  if (TYPE_NAME (TREE_TYPE (field))
> +			      && (TREE_CODE (TYPE_NAME (TREE_TYPE (field)))
> +				  == TYPE_DECL))
> +			    inform (DECL_SOURCE_LOCATION
> +				      (TYPE_NAME (TREE_TYPE (field))),
> +				    "type of field declared here");
> +			  if (closest_match
> +			      && TYPE_NAME (TREE_TYPE (closest_match))
> +			      && (TREE_CODE (TYPE_NAME
> +				   (TREE_TYPE (closest_match))) == TYPE_DECL))
> +			    inform (DECL_SOURCE_LOCATION
> +				      (TYPE_NAME (TREE_TYPE (closest_match))),
> +				    "type of mismatching field declared here");
> +			}
> +		      /* And finally fixup the types.  */
> +		      TREE_OPERAND (op, 0)
> +			= build1 (VIEW_CONVERT_EXPR, type,
> +				  TREE_OPERAND (op, 0));
> +		    }
> +		  else
> +		    TREE_OPERAND (op, 1) = tem;
> +		}
> +
> +	      op = TREE_OPERAND (op, 0);
> +	    }
> +	}
> +      if (is_gimple_call (stmt))
> +	{
> +	  if (gimple_call_internal_p (stmt))
> +	    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));
> +	}
> +      break;
> +
> +    case GIMPLE_NOP:
> +    case GIMPLE_PREDICT:
> +      break;
> +
> +    default:
> +      internal_error ("bytecode stream: unknown GIMPLE statement tag %s",
> +		      lto_tag_name (tag));
> +    }
> +
> +  /* Update the properties of symbols, SSA names and labels associated
> +     with STMT.  */
> +  if (code == GIMPLE_ASSIGN || code == GIMPLE_CALL)
> +    {
> +      tree lhs = gimple_get_lhs (stmt);
> +      if (lhs && TREE_CODE (lhs) == SSA_NAME)
> +	SSA_NAME_DEF_STMT (lhs) = stmt;
> +    }
> +  else if (code == GIMPLE_LABEL)
> +    gcc_assert (emit_label_in_global_context_p (gimple_label_label (stmt))
> +	        || DECL_CONTEXT (gimple_label_label (stmt)) == fn->decl);
> +  else if (code == GIMPLE_ASM)
> +    {
> +      unsigned i;
> +
> +      for (i = 0; i < gimple_asm_noutputs (stmt); i++)
> +	{
> +	  tree op = TREE_VALUE (gimple_asm_output_op (stmt, i));
> +	  if (TREE_CODE (op) == SSA_NAME)
> +	    SSA_NAME_DEF_STMT (op) = stmt;
> +	}
> +    }
> +
> +  /* Reset alias information.  */
> +  if (code == GIMPLE_CALL)
> +    gimple_call_reset_alias_info (stmt);
> +
> +  /* Mark the statement modified so its operand vectors can be filled in.  */
> +  gimple_set_modified (stmt, true);
> +
> +  return stmt;
> +}
> +
> +
> +/* Read a basic block with tag TAG from DATA_IN using input block IB.
> +   FN is the function being processed.  */
> +
> +void
> +input_bb (struct lto_input_block *ib, enum LTO_tags tag,
> +	  struct data_in *data_in, struct function *fn,
> +	  int count_materialization_scale)
> +{
> +  unsigned int index;
> +  basic_block bb;
> +  gimple_stmt_iterator bsi;
> +
> +  /* This routine assumes that CFUN is set to FN, as it needs to call
> +     basic GIMPLE routines that use CFUN.  */
> +  gcc_assert (cfun == fn);
> +
> +  index = lto_input_uleb128 (ib);
> +  bb = BASIC_BLOCK_FOR_FUNCTION (fn, index);
> +
> +  bb->count = (lto_input_sleb128 (ib) * count_materialization_scale
> +	       + REG_BR_PROB_BASE / 2) / REG_BR_PROB_BASE;
> +  bb->loop_depth = lto_input_sleb128 (ib);
> +  bb->frequency = lto_input_sleb128 (ib);
> +  bb->flags = lto_input_sleb128 (ib);
> +
> +  /* LTO_bb1 has statements.  LTO_bb0 does not.  */
> +  if (tag == LTO_bb0)
> +    return;
> +
> +  bsi = gsi_start_bb (bb);
> +  tag = input_record_start (ib);
> +  while (tag)
> +    {
> +      gimple stmt = input_gimple_stmt (ib, data_in, fn, tag);
> +      if (!is_gimple_debug (stmt))
> +	find_referenced_vars_in (stmt);
> +      gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
> +
> +      /* After the statement, expect a 0 delimiter or the EH region
> +	 that the previous statement belongs to.  */
> +      tag = input_record_start (ib);
> +      lto_tag_check_set (tag, 2, LTO_eh_region, LTO_null);
> +
> +      if (tag == LTO_eh_region)
> +	{
> +	  HOST_WIDE_INT region = lto_input_sleb128 (ib);
> +	  gcc_assert (region == (int) region);
> +	  add_stmt_to_eh_lp (stmt, region);
> +	}
> +
> +      tag = input_record_start (ib);
> +    }
> +
> +  tag = input_record_start (ib);
> +  while (tag)
> +    {
> +      gimple phi = input_phi (ib, bb, data_in, fn);
> +      find_referenced_vars_in (phi);
> +      tag = input_record_start (ib);
> +    }
> +}
> diff --git a/gcc/gimple-streamer-out.c b/gcc/gimple-streamer-out.c
> new file mode 100644
> index 0000000..0a41510
> --- /dev/null
> +++ b/gcc/gimple-streamer-out.c
> @@ -0,0 +1,213 @@
> +/* Routines for emitting GIMPLE to a file stream.
> +
> +   Copyright 2011 Free Software Foundation, Inc.
> +   Contributed by Diego Novillo <dnovillo@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "tree.h"
> +#include "tree-flow.h"
> +#include "data-streamer.h"
> +#include "gimple-streamer.h"
> +#include "lto-streamer.h"
> +
> +/* Output PHI function PHI to the main stream in OB.  */
> +
> +static void
> +output_phi (struct output_block *ob, gimple phi)
> +{
> +  unsigned i, len = gimple_phi_num_args (phi);
> +
> +  output_record_start (ob, lto_gimple_code_to_tag (GIMPLE_PHI));
> +  output_uleb128 (ob, SSA_NAME_VERSION (PHI_RESULT (phi)));
> +
> +  for (i = 0; i < len; i++)
> +    {
> +      lto_output_tree_ref (ob, gimple_phi_arg_def (phi, i));
> +      output_uleb128 (ob, gimple_phi_arg_edge (phi, i)->src->index);
> +      lto_output_location (ob, gimple_phi_arg_location (phi, i));
> +    }
> +}
> +
> +
> +/* Emit statement STMT on the main stream of output block OB.  */
> +
> +static void
> +output_gimple_stmt (struct output_block *ob, gimple stmt)
> +{
> +  unsigned i;
> +  enum gimple_code code;
> +  enum LTO_tags tag;
> +  struct bitpack_d bp;
> +
> +  /* Emit identifying tag.  */
> +  code = gimple_code (stmt);
> +  tag = lto_gimple_code_to_tag (code);
> +  output_record_start (ob, tag);
> +
> +  /* Emit the tuple header.  */
> +  bp = bitpack_create (ob->main_stream);
> +  bp_pack_var_len_unsigned (&bp, gimple_num_ops (stmt));
> +  bp_pack_value (&bp, gimple_no_warning_p (stmt), 1);
> +  if (is_gimple_assign (stmt))
> +    bp_pack_value (&bp, gimple_assign_nontemporal_move_p (stmt), 1);
> +  bp_pack_value (&bp, gimple_has_volatile_ops (stmt), 1);
> +  bp_pack_var_len_unsigned (&bp, stmt->gsbase.subcode);
> +  lto_output_bitpack (&bp);
> +
> +  /* Emit location information for the statement.  */
> +  lto_output_location (ob, gimple_location (stmt));
> +
> +  /* Emit the lexical block holding STMT.  */
> +  lto_output_tree (ob, gimple_block (stmt), true);
> +
> +  /* Emit the operands.  */
> +  switch (gimple_code (stmt))
> +    {
> +    case GIMPLE_RESX:
> +      output_sleb128 (ob, gimple_resx_region (stmt));
> +      break;
> +
> +    case GIMPLE_EH_MUST_NOT_THROW:
> +      lto_output_tree_ref (ob, gimple_eh_must_not_throw_fndecl (stmt));
> +      break;
> +
> +    case GIMPLE_EH_DISPATCH:
> +      output_sleb128 (ob, gimple_eh_dispatch_region (stmt));
> +      break;
> +
> +    case GIMPLE_ASM:
> +      lto_output_uleb128_stream (ob->main_stream, gimple_asm_ninputs (stmt));
> +      lto_output_uleb128_stream (ob->main_stream, gimple_asm_noutputs (stmt));
> +      lto_output_uleb128_stream (ob->main_stream, gimple_asm_nclobbers (stmt));
> +      lto_output_uleb128_stream (ob->main_stream, gimple_asm_nlabels (stmt));
> +      lto_output_string (ob, ob->main_stream, gimple_asm_string (stmt), true);
> +      /* Fallthru  */
> +
> +    case GIMPLE_ASSIGN:
> +    case GIMPLE_CALL:
> +    case GIMPLE_RETURN:
> +    case GIMPLE_SWITCH:
> +    case GIMPLE_LABEL:
> +    case GIMPLE_COND:
> +    case GIMPLE_GOTO:
> +    case GIMPLE_DEBUG:
> +      for (i = 0; i < gimple_num_ops (stmt); i++)
> +	{
> +	  tree op = gimple_op (stmt, i);
> +	  /* Wrap all uses of non-automatic variables inside MEM_REFs
> +	     so that we do not have to deal with type mismatches on
> +	     merged symbols during IL read in.  The first operand
> +	     of GIMPLE_DEBUG must be a decl, not MEM_REF, though.  */
> +	  if (op && (i || !is_gimple_debug (stmt)))
> +	    {
> +	      tree *basep = &op;
> +	      while (handled_component_p (*basep))
> +		basep = &TREE_OPERAND (*basep, 0);
> +	      if (TREE_CODE (*basep) == VAR_DECL
> +		  && !auto_var_in_fn_p (*basep, current_function_decl)
> +		  && !DECL_REGISTER (*basep))
> +		{
> +		  bool volatilep = TREE_THIS_VOLATILE (*basep);
> +		  *basep = build2 (MEM_REF, TREE_TYPE (*basep),
> +				   build_fold_addr_expr (*basep),
> +				   build_int_cst (build_pointer_type
> +						  (TREE_TYPE (*basep)), 0));
> +		  TREE_THIS_VOLATILE (*basep) = volatilep;
> +		}
> +	    }
> +	  lto_output_tree_ref (ob, op);
> +	}
> +      if (is_gimple_call (stmt))
> +	{
> +	  if (gimple_call_internal_p (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));
> +	}
> +      break;
> +
> +    case GIMPLE_NOP:
> +    case GIMPLE_PREDICT:
> +      break;
> +
> +    default:
> +      gcc_unreachable ();
> +    }
> +}
> +
> +
> +/* Output a basic block BB to the main stream in OB for this FN.  */
> +
> +void
> +output_bb (struct output_block *ob, basic_block bb, struct function *fn)
> +{
> +  gimple_stmt_iterator bsi = gsi_start_bb (bb);
> +
> +  output_record_start (ob,
> +		       (!gsi_end_p (bsi)) || phi_nodes (bb)
> +		        ? LTO_bb1
> +			: LTO_bb0);
> +
> +  output_uleb128 (ob, bb->index);
> +  output_sleb128 (ob, bb->count);
> +  output_sleb128 (ob, bb->loop_depth);
> +  output_sleb128 (ob, bb->frequency);
> +  output_sleb128 (ob, bb->flags);
> +
> +  if (!gsi_end_p (bsi) || phi_nodes (bb))
> +    {
> +      /* Output the statements.  The list of statements is terminated
> +	 with a zero.  */
> +      for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
> +	{
> +	  int region;
> +	  gimple stmt = gsi_stmt (bsi);
> +
> +	  output_gimple_stmt (ob, stmt);
> +
> +	  /* Emit the EH region holding STMT.  */
> +	  region = lookup_stmt_eh_lp_fn (fn, stmt);
> +	  if (region != 0)
> +	    {
> +	      output_record_start (ob, LTO_eh_region);
> +	      output_sleb128 (ob, region);
> +	    }
> +	  else
> +	    output_record_start (ob, LTO_null);
> +	}
> +
> +      output_record_start (ob, LTO_null);
> +
> +      for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
> +	{
> +	  gimple phi = gsi_stmt (bsi);
> +
> +	  /* Only emit PHIs for gimple registers.  PHI nodes for .MEM
> +	     will be filled in on reading when the SSA form is
> +	     updated.  */
> +	  if (is_gimple_reg (gimple_phi_result (phi)))
> +	    output_phi (ob, phi);
> +	}
> +
> +      output_record_start (ob, LTO_null);
> +    }
> +}
> diff --git a/gcc/gimple-streamer.h b/gcc/gimple-streamer.h
> new file mode 100644
> index 0000000..257fdbc
> --- /dev/null
> +++ b/gcc/gimple-streamer.h
> @@ -0,0 +1,36 @@
> +/* Data structures and functions for streaming GIMPLE.
> +
> +   Copyright 2011 Free Software Foundation, Inc.
> +   Contributed by Diego Novillo <dnovillo@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GCC_GIMPLE_STREAMER_H
> +#define GCC_GIMPLE_STREAMER_H
> +
> +#include "basic-block.h"
> +#include "function.h"
> +#include "lto-streamer.h"
> +
> +/* In gimple-streamer-in.c  */
> +void input_bb (struct lto_input_block *, enum LTO_tags, struct data_in *,
> +	       struct function *, int);
> +
> +/* In gimple-streamer-out.c  */
> +void output_bb (struct output_block *, basic_block, struct function *);
> +
> +#endif  /* GCC_GIMPLE_STREAMER_H  */
> diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
> index df96c99..bc65a45 100644
> --- a/gcc/ipa-inline-analysis.c
> +++ b/gcc/ipa-inline-analysis.c
> @@ -84,6 +84,8 @@ along with GCC; see the file COPYING3.  If not see
>  #include "tree-flow.h"
>  #include "ipa-prop.h"
>  #include "lto-streamer.h"
> +#include "data-streamer.h"
> +#include "tree-streamer.h"
>  #include "ipa-inline.h"
>  #include "alloc-pool.h"
>  
> diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
> index def34c3..7f9f547 100644
> --- a/gcc/ipa-prop.c
> +++ b/gcc/ipa-prop.c
> @@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
>  #include "tree-pretty-print.h"
>  #include "gimple-pretty-print.h"
>  #include "lto-streamer.h"
> +#include "data-streamer.h"
> +#include "tree-streamer.h"
>  
>  
>  /* Intermediate information about a parameter that is only useful during the
> diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
> index 0414273..4f02c7b 100644
> --- a/gcc/ipa-pure-const.c
> +++ b/gcc/ipa-pure-const.c
> @@ -54,6 +54,8 @@ along with GCC; see the file COPYING3.  If not see
>  #include "langhooks.h"
>  #include "target.h"
>  #include "lto-streamer.h"
> +#include "data-streamer.h"
> +#include "tree-streamer.h"
>  #include "cfgloop.h"
>  #include "tree-scalar-evolution.h"
>  #include "intl.h"
> diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
> index 9d9cb43..c4da1ff 100644
> --- a/gcc/lto-cgraph.c
> +++ b/gcc/lto-cgraph.c
> @@ -43,6 +43,8 @@ along with GCC; see the file COPYING3.  If not see
>  #include "output.h"
>  #include "pointer-set.h"
>  #include "lto-streamer.h"
> +#include "data-streamer.h"
> +#include "tree-streamer.h"
>  #include "gcov-io.h"
>  
>  static void output_varpool (cgraph_node_set, varpool_node_set);
> diff --git a/gcc/lto-section-in.c b/gcc/lto-section-in.c
> index 0c2c4c0..1c285fa 100644
> --- a/gcc/lto-section-in.c
> +++ b/gcc/lto-section-in.c
> @@ -63,115 +63,6 @@ const char *lto_section_name[LTO_N_SECTION_TYPES] =
>  };
>  
>  
> -/* Read an ULEB128 Number of IB.  */
> -
> -unsigned HOST_WIDE_INT
> -lto_input_uleb128 (struct lto_input_block *ib)
> -{
> -  unsigned HOST_WIDE_INT result = 0;
> -  int shift = 0;
> -  unsigned HOST_WIDE_INT byte;
> -
> -  while (true)
> -    {
> -      byte = lto_input_1_unsigned (ib);
> -      result |= (byte & 0x7f) << shift;
> -      shift += 7;
> -      if ((byte & 0x80) == 0)
> -	return result;
> -    }
> -}
> -
> -/* HOST_WIDEST_INT version of lto_input_uleb128.  IB is as in
> -   lto_input_uleb128.  */
> -
> -unsigned HOST_WIDEST_INT
> -lto_input_widest_uint_uleb128 (struct lto_input_block *ib)
> -{
> -  unsigned HOST_WIDEST_INT result = 0;
> -  int shift = 0;
> -  unsigned HOST_WIDEST_INT byte;
> -
> -  while (true)
> -    {
> -      byte = lto_input_1_unsigned (ib);
> -      result |= (byte & 0x7f) << shift;
> -      shift += 7;
> -      if ((byte & 0x80) == 0)
> -	return result;
> -    }
> -}
> -
> -/* Read an SLEB128 Number of IB.  */
> -
> -HOST_WIDE_INT
> -lto_input_sleb128 (struct lto_input_block *ib)
> -{
> -  HOST_WIDE_INT result = 0;
> -  int shift = 0;
> -  unsigned HOST_WIDE_INT byte;
> -
> -  while (true)
> -    {
> -      byte = lto_input_1_unsigned (ib);
> -      result |= (byte & 0x7f) << shift;
> -      shift += 7;
> -      if ((byte & 0x80) == 0)
> -	{
> -	  if ((shift < HOST_BITS_PER_WIDE_INT) && (byte & 0x40))
> -	    result |= - ((HOST_WIDE_INT)1 << shift);
> -
> -	  return result;
> -	}
> -    }
> -}
> -
> -
> -/* Unpack VAL from BP in a variant of uleb format.  */
> -
> -unsigned HOST_WIDE_INT
> -bp_unpack_var_len_unsigned (struct bitpack_d *bp)
> -{
> -  unsigned HOST_WIDE_INT result = 0;
> -  int shift = 0;
> -  unsigned HOST_WIDE_INT half_byte;
> -
> -  while (true)
> -    {
> -      half_byte = bp_unpack_value (bp, 4);
> -      result |= (half_byte & 0x7) << shift;
> -      shift += 3;
> -      if ((half_byte & 0x8) == 0)
> -	return result;
> -    }
> -}
> -
> -
> -/* Unpack VAL from BP in a variant of sleb format.  */
> -
> -HOST_WIDE_INT
> -bp_unpack_var_len_int (struct bitpack_d *bp)
> -{
> -  HOST_WIDE_INT result = 0;
> -  int shift = 0;
> -  unsigned HOST_WIDE_INT half_byte;
> -
> -  while (true)
> -    {
> -      half_byte = bp_unpack_value (bp, 4);
> -      result |= (half_byte & 0x7) << shift;
> -      shift += 3;
> -      if ((half_byte & 0x8) == 0)
> -	{
> -	  if ((shift < HOST_BITS_PER_WIDE_INT) && (half_byte & 0x4))
> -	    result |= - ((HOST_WIDE_INT)1 << shift);
> -
> -	  return result;
> -	}
> -    }
> -}
> -
> -
>  /* Hooks so that the ipa passes can call into the lto front end to get
>     sections.  */
>  
> diff --git a/gcc/lto-section-out.c b/gcc/lto-section-out.c
> index 55c9d8d..7f44d6e 100644
> --- a/gcc/lto-section-out.c
> +++ b/gcc/lto-section-out.c
> @@ -265,113 +265,6 @@ lto_output_data_stream (struct lto_output_stream *obs, const void *data,
>  }
>  
>  
> -/* Output an unsigned LEB128 quantity to OBS.  */
> -
> -void
> -lto_output_uleb128_stream (struct lto_output_stream *obs,
> -			   unsigned HOST_WIDE_INT work)
> -{
> -  do
> -    {
> -      unsigned int byte = (work & 0x7f);
> -      work >>= 7;
> -      if (work != 0)
> -	/* More bytes to follow.  */
> -	byte |= 0x80;
> -
> -      lto_output_1_stream (obs, byte);
> -    }
> -  while (work != 0);
> -}
> -
> -/* Identical to output_uleb128_stream above except using unsigned
> -   HOST_WIDEST_INT type.  For efficiency on host where unsigned HOST_WIDEST_INT
> -   is not native, we only use this if we know that HOST_WIDE_INT is not wide
> -   enough.  */
> -
> -void
> -lto_output_widest_uint_uleb128_stream (struct lto_output_stream *obs,
> -				       unsigned HOST_WIDEST_INT work)
> -{
> -  do
> -    {
> -      unsigned int byte = (work & 0x7f);
> -      work >>= 7;
> -      if (work != 0)
> -	/* More bytes to follow.  */
> -	byte |= 0x80;
> -
> -      lto_output_1_stream (obs, byte);
> -    }
> -  while (work != 0);
> -}
> -
> -
> -/* Output a signed LEB128 quantity.  */
> -
> -void
> -lto_output_sleb128_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
> -{
> -  int more, byte;
> -
> -  do
> -    {
> -      byte = (work & 0x7f);
> -      /* arithmetic shift */
> -      work >>= 7;
> -      more = !((work == 0 && (byte & 0x40) == 0)
> -	       || (work == -1 && (byte & 0x40) != 0));
> -      if (more)
> -	byte |= 0x80;
> -
> -      lto_output_1_stream (obs, byte);
> -    }
> -  while (more);
> -}
> -
> -
> -/* Pack WORK into BP in a variant of uleb format.  */
> -
> -void
> -bp_pack_var_len_unsigned (struct bitpack_d *bp, unsigned HOST_WIDE_INT work)
> -{
> -  do
> -    {
> -      unsigned int half_byte = (work & 0x7);
> -      work >>= 3;
> -      if (work != 0)
> -	/* More half_bytes to follow.  */
> -	half_byte |= 0x8;
> -
> -      bp_pack_value (bp, half_byte, 4);
> -    }
> -  while (work != 0);
> -}
> -
> -
> -/* Pack WORK into BP in a variant of sleb format.  */
> -
> -void
> -bp_pack_var_len_int (struct bitpack_d *bp, HOST_WIDE_INT work)
> -{
> -  int more, half_byte;
> -
> -  do
> -    {
> -      half_byte = (work & 0x7);
> -      /* arithmetic shift */
> -      work >>= 3;
> -      more = !((work == 0 && (half_byte & 0x4) == 0)
> -	       || (work == -1 && (half_byte & 0x4) != 0));
> -      if (more)
> -	half_byte |= 0x8;
> -
> -      bp_pack_value (bp, half_byte, 4);
> -    }
> -  while (more);
> -}
> -
> -
>  /* Lookup NAME in ENCODER.  If NAME is not found, create a new entry in
>     ENCODER for NAME with the next available index of ENCODER,  then
>     print the index to OBS.  True is returned if NAME was added to
> diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
> index d249033..1330d60 100644
> --- a/gcc/lto-streamer-in.c
> +++ b/gcc/lto-streamer-in.c
> @@ -45,16 +45,12 @@ along with GCC; see the file COPYING3.  If not see
>  #include "timevar.h"
>  #include "output.h"
>  #include "ipa-utils.h"
> +#include "data-streamer.h"
> +#include "gimple-streamer.h"
>  #include "lto-streamer.h"
> +#include "tree-streamer.h"
>  #include "tree-pass.h"
>  
> -/* Data structure used to hash file names in the source_location field.  */
> -struct string_slot
> -{
> -  const char *s;
> -  unsigned int slot_num;
> -};
> -
>  /* The table to hold the file names.  */
>  static htab_t file_name_hash_table;
>  
> @@ -62,7 +58,7 @@ static htab_t file_name_hash_table;
>  /* Check that tag ACTUAL has one of the given values.  NUM_TAGS is the
>     number of valid tag values to check.  */
>  
> -static void
> +void
>  lto_tag_check_set (enum LTO_tags actual, int ntags, ...)
>  {
>    va_list ap;
> @@ -81,128 +77,6 @@ lto_tag_check_set (enum LTO_tags actual, int ntags, ...)
>  }
>  
>  
> -/* Check that tag ACTUAL is in the range [TAG1, TAG2].  */
> -
> -static void
> -lto_tag_check_range (enum LTO_tags actual, enum LTO_tags tag1,
> -		     enum LTO_tags tag2)
> -{
> -  if (actual < tag1 || actual > tag2)
> -    internal_error ("bytecode stream: tag %s is not in the expected range "
> -		    "[%s, %s]",
> -		    lto_tag_name (actual),
> -		    lto_tag_name (tag1),
> -		    lto_tag_name (tag2));
> -}
> -
> -
> -/* Check that tag ACTUAL == EXPECTED.  */
> -
> -static void
> -lto_tag_check (enum LTO_tags actual, enum LTO_tags expected)
> -{
> -  if (actual != expected)
> -    internal_error ("bytecode stream: expected tag %s instead of %s",
> -		    lto_tag_name (expected), lto_tag_name (actual));
> -}
> -
> -
> -/* Return a hash code for P.  */
> -
> -static hashval_t
> -hash_string_slot_node (const void *p)
> -{
> -  const struct string_slot *ds = (const struct string_slot *) p;
> -  return (hashval_t) htab_hash_string (ds->s);
> -}
> -
> -
> -/* Returns nonzero if P1 and P2 are equal.  */
> -
> -static int
> -eq_string_slot_node (const void *p1, const void *p2)
> -{
> -  const struct string_slot *ds1 = (const struct string_slot *) p1;
> -  const struct string_slot *ds2 = (const struct string_slot *) p2;
> -  return strcmp (ds1->s, ds2->s) == 0;
> -}
> -
> -
> -/* Read a string from the string table in DATA_IN using input block
> -   IB.  Write the length to RLEN.  */
> -
> -static const char *
> -string_for_index (struct data_in *data_in,
> -		  unsigned int loc,
> -		  unsigned int *rlen)
> -{
> -  struct lto_input_block str_tab;
> -  unsigned int len;
> -  const char *result;
> -
> -  if (!loc)
> -    {
> -      *rlen = 0;
> -      return NULL;
> -    }
> -
> -  /* Get the string stored at location LOC in DATA_IN->STRINGS.  */
> -  LTO_INIT_INPUT_BLOCK (str_tab, data_in->strings, loc - 1, data_in->strings_len);
> -  len = lto_input_uleb128 (&str_tab);
> -  *rlen = len;
> -
> -  if (str_tab.p + len > data_in->strings_len)
> -    internal_error ("bytecode stream: string too long for the string table");
> -
> -  result = (const char *)(data_in->strings + str_tab.p);
> -
> -  return result;
> -}
> -
> -
> -/* Read a string from the string table in DATA_IN using input block
> -   IB.  Write the length to RLEN.  */
> -
> -static const char *
> -input_string_internal (struct data_in *data_in, struct lto_input_block *ib,
> -		       unsigned int *rlen)
> -{
> -  return string_for_index (data_in, lto_input_uleb128 (ib), rlen);
> -}
> -
> -
> -/* Read a STRING_CST from the string table in DATA_IN using input
> -   block IB.  */
> -
> -static tree
> -input_string_cst (struct data_in *data_in, struct lto_input_block *ib)
> -{
> -  unsigned int len;
> -  const char * ptr;
> -
> -  ptr = input_string_internal (data_in, ib, &len);
> -  if (!ptr)
> -    return NULL;
> -  return build_string (len, ptr);
> -}
> -
> -
> -/* Read an IDENTIFIER from the string table in DATA_IN using input
> -   block IB.  */
> -
> -static tree
> -input_identifier (struct data_in *data_in, struct lto_input_block *ib)
> -{
> -  unsigned int len;
> -  const char *ptr;
> -
> -  ptr = input_string_internal (data_in, ib, &len);
> -  if (!ptr)
> -    return NULL;
> -  return get_identifier_with_length (ptr, len);
> -}
> -
> -
>  /* Read LENGTH bytes from STREAM to ADDR.  */
>  
>  void
> @@ -216,33 +90,6 @@ lto_input_data_block (struct lto_input_block *ib, void *addr, size_t length)
>  }
>  
>  
> -/* Read a NULL terminated string from the string table in DATA_IN.  */
> -
> -const char *
> -lto_input_string (struct data_in *data_in, struct lto_input_block *ib)
> -{
> -  unsigned int len;
> -  const char *ptr;
> -
> -  ptr = input_string_internal (data_in, ib, &len);
> -  if (!ptr)
> -    return NULL;
> -  if (ptr[len - 1] != '\0')
> -    internal_error ("bytecode stream: found non-null terminated string");
> -
> -  return ptr;
> -}
> -
> -
> -/* Return the next tag in the input block IB.  */
> -
> -static inline enum LTO_tags
> -input_record_start (struct lto_input_block *ib)
> -{
> -  return lto_input_enum (ib, LTO_tags, LTO_NUM_TAGS);
> -}
> -
> -
>  /* Lookup STRING in file_name_hash_table.  If found, return the existing
>     string, otherwise insert STRING as the canonical version.  */
>  
> @@ -252,6 +99,7 @@ canon_file_name (const char *string)
>    void **slot;
>    struct string_slot s_slot;
>    s_slot.s = string;
> +  s_slot.len = strlen (string);
>  
>    slot = htab_find_slot (file_name_hash_table, &s_slot, INSERT);
>    if (*slot == NULL)
> @@ -333,7 +181,7 @@ lto_input_location_bitpack (struct data_in *data_in, struct bitpack_d *bp)
>  
>  /* Read a location from input block IB.  */
>  
> -static location_t
> +location_t
>  lto_input_location (struct lto_input_block *ib, struct data_in *data_in)
>  {
>    struct bitpack_d bp;
> @@ -350,7 +198,7 @@ lto_input_location (struct lto_input_block *ib, struct data_in *data_in)
>     representation of the tree using lto_input_tree.  FN is the
>     function scope for the read tree.  */
>  
> -static tree
> +tree
>  lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
>  		    struct function *fn, enum LTO_tags tag)
>  {
> @@ -411,33 +259,6 @@ lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
>  }
>  
>  
> -/* Read a chain of tree nodes from input block IB. DATA_IN contains
> -   tables and descriptors for the file being read.  */
> -
> -static tree
> -lto_input_chain (struct lto_input_block *ib, struct data_in *data_in)
> -{
> -  int i, count;
> -  tree first, prev, curr;
> -
> -  first = prev = NULL_TREE;
> -  count = lto_input_sleb128 (ib);
> -  for (i = 0; i < count; i++)
> -    {
> -      curr = lto_input_tree (ib, data_in);
> -      if (prev)
> -	TREE_CHAIN (prev) = curr;
> -      else
> -	first = curr;
> -
> -      TREE_CHAIN (curr) = NULL_TREE;
> -      prev = curr;
> -    }
> -
> -  return first;
> -}
> -
> -
>  /* Read and return a double-linked list of catch handlers from input
>     block IB, using descriptors in DATA_IN.  */
>  
> @@ -641,7 +462,7 @@ fixup_eh_region_pointers (struct function *fn, HOST_WIDE_INT root_region)
>  
>  /* Initialize EH support.  */
>  
> -static void
> +void
>  lto_init_eh (void)
>  {
>    static bool eh_initialized_p = false;
> @@ -856,51 +677,6 @@ input_cfg (struct lto_input_block *ib, struct function *fn,
>  }
>  
>  
> -/* Read a PHI function for basic block BB in function FN.  DATA_IN is
> -   the file being read.  IB is the input block to use for reading.  */
> -
> -static gimple
> -input_phi (struct lto_input_block *ib, basic_block bb, struct data_in *data_in,
> -	   struct function *fn)
> -{
> -  unsigned HOST_WIDE_INT ix;
> -  tree phi_result;
> -  int i, len;
> -  gimple result;
> -
> -  ix = lto_input_uleb128 (ib);
> -  phi_result = VEC_index (tree, SSANAMES (fn), ix);
> -  len = EDGE_COUNT (bb->preds);
> -  result = create_phi_node (phi_result, bb);
> -  SSA_NAME_DEF_STMT (phi_result) = result;
> -
> -  /* We have to go through a lookup process here because the preds in the
> -     reconstructed graph are generally in a different order than they
> -     were in the original program.  */
> -  for (i = 0; i < len; i++)
> -    {
> -      tree def = lto_input_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);
> -
> -      edge e = NULL;
> -      int j;
> -
> -      for (j = 0; j < len; j++)
> -	if (EDGE_PRED (bb, j)->src == sbb)
> -	  {
> -	    e = EDGE_PRED (bb, j);
> -	    break;
> -	  }
> -
> -      add_phi_arg (result, def, e, arg_loc);
> -    }
> -
> -  return result;
> -}
> -
> -
>  /* Read the SSA names array for function FN from DATA_IN using input
>     block IB.  */
>  
> @@ -934,263 +710,6 @@ input_ssa_names (struct lto_input_block *ib, struct data_in *data_in,
>      }
>  }
>  
> -/* Read a statement with tag TAG in function FN from block IB using
> -   descriptors in DATA_IN.  */
> -
> -static gimple
> -input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
> -		   struct function *fn, enum LTO_tags tag)
> -{
> -  gimple stmt;
> -  enum gimple_code code;
> -  unsigned HOST_WIDE_INT num_ops;
> -  size_t i;
> -  struct bitpack_d bp;
> -
> -  code = lto_tag_to_gimple_code (tag);
> -
> -  /* Read the tuple header.  */
> -  bp = lto_input_bitpack (ib);
> -  num_ops = bp_unpack_var_len_unsigned (&bp);
> -  stmt = gimple_alloc (code, num_ops);
> -  stmt->gsbase.no_warning = bp_unpack_value (&bp, 1);
> -  if (is_gimple_assign (stmt))
> -    stmt->gsbase.nontemporal_move = bp_unpack_value (&bp, 1);
> -  stmt->gsbase.has_volatile_ops = bp_unpack_value (&bp, 1);
> -  stmt->gsbase.subcode = bp_unpack_var_len_unsigned (&bp);
> -
> -  /* Read location information.  */
> -  gimple_set_location (stmt, lto_input_location (ib, data_in));
> -
> -  /* Read lexical block reference.  */
> -  gimple_set_block (stmt, lto_input_tree (ib, data_in));
> -
> -  /* Read in all the operands.  */
> -  switch (code)
> -    {
> -    case GIMPLE_RESX:
> -      gimple_resx_set_region (stmt, lto_input_sleb128 (ib));
> -      break;
> -
> -    case GIMPLE_EH_MUST_NOT_THROW:
> -      gimple_eh_must_not_throw_set_fndecl (stmt, lto_input_tree (ib, data_in));
> -      break;
> -
> -    case GIMPLE_EH_DISPATCH:
> -      gimple_eh_dispatch_set_region (stmt, lto_input_sleb128 (ib));
> -      break;
> -
> -    case GIMPLE_ASM:
> -      {
> -	/* FIXME lto.  Move most of this into a new gimple_asm_set_string().  */
> -	tree str;
> -	stmt->gimple_asm.ni = lto_input_uleb128 (ib);
> -	stmt->gimple_asm.no = lto_input_uleb128 (ib);
> -	stmt->gimple_asm.nc = lto_input_uleb128 (ib);
> -	stmt->gimple_asm.nl = lto_input_uleb128 (ib);
> -	str = input_string_cst (data_in, ib);
> -	stmt->gimple_asm.string = TREE_STRING_POINTER (str);
> -      }
> -      /* Fallthru  */
> -
> -    case GIMPLE_ASSIGN:
> -    case GIMPLE_CALL:
> -    case GIMPLE_RETURN:
> -    case GIMPLE_SWITCH:
> -    case GIMPLE_LABEL:
> -    case GIMPLE_COND:
> -    case GIMPLE_GOTO:
> -    case GIMPLE_DEBUG:
> -      for (i = 0; i < num_ops; i++)
> -	{
> -	  tree op = lto_input_tree (ib, data_in);
> -	  gimple_set_op (stmt, i, op);
> -	  if (!op)
> -	    continue;
> -
> -	  /* Fixup FIELD_DECLs in COMPONENT_REFs, they are not handled
> -	     by decl merging.  */
> -	  if (TREE_CODE (op) == ADDR_EXPR)
> -	    op = TREE_OPERAND (op, 0);
> -	  while (handled_component_p (op))
> -	    {
> -	      if (TREE_CODE (op) == COMPONENT_REF)
> -		{
> -		  tree field, type, tem;
> -		  tree closest_match = NULL_TREE;
> -		  field = TREE_OPERAND (op, 1);
> -		  type = DECL_CONTEXT (field);
> -		  for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
> -		    {
> -		      if (tem == field)
> -			break;
> -		      if (DECL_NONADDRESSABLE_P (tem)
> -			  == DECL_NONADDRESSABLE_P (field)
> -			  && gimple_compare_field_offset (tem, field))
> -			{
> -			  if (types_compatible_p (TREE_TYPE (tem),
> -						  TREE_TYPE (field)))
> -			    break;
> -			  else
> -			    closest_match = tem;
> -			}
> -		    }
> -		  /* In case of type mismatches across units we can fail
> -		     to unify some types and thus not find a proper
> -		     field-decl here.  */
> -		  if (tem == NULL_TREE)
> -		    {
> -		      /* Thus, emit a ODR violation warning.  */
> -		      if (warning_at (gimple_location (stmt), 0,
> -				      "use of type %<%E%> with two mismatching "
> -				      "declarations at field %<%E%>",
> -				      type, TREE_OPERAND (op, 1)))
> -			{
> -			  if (TYPE_FIELDS (type))
> -			    inform (DECL_SOURCE_LOCATION (TYPE_FIELDS (type)),
> -				    "original type declared here");
> -			  inform (DECL_SOURCE_LOCATION (TREE_OPERAND (op, 1)),
> -				  "field in mismatching type declared here");
> -			  if (TYPE_NAME (TREE_TYPE (field))
> -			      && (TREE_CODE (TYPE_NAME (TREE_TYPE (field)))
> -				  == TYPE_DECL))
> -			    inform (DECL_SOURCE_LOCATION
> -				      (TYPE_NAME (TREE_TYPE (field))),
> -				    "type of field declared here");
> -			  if (closest_match
> -			      && TYPE_NAME (TREE_TYPE (closest_match))
> -			      && (TREE_CODE (TYPE_NAME
> -				   (TREE_TYPE (closest_match))) == TYPE_DECL))
> -			    inform (DECL_SOURCE_LOCATION
> -				      (TYPE_NAME (TREE_TYPE (closest_match))),
> -				    "type of mismatching field declared here");
> -			}
> -		      /* And finally fixup the types.  */
> -		      TREE_OPERAND (op, 0)
> -			= build1 (VIEW_CONVERT_EXPR, type,
> -				  TREE_OPERAND (op, 0));
> -		    }
> -		  else
> -		    TREE_OPERAND (op, 1) = tem;
> -		}
> -
> -	      op = TREE_OPERAND (op, 0);
> -	    }
> -	}
> -      if (is_gimple_call (stmt))
> -	{
> -	  if (gimple_call_internal_p (stmt))
> -	    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));
> -	}
> -      break;
> -
> -    case GIMPLE_NOP:
> -    case GIMPLE_PREDICT:
> -      break;
> -
> -    default:
> -      internal_error ("bytecode stream: unknown GIMPLE statement tag %s",
> -		      lto_tag_name (tag));
> -    }
> -
> -  /* Update the properties of symbols, SSA names and labels associated
> -     with STMT.  */
> -  if (code == GIMPLE_ASSIGN || code == GIMPLE_CALL)
> -    {
> -      tree lhs = gimple_get_lhs (stmt);
> -      if (lhs && TREE_CODE (lhs) == SSA_NAME)
> -	SSA_NAME_DEF_STMT (lhs) = stmt;
> -    }
> -  else if (code == GIMPLE_LABEL)
> -    gcc_assert (emit_label_in_global_context_p (gimple_label_label (stmt))
> -	        || DECL_CONTEXT (gimple_label_label (stmt)) == fn->decl);
> -  else if (code == GIMPLE_ASM)
> -    {
> -      unsigned i;
> -
> -      for (i = 0; i < gimple_asm_noutputs (stmt); i++)
> -	{
> -	  tree op = TREE_VALUE (gimple_asm_output_op (stmt, i));
> -	  if (TREE_CODE (op) == SSA_NAME)
> -	    SSA_NAME_DEF_STMT (op) = stmt;
> -	}
> -    }
> -
> -  /* Reset alias information.  */
> -  if (code == GIMPLE_CALL)
> -    gimple_call_reset_alias_info (stmt);
> -
> -  /* Mark the statement modified so its operand vectors can be filled in.  */
> -  gimple_set_modified (stmt, true);
> -
> -  return stmt;
> -}
> -
> -
> -/* Read a basic block with tag TAG from DATA_IN using input block IB.
> -   FN is the function being processed.  */
> -
> -static void
> -input_bb (struct lto_input_block *ib, enum LTO_tags tag,
> -	  struct data_in *data_in, struct function *fn,
> -	  int count_materialization_scale)
> -{
> -  unsigned int index;
> -  basic_block bb;
> -  gimple_stmt_iterator bsi;
> -
> -  /* This routine assumes that CFUN is set to FN, as it needs to call
> -     basic GIMPLE routines that use CFUN.  */
> -  gcc_assert (cfun == fn);
> -
> -  index = lto_input_uleb128 (ib);
> -  bb = BASIC_BLOCK_FOR_FUNCTION (fn, index);
> -
> -  bb->count = (lto_input_sleb128 (ib) * count_materialization_scale
> -	       + REG_BR_PROB_BASE / 2) / REG_BR_PROB_BASE;
> -  bb->loop_depth = lto_input_sleb128 (ib);
> -  bb->frequency = lto_input_sleb128 (ib);
> -  bb->flags = lto_input_sleb128 (ib);
> -
> -  /* LTO_bb1 has statements.  LTO_bb0 does not.  */
> -  if (tag == LTO_bb0)
> -    return;
> -
> -  bsi = gsi_start_bb (bb);
> -  tag = input_record_start (ib);
> -  while (tag)
> -    {
> -      gimple stmt = input_gimple_stmt (ib, data_in, fn, tag);
> -      if (!is_gimple_debug (stmt))
> -	find_referenced_vars_in (stmt);
> -      gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
> -
> -      /* After the statement, expect a 0 delimiter or the EH region
> -	 that the previous statement belongs to.  */
> -      tag = input_record_start (ib);
> -      lto_tag_check_set (tag, 2, LTO_eh_region, LTO_null);
> -
> -      if (tag == LTO_eh_region)
> -	{
> -	  HOST_WIDE_INT region = lto_input_sleb128 (ib);
> -	  gcc_assert (region == (int) region);
> -	  add_stmt_to_eh_lp (stmt, region);
> -	}
> -
> -      tag = input_record_start (ib);
> -    }
> -
> -  tag = input_record_start (ib);
> -  while (tag)
> -    {
> -      gimple phi = input_phi (ib, bb, data_in, fn);
> -      find_referenced_vars_in (phi);
> -      tag = input_record_start (ib);
> -    }
> -}
>  
>  /* Go through all NODE edges and fixup call_stmt pointers
>     so they point to STMTS.  */
> @@ -1525,994 +1044,13 @@ lto_input_constructors_and_inits (struct lto_file_decl_data *file_data,
>  }
>  
>  
> -/* Unpack all the non-pointer fields of the TS_BASE structure of
> -   expression EXPR from bitpack BP.  */
> -
> -static void
> -unpack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  /* Note that the code for EXPR has already been unpacked to create EXPR in
> -     lto_materialize_tree.  */
> -  if (!TYPE_P (expr))
> -    {
> -      TREE_SIDE_EFFECTS (expr) = (unsigned) bp_unpack_value (bp, 1);
> -      TREE_CONSTANT (expr) = (unsigned) bp_unpack_value (bp, 1);
> -      TREE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1);
> -
> -      /* TREE_PUBLIC is used on types to indicate that the type
> -	 has a TYPE_CACHED_VALUES vector.  This is not streamed out,
> -	 so we skip it here.  */
> -      TREE_PUBLIC (expr) = (unsigned) bp_unpack_value (bp, 1);
> -    }
> -  else
> -    bp_unpack_value (bp, 4);
> -  TREE_ADDRESSABLE (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  TREE_THIS_VOLATILE (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  if (DECL_P (expr))
> -    DECL_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  else if (TYPE_P (expr))
> -    TYPE_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  else
> -    bp_unpack_value (bp, 1);
> -  TREE_ASM_WRITTEN (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  if (TYPE_P (expr))
> -    TYPE_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  else
> -    TREE_NO_WARNING (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  TREE_USED (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  TREE_NOTHROW (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  TREE_STATIC (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  TREE_PRIVATE (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  TREE_PROTECTED (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  TREE_DEPRECATED (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  if (TYPE_P (expr))
> -    TYPE_SATURATING (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  else if (TREE_CODE (expr) == SSA_NAME)
> -    SSA_NAME_IS_DEFAULT_DEF (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  else
> -    bp_unpack_value (bp, 1);
> -}
> -
> -
> -/* Unpack all the non-pointer fields of the TS_REAL_CST structure of
> -   expression EXPR from bitpack BP.  */
> -
> -static void
> -unpack_ts_real_cst_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  unsigned i;
> -  REAL_VALUE_TYPE r;
> -  REAL_VALUE_TYPE *rp;
> -
> -  r.cl = (unsigned) bp_unpack_value (bp, 2);
> -  r.decimal = (unsigned) bp_unpack_value (bp, 1);
> -  r.sign = (unsigned) bp_unpack_value (bp, 1);
> -  r.signalling = (unsigned) bp_unpack_value (bp, 1);
> -  r.canonical = (unsigned) bp_unpack_value (bp, 1);
> -  r.uexp = (unsigned) bp_unpack_value (bp, EXP_BITS);
> -  for (i = 0; i < SIGSZ; i++)
> -    r.sig[i] = (unsigned long) bp_unpack_value (bp, HOST_BITS_PER_LONG);
> -
> -  rp = ggc_alloc_real_value ();
> -  memcpy (rp, &r, sizeof (REAL_VALUE_TYPE));
> -  TREE_REAL_CST_PTR (expr) = rp;
> -}
> -
> -
> -/* Unpack all the non-pointer fields of the TS_FIXED_CST structure of
> -   expression EXPR from bitpack BP.  */
> -
> -static void
> -unpack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  struct fixed_value fv;
> -
> -  fv.mode = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
> -  fv.data.low = bp_unpack_var_len_int (bp);
> -  fv.data.high = bp_unpack_var_len_int (bp);
> -  TREE_FIXED_CST (expr) = fv;
> -}
> -
> -
> -/* Unpack all the non-pointer fields of the TS_DECL_COMMON structure
> -   of expression EXPR from bitpack BP.  */
> -
> -static void
> -unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  DECL_MODE (expr) = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
> -  DECL_NONLOCAL (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_VIRTUAL_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_IGNORED_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_ABSTRACT (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_USER_ALIGN (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_PRESERVE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_DEBUG_EXPR_IS_FROM (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_EXTERNAL (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_GIMPLE_REG_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_ALIGN (expr) = (unsigned) bp_unpack_var_len_unsigned (bp);
> -
> -  if (TREE_CODE (expr) == LABEL_DECL)
> -    {
> -      DECL_ERROR_ISSUED (expr) = (unsigned) bp_unpack_value (bp, 1);
> -      EH_LANDING_PAD_NR (expr) = (int) bp_unpack_var_len_unsigned (bp);
> -
> -      /* Always assume an initial value of -1 for LABEL_DECL_UID to
> -	 force gimple_set_bb to recreate label_to_block_map.  */
> -      LABEL_DECL_UID (expr) = -1;
> -    }
> -
> -  if (TREE_CODE (expr) == FIELD_DECL)
> -    {
> -      DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
> -      DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> -      expr->decl_common.off_align = bp_unpack_value (bp, 8);
> -    }
> -
> -  if (TREE_CODE (expr) == RESULT_DECL
> -      || TREE_CODE (expr) == PARM_DECL
> -      || TREE_CODE (expr) == VAR_DECL)
> -    {
> -      DECL_BY_REFERENCE (expr) = (unsigned) bp_unpack_value (bp, 1);
> -      if (TREE_CODE (expr) == VAR_DECL
> -	  || TREE_CODE (expr) == PARM_DECL)
> -	DECL_HAS_VALUE_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> -      DECL_RESTRICTED_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> -    }
> -}
> -
> -
> -/* Unpack all the non-pointer fields of the TS_DECL_WRTL structure
> -   of expression EXPR from bitpack BP.  */
> -
> -static void
> -unpack_ts_decl_wrtl_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  DECL_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1);
> -}
> -
> -
> -/* Unpack all the non-pointer fields of the TS_DECL_WITH_VIS structure
> -   of expression EXPR from bitpack BP.  */
> -
> -static void
> -unpack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  DECL_DEFER_OUTPUT (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_COMMON (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_DLLIMPORT_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_WEAK (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_SEEN_IN_BIND_EXPR_P (expr) = (unsigned) bp_unpack_value (bp,  1);
> -  DECL_COMDAT (expr) = (unsigned) bp_unpack_value (bp,  1);
> -  DECL_VISIBILITY (expr) = (enum symbol_visibility) bp_unpack_value (bp,  2);
> -  DECL_VISIBILITY_SPECIFIED (expr) = (unsigned) bp_unpack_value (bp,  1);
> -
> -  if (TREE_CODE (expr) == VAR_DECL)
> -    {
> -      DECL_HARD_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1);
> -      DECL_IN_TEXT_SECTION (expr) = (unsigned) bp_unpack_value (bp, 1);
> -      DECL_IN_CONSTANT_POOL (expr) = (unsigned) bp_unpack_value (bp, 1);
> -      DECL_TLS_MODEL (expr) = (enum tls_model) bp_unpack_value (bp,  3);
> -    }
> -
> -  if (VAR_OR_FUNCTION_DECL_P (expr))
> -    {
> -      priority_type p;
> -      p = (priority_type) bp_unpack_var_len_unsigned (bp);
> -      SET_DECL_INIT_PRIORITY (expr, p);
> -    }
> -}
> -
> -
> -/* Unpack all the non-pointer fields of the TS_FUNCTION_DECL structure
> -   of expression EXPR from bitpack BP.  */
> -
> -static void
> -unpack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  DECL_BUILT_IN_CLASS (expr) = bp_unpack_enum (bp, built_in_class,
> -					       BUILT_IN_LAST);
> -  DECL_STATIC_CONSTRUCTOR (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_STATIC_DESTRUCTOR (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_UNINLINABLE (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_POSSIBLY_INLINED (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_IS_NOVOPS (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_IS_RETURNS_TWICE (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_IS_MALLOC (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_IS_OPERATOR_NEW (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_DECLARED_INLINE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_STATIC_CHAIN (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_NO_INLINE_WARNING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr)
> -    			= (unsigned) bp_unpack_value (bp, 1);
> -  DECL_NO_LIMIT_STACK (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_DISREGARD_INLINE_LIMITS (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  DECL_LOOPING_CONST_OR_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  if (DECL_BUILT_IN_CLASS (expr) != NOT_BUILT_IN)
> -    {
> -      DECL_FUNCTION_CODE (expr) = (enum built_in_function) bp_unpack_value (bp, 11);
> -      if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_NORMAL
> -	  && DECL_FUNCTION_CODE (expr) >= END_BUILTINS)
> -	fatal_error ("machine independent builtin code out of range");
> -      else if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD)
> -	{
> -          tree result = targetm.builtin_decl (DECL_FUNCTION_CODE (expr), true);
> -	  if (!result || result == error_mark_node)
> -	    fatal_error ("target specific builtin not available");
> -	}
> -    }
> -  if (DECL_STATIC_DESTRUCTOR (expr))
> -    {
> -      priority_type p;
> -      p = (priority_type) bp_unpack_var_len_unsigned (bp);
> -      SET_DECL_FINI_PRIORITY (expr, p);
> -    }
> -}
> -
> -
> -/* Unpack all the non-pointer fields of the TS_TYPE_COMMON structure
> -   of expression EXPR from bitpack BP.  */
> +/* 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.  */
>  
> -static void
> -unpack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  enum machine_mode mode;
> -
> -  mode = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
> -  SET_TYPE_MODE (expr, mode);
> -  TYPE_STRING_FLAG (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  TYPE_NO_FORCE_BLK (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  TYPE_NEEDS_CONSTRUCTING (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  if (RECORD_OR_UNION_TYPE_P (expr))
> -    TYPE_TRANSPARENT_AGGR (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  TYPE_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  TYPE_RESTRICT (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr)
> -    	= (unsigned) bp_unpack_value (bp, 2);
> -  TYPE_USER_ALIGN (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  TYPE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  TYPE_PRECISION (expr) = bp_unpack_var_len_unsigned (bp);
> -  TYPE_ALIGN (expr) = bp_unpack_var_len_unsigned (bp);
> -  TYPE_ALIAS_SET (expr) = bp_unpack_var_len_int (bp);
> -}
> -
> -
> -/* Unpack all the non-pointer fields of the TS_BLOCK structure
> -   of expression EXPR from bitpack BP.  */
> -
> -static void
> -unpack_ts_block_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  BLOCK_ABSTRACT (expr) = (unsigned) bp_unpack_value (bp, 1);
> -  /* BLOCK_NUMBER is recomputed.  */
> -}
> -
> -/* Unpack all the non-pointer fields of the TS_TRANSLATION_UNIT_DECL
> -   structure of expression EXPR from bitpack BP.  */
> -
> -static void
> -unpack_ts_translation_unit_decl_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED, tree expr ATTRIBUTE_UNUSED)
> -{
> -}
> -
> -/* Unpack all the non-pointer fields in EXPR into a bit pack.  */
> -
> -static void
> -unpack_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  enum tree_code code;
> -
> -  code = TREE_CODE (expr);
> -
> -  /* Note that all these functions are highly sensitive to changes in
> -     the types and sizes of each of the fields being packed.  */
> -  unpack_ts_base_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
> -    unpack_ts_real_cst_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_FIXED_CST))
> -    unpack_ts_fixed_cst_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
> -    unpack_ts_decl_common_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL))
> -    unpack_ts_decl_wrtl_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
> -    unpack_ts_decl_with_vis_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
> -    unpack_ts_function_decl_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
> -    unpack_ts_type_common_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
> -    unpack_ts_block_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
> -    unpack_ts_translation_unit_decl_value_fields (bp, expr);
> -
> -  if (streamer_hooks.unpack_value_fields)
> -    streamer_hooks.unpack_value_fields (bp, expr);
> -}
> -
> -
> -/* Materialize a new tree from input block IB using descriptors in
> -   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
> -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
> -  HOST_WIDEST_INT orig_address_in_writer;
> -#endif
> -
> -  result = NULL_TREE;
> -
> -#ifdef LTO_STREAMER_DEBUG
> -  /* Read the word representing the memory address for the tree
> -     as it was written by the writer.  This is useful when
> -     debugging differences between the writer and reader.  */
> -  orig_address_in_writer = lto_input_sleb128 (ib);
> -  gcc_assert ((intptr_t) orig_address_in_writer == orig_address_in_writer);
> -#endif
> -
> -  code = lto_tag_to_tree_code (tag);
> -
> -  /* We should never see an SSA_NAME tree.  Only the version numbers of
> -     SSA names are ever written out.  See input_ssa_names.  */
> -  gcc_assert (code != SSA_NAME);
> -
> -  /* Instantiate a new tree using the header data.  */
> -  if (CODE_CONTAINS_STRUCT (code, TS_STRING))
> -    result = input_string_cst (data_in, ib);
> -  else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER))
> -    result = input_identifier (data_in, ib);
> -  else if (CODE_CONTAINS_STRUCT (code, TS_VEC))
> -    {
> -      HOST_WIDE_INT len = lto_input_sleb128 (ib);
> -      result = make_tree_vec (len);
> -    }
> -  else if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
> -    {
> -      unsigned HOST_WIDE_INT len = lto_input_uleb128 (ib);
> -      result = make_tree_binfo (len);
> -    }
> -  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
> -	 make_node call.  */
> -      if (result == NULL_TREE)
> -	result = make_node (code);
> -    }
> -
> -#ifdef LTO_STREAMER_DEBUG
> -  /* Store the original address of the tree as seen by the writer
> -     in RESULT's aux field.  This is useful when debugging streaming
> -     problems.  This way, a debugging session can be started on
> -     both writer and reader with a breakpoint using this address
> -     value in both.  */
> -  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;
> -}
> -
> -
> -/* Read all pointer fields in the TS_COMMON structure of EXPR from input
> -   block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -
> -static void
> -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);
> -}
> -
> -
> -/* Read all pointer fields in the TS_VECTOR structure of EXPR from input
> -   block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -static void
> -lto_input_ts_vector_tree_pointers (struct lto_input_block *ib,
> -				   struct data_in *data_in, tree expr)
> -{
> -  TREE_VECTOR_CST_ELTS (expr) = lto_input_chain (ib, data_in);
> -}
> -
> -
> -/* Read all pointer fields in the TS_COMPLEX structure of EXPR from input
> -   block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -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);
> -}
> -
> -
> -/* Read all pointer fields in the TS_DECL_MINIMAL structure of EXPR
> -   from input block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -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_SOURCE_LOCATION (expr) = lto_input_location (ib, data_in);
> -}
> -
> -
> -/* Read all pointer fields in the TS_DECL_COMMON structure of EXPR from
> -   input block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -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);
> -
> -  /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
> -     for early inlining so drop it on the floor instead of ICEing in
> -     dwarf2out.c.  */
> -
> -  if (TREE_CODE (expr) == PARM_DECL)
> -    TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
> -
> -  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));
> -
> -  if (TREE_CODE (expr) == VAR_DECL)
> -    {
> -      tree dexpr = lto_input_tree (ib, data_in);
> -      if (dexpr)
> -	SET_DECL_DEBUG_EXPR (expr, dexpr);
> -    }
> -}
> -
> -
> -/* Read all pointer fields in the TS_DECL_NON_COMMON structure of
> -   EXPR from input block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -static void
> -lto_input_ts_decl_non_common_tree_pointers (struct lto_input_block *ib,
> -					    struct data_in *data_in, tree expr)
> -{
> -  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_VINDEX (expr) = lto_input_tree (ib, data_in);
> -}
> -
> -
> -/* Read all pointer fields in the TS_DECL_WITH_VIS structure of EXPR
> -   from input block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -static void
> -lto_input_ts_decl_with_vis_tree_pointers (struct lto_input_block *ib,
> -				          struct data_in *data_in, tree expr)
> -{
> -  tree id;
> -
> -  id = lto_input_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);
> -}
> -
> -
> -/* Read all pointer fields in the TS_FIELD_DECL structure of EXPR from
> -   input block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -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);
> -  TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
> -}
> -
> -
> -/* Read all pointer fields in the TS_FUNCTION_DECL structure of EXPR
> -   from input block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -static void
> -lto_input_ts_function_decl_tree_pointers (struct lto_input_block *ib,
> -					  struct data_in *data_in, tree expr)
> -{
> -  /* 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);
> -
> -  /* If the file contains a function with an EH personality set,
> -     then it was compiled with -fexceptions.  In that case, initialize
> -     the backend EH machinery.  */
> -  if (DECL_FUNCTION_PERSONALITY (expr))
> -    lto_init_eh ();
> -}
> -
> -
> -/* Read all pointer fields in the TS_TYPE_COMMON structure of EXPR from
> -   input block IB.  DATA_IN contains tables and descriptors for the file
> -   being read.  */
> -
> -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);
> -  /* 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_CANONICAL gets re-computed during type merging.  */
> -  TYPE_CANONICAL (expr) = NULL_TREE;
> -  TYPE_STUB_DECL (expr) = lto_input_tree (ib, data_in);
> -}
> -
> -/* Read all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
> -   from input block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -static void
> -lto_input_ts_type_non_common_tree_pointers (struct lto_input_block *ib,
> -					    struct data_in *data_in,
> -					    tree expr)
> -{
> -  if (TREE_CODE (expr) == ENUMERAL_TYPE)
> -    TYPE_VALUES (expr) = lto_input_tree (ib, data_in);
> -  else if (TREE_CODE (expr) == ARRAY_TYPE)
> -    TYPE_DOMAIN (expr) = lto_input_tree (ib, data_in);
> -  else if (RECORD_OR_UNION_TYPE_P (expr))
> -    TYPE_FIELDS (expr) = lto_input_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);
> -
> -  if (!POINTER_TYPE_P (expr))
> -    TYPE_MINVAL (expr) = lto_input_tree (ib, data_in);
> -  TYPE_MAXVAL (expr) = lto_input_tree (ib, data_in);
> -  if (RECORD_OR_UNION_TYPE_P (expr))
> -    TYPE_BINFO (expr) = lto_input_tree (ib, data_in);
> -}
> -
> -
> -/* Read all pointer fields in the TS_LIST structure of EXPR from input
> -   block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -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_CHAIN (expr) = lto_input_chain (ib, data_in);
> -}
> -
> -
> -/* Read all pointer fields in the TS_VEC structure of EXPR from input
> -   block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -static void
> -lto_input_ts_vec_tree_pointers (struct lto_input_block *ib,
> -				struct data_in *data_in, tree expr)
> -{
> -  int i;
> -
> -  /* 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);
> -}
> -
> -
> -/* Read all pointer fields in the TS_EXP structure of EXPR from input
> -   block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -
> -static void
> -lto_input_ts_exp_tree_pointers (struct lto_input_block *ib,
> -			        struct data_in *data_in, tree expr)
> -{
> -  int i, length;
> -  location_t loc;
> -
> -  length = lto_input_sleb128 (ib);
> -  gcc_assert (length == TREE_OPERAND_LENGTH (expr));
> -
> -  for (i = 0; i < length; i++)
> -    TREE_OPERAND (expr, i) = lto_input_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);
> -}
> -
> -
> -/* Read all pointer fields in the TS_BLOCK structure of EXPR from input
> -   block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -static void
> -lto_input_ts_block_tree_pointers (struct lto_input_block *ib,
> -				  struct data_in *data_in, tree expr)
> -{
> -  /* Do not stream BLOCK_SOURCE_LOCATION.  We cannot handle debug information
> -     for early inlining so drop it on the floor instead of ICEing in
> -     dwarf2out.c.  */
> -  BLOCK_VARS (expr) = lto_input_chain (ib, data_in);
> -
> -  /* Do not stream BLOCK_NONLOCALIZED_VARS.  We cannot handle debug information
> -     for early inlining so drop it on the floor instead of ICEing in
> -     dwarf2out.c.  */
> -
> -  BLOCK_SUPERCONTEXT (expr) = lto_input_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);
> -  /* We re-compute BLOCK_SUBBLOCKS of our parent here instead
> -     of streaming it.  For non-BLOCK BLOCK_SUPERCONTEXTs we still
> -     stream the child relationship explicitly.  */
> -  if (BLOCK_SUPERCONTEXT (expr)
> -      && TREE_CODE (BLOCK_SUPERCONTEXT (expr)) == BLOCK)
> -    {
> -      BLOCK_CHAIN (expr) = BLOCK_SUBBLOCKS (BLOCK_SUPERCONTEXT (expr));
> -      BLOCK_SUBBLOCKS (BLOCK_SUPERCONTEXT (expr)) = expr;
> -    }
> -  /* The global block is rooted at the TU decl.  Hook it here to
> -     avoid the need to stream in this block during WPA time.  */
> -  else if (BLOCK_SUPERCONTEXT (expr)
> -	   && TREE_CODE (BLOCK_SUPERCONTEXT (expr)) == TRANSLATION_UNIT_DECL)
> -    DECL_INITIAL (BLOCK_SUPERCONTEXT (expr)) = expr;
> -  /* The function-level block is connected at the time we read in
> -     function bodies for the same reason.  */
> -}
> -
> -
> -/* Read all pointer fields in the TS_BINFO structure of EXPR from input
> -   block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -static void
> -lto_input_ts_binfo_tree_pointers (struct lto_input_block *ib,
> -				  struct data_in *data_in, tree expr)
> -{
> -  unsigned i, len;
> -  tree t;
> -
> -  /* Note that the number of slots in EXPR was read in
> -     lto_materialize_tree when instantiating EXPR.  However, the
> -     vector is empty so we cannot rely on VEC_length to know how many
> -     elements to read.  So, this list is emitted as a 0-terminated
> -     list on the writer side.  */
> -  do
> -    {
> -      t = lto_input_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);
> -
> -  len = lto_input_uleb128 (ib);
> -  if (len > 0)
> -    {
> -      VEC_reserve_exact (tree, gc, BINFO_BASE_ACCESSES (expr), len);
> -      for (i = 0; i < len; i++)
> -	{
> -	  tree a = lto_input_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);
> -}
> -
> -
> -/* Read all pointer fields in the TS_CONSTRUCTOR structure of EXPR from
> -   input block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> -
> -static void
> -lto_input_ts_constructor_tree_pointers (struct lto_input_block *ib,
> -				        struct data_in *data_in, tree expr)
> -{
> -  unsigned i, len;
> -
> -  len = lto_input_uleb128 (ib);
> -  for (i = 0; i < len; i++)
> -    {
> -      tree index, value;
> -
> -      index = lto_input_tree (ib, data_in);
> -      value = lto_input_tree (ib, data_in);
> -      CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (expr), index, value);
> -    }
> -}
> -
> -
> -/* Input a TS_TARGET_OPTION tree from IB into EXPR.  */
> -
> -static void
> -lto_input_ts_target_option (struct lto_input_block *ib, tree expr)
> -{
> -  unsigned i, len;
> -  struct bitpack_d bp;
> -  struct cl_target_option *t = TREE_TARGET_OPTION (expr);
> -
> -  bp = lto_input_bitpack (ib);
> -  len = sizeof (struct cl_target_option);
> -  for (i = 0; i < len; i++)
> -    ((unsigned char *)t)[i] = bp_unpack_value (&bp, 8);
> -  if (bp_unpack_value (&bp, 32) != 0x12345678)
> -    fatal_error ("cl_target_option size mismatch in LTO reader and writer");
> -}
> -
> -/* Input a TS_TRANSLATION_UNIT_DECL tree from IB and DATA_IN into EXPR.  */
> -
> -static void
> -lto_input_ts_translation_unit_decl_tree_pointers (struct lto_input_block *ib,
> -						  struct data_in *data_in,
> -						  tree expr)
> -{
> -  TRANSLATION_UNIT_LANGUAGE (expr) = xstrdup (lto_input_string (data_in, 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.  */
> -
> -static void
> -lto_input_tree_pointers (struct lto_input_block *ib, struct data_in *data_in,
> -			 tree expr)
> -{
> -  enum tree_code code;
> -
> -  code = TREE_CODE (expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
> -    lto_input_ts_common_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_VECTOR))
> -    lto_input_ts_vector_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX))
> -    lto_input_ts_complex_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL))
> -    lto_input_ts_decl_minimal_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
> -    lto_input_ts_decl_common_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
> -    lto_input_ts_decl_non_common_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
> -    lto_input_ts_decl_with_vis_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL))
> -    lto_input_ts_field_decl_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
> -    lto_input_ts_function_decl_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
> -    lto_input_ts_type_common_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON))
> -    lto_input_ts_type_non_common_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_LIST))
> -    lto_input_ts_list_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_VEC))
> -    lto_input_ts_vec_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_EXP))
> -    lto_input_ts_exp_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
> -    lto_input_ts_block_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
> -    lto_input_ts_binfo_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
> -    lto_input_ts_constructor_tree_pointers (ib, data_in, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
> -    lto_input_ts_target_option (ib, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
> -    lto_input_ts_translation_unit_decl_tree_pointers (ib, data_in, expr);
> -}
> -
> -
> -/* Read an index IX from input block IB and return the tree node at
> -   DATA_IN->FILE_DATA->GLOBALS_INDEX[IX].  */
> -
> -static tree
> -lto_get_pickled_tree (struct lto_input_block *ib, struct data_in *data_in)
> -{
> -  unsigned HOST_WIDE_INT ix;
> -  tree result;
> -  enum LTO_tags expected_tag;
> -
> -  ix = lto_input_uleb128 (ib);
> -  expected_tag = lto_input_enum (ib, LTO_tags, LTO_NUM_TAGS);
> -
> -  result = lto_streamer_cache_get (data_in->reader_cache, ix);
> -  gcc_assert (result
> -              && TREE_CODE (result) == lto_tag_to_tree_code (expected_tag));
> -
> -  return result;
> -}
> -
> -
> -/* Read a code and class from input block IB and return the
> -   corresponding builtin.  DATA_IN is as in lto_input_tree.  */
> -
> -static tree
> -lto_get_builtin_tree (struct lto_input_block *ib, struct data_in *data_in)
> -{
> -  enum built_in_class fclass;
> -  enum built_in_function fcode;
> -  const char *asmname;
> -  tree result;
> -
> -  fclass = lto_input_enum (ib, built_in_class, BUILT_IN_LAST);
> -  gcc_assert (fclass == BUILT_IN_NORMAL || fclass == BUILT_IN_MD);
> -
> -  fcode = (enum built_in_function) lto_input_uleb128 (ib);
> -
> -  if (fclass == BUILT_IN_NORMAL)
> -    {
> -      if (fcode >= END_BUILTINS)
> -	fatal_error ("machine independent builtin code out of range");
> -      result = built_in_decls[fcode];
> -      gcc_assert (result);
> -    }
> -  else if (fclass == BUILT_IN_MD)
> -    {
> -      result = targetm.builtin_decl (fcode, true);
> -      if (!result || result == error_mark_node)
> -	fatal_error ("target specific builtin not available");
> -    }
> -  else
> -    gcc_unreachable ();
> -
> -  asmname = lto_input_string (data_in, ib);
> -  if (asmname)
> -    set_builtin_user_assembler_name (result, asmname);
> -
> -  lto_streamer_cache_append (data_in->reader_cache, result);
> -
> -  return result;
> -}
> -
> -
> -/* 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;
> -}
> -
> -
> -/* 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.  */
> -
> -void
> -lto_streamer_read_tree (struct lto_input_block *ib, struct data_in *data_in,
> -			tree expr)
> +void
> +lto_streamer_read_tree (struct lto_input_block *ib, struct data_in *data_in,
> +			tree expr)
>  {
>    if (DECL_P (expr)
>        && TREE_CODE (expr) != FUNCTION_DECL
> @@ -2521,84 +1059,6 @@ lto_streamer_read_tree (struct lto_input_block *ib, struct data_in *data_in,
>  }
>  
>  
> -/* Read and INTEGER_CST node from input block IB using the per-file
> -   context in DATA_IN.  */
> -
> -static 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);
> -  overflow_p = (lto_input_1_unsigned (ib) != 0);
> -  low = lto_input_uleb128 (ib);
> -  high = lto_input_uleb128 (ib);
> -  result = build_int_cst_wide (type, low, high);
> -
> -  /* If the original constant had overflown, build a replica of RESULT to
> -     avoid modifying the shared constant returned by build_int_cst_wide.  */
> -  if (overflow_p)
> -    {
> -      result = copy_node (result);
> -      TREE_OVERFLOW (result) = 1;
> -    }
> -
> -  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;
> -}
> -
> -
>  /* Initialization for the LTO reader.  */
>  
>  void
> diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
> index 6345d83..0b84b08 100644
> --- a/gcc/lto-streamer-out.c
> +++ b/gcc/lto-streamer-out.c
> @@ -41,45 +41,10 @@ along with GCC; see the file COPYING3.  If not see
>  #include "vec.h"
>  #include "lto-symtab.h"
>  #include "lto-streamer.h"
> -
> -
> -struct string_slot
> -{
> -  const char *s;
> -  int len;
> -  unsigned int slot_num;
> -};
> -
> -
> -/* Returns a hash code for P.  
> -   Shamelessly stollen from libiberty.  */
> -
> -static hashval_t
> -hash_string_slot_node (const void *p)
> -{
> -  const struct string_slot *ds = (const struct string_slot *) p;
> -  hashval_t r = ds->len;
> -  int i;
> -
> -  for (i = 0; i < ds->len; i++)
> -     r = r * 67 + (unsigned)ds->s[i] - 113;
> -  return r;
> -}
> -
> -
> -/* Returns nonzero if P1 and P2 are equal.  */
> -
> -static int
> -eq_string_slot_node (const void *p1, const void *p2)
> -{
> -  const struct string_slot *ds1 = (const struct string_slot *) p1;
> -  const struct string_slot *ds2 = (const struct string_slot *) p2;
> -
> -  if (ds1->len == ds2->len)
> -    return memcmp (ds1->s, ds2->s, ds1->len) == 0;
> -
> -  return 0;
> -}
> +#include "data-streamer.h"
> +#include "gimple-streamer.h"
> +#include "tree-streamer.h"
> +#include "streamer-hooks.h"
>  
>  
>  /* Clear the line info stored in DATA_IN.  */
> @@ -108,1331 +73,125 @@ create_output_block (enum lto_section_type section_type)
>    ob->writer_cache = lto_streamer_cache_create ();
>  
>    if (section_type == LTO_section_function_body)
> -    ob->cfg_stream = XCNEW (struct lto_output_stream);
> -
> -  clear_line_info (ob);
> -
> -  ob->string_hash_table = htab_create (37, hash_string_slot_node,
> -				       eq_string_slot_node, NULL);
> -  gcc_obstack_init (&ob->obstack);
> -
> -  return ob;
> -}
> -
> -
> -/* Destroy the output block OB.  */
> -
> -void
> -destroy_output_block (struct output_block *ob)
> -{
> -  enum lto_section_type section_type = ob->section_type;
> -
> -  htab_delete (ob->string_hash_table);
> -
> -  free (ob->main_stream);
> -  free (ob->string_stream);
> -  if (section_type == LTO_section_function_body)
> -    free (ob->cfg_stream);
> -
> -  lto_streamer_cache_delete (ob->writer_cache);
> -  obstack_free (&ob->obstack, NULL);
> -
> -  free (ob);
> -}
> -
> -/* Return index used to reference STRING of LEN characters in the string table
> -   in OB.  The string might or might not include a trailing '\0'.
> -   Then put the index onto the INDEX_STREAM.  
> -   When PERSISTENT is set, the string S is supposed to not change during
> -   duration of the OB and thus OB can keep pointer into it.  */
> -
> -static unsigned
> -lto_string_index (struct output_block *ob,
> -		  const char *s,
> -		  unsigned int len,
> -		  bool persistent)
> -{
> -  struct string_slot **slot;
> -  struct string_slot s_slot;
> -
> -  s_slot.s = s;
> -  s_slot.len = len;
> -  s_slot.slot_num = 0;
> -
> -  slot = (struct string_slot **) htab_find_slot (ob->string_hash_table,
> -						 &s_slot, INSERT);
> -  if (*slot == NULL)
> -    {
> -      struct lto_output_stream *string_stream = ob->string_stream;
> -      unsigned int start = string_stream->total_size;
> -      struct string_slot *new_slot
> -	= XOBNEW (&ob->obstack, struct string_slot);
> -      const char *string;
> -
> -      if (!persistent)
> -	{
> -	  char *tmp;
> -	  string = tmp = XOBNEWVEC (&ob->obstack, char, len);
> -          memcpy (tmp, s, len);
> -        }
> -      else
> -	string = s;
> -
> -      new_slot->s = string;
> -      new_slot->len = len;
> -      new_slot->slot_num = start;
> -      *slot = new_slot;
> -      lto_output_uleb128_stream (string_stream, len);
> -      lto_output_data_stream (string_stream, string, len);
> -      return start + 1;
> -    }
> -  else
> -    {
> -      struct string_slot *old_slot = *slot;
> -      return old_slot->slot_num + 1;
> -    }
> -}
> -
> -
> -/* Output STRING of LEN characters to the string
> -   table in OB. The string might or might not include a trailing '\0'.
> -   Then put the index onto the INDEX_STREAM. 
> -   When PERSISTENT is set, the string S is supposed to not change during
> -   duration of the OB and thus OB can keep pointer into it.  */
> -
> -static void
> -lto_output_string_with_length (struct output_block *ob,
> -			       struct lto_output_stream *index_stream,
> -			       const char *s,
> -			       unsigned int len,
> -			       bool persistent)
> -{
> -  if (s)
> -    lto_output_uleb128_stream (index_stream,
> -			       lto_string_index (ob, s, len, persistent));
> -  else
> -    lto_output_1_stream (index_stream, 0);
> -}
> -
> -/* Output the '\0' terminated STRING to the string
> -   table in OB.  Then put the index onto the INDEX_STREAM.
> -   When PERSISTENT is set, the string S is supposed to not change during
> -   duration of the OB and thus OB can keep pointer into it.  */
> -
> -static void
> -lto_output_string (struct output_block *ob,
> -	           struct lto_output_stream *index_stream,
> -	           const char *string,
> -		   bool persistent)
> -{
> -  if (string)
> -    lto_output_string_with_length (ob, index_stream, string,
> -				   strlen (string) + 1,
> -				   persistent);
> -  else
> -    lto_output_1_stream (index_stream, 0);
> -}
> -
> -
> -/* Output the STRING constant to the string
> -   table in OB.  Then put the index onto the INDEX_STREAM.  */
> -
> -static void
> -output_string_cst (struct output_block *ob,
> -		   struct lto_output_stream *index_stream,
> -		   tree string)
> -{
> -  lto_output_string_with_length (ob, index_stream,
> -				 TREE_STRING_POINTER (string),
> -				 TREE_STRING_LENGTH (string),
> -				 true);
> -}
> -
> -
> -/* Output the identifier ID to the string
> -   table in OB.  Then put the index onto the INDEX_STREAM.  */
> -
> -static void
> -output_identifier (struct output_block *ob,
> -		   struct lto_output_stream *index_stream,
> -		   tree id)
> -{
> -  lto_output_string_with_length (ob, index_stream,
> -				 IDENTIFIER_POINTER (id),
> -				 IDENTIFIER_LENGTH (id),
> -				 true);
> -}
> -
> -
> -/* Write a zero to the output stream.  */
> -
> -static void
> -output_zero (struct output_block *ob)
> -{
> -  lto_output_1_stream (ob->main_stream, 0);
> -}
> -
> -
> -/* Output an unsigned LEB128 quantity to OB->main_stream.  */
> -
> -static void
> -output_uleb128 (struct output_block *ob, unsigned HOST_WIDE_INT work)
> -{
> -  lto_output_uleb128_stream (ob->main_stream, work);
> -}
> -
> -
> -/* Output a signed LEB128 quantity to OB->main_stream.  */
> -
> -static void
> -output_sleb128 (struct output_block *ob, HOST_WIDE_INT work)
> -{
> -  lto_output_sleb128_stream (ob->main_stream, work);
> -}
> -
> -
> -/* Output the start of a record with TAG to output block OB.  */
> -
> -static inline void
> -output_record_start (struct output_block *ob, enum LTO_tags tag)
> -{
> -  lto_output_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS, tag);
> -}
> -
> -
> -/* Look up NODE in the type table and write the index for it to OB.  */
> -
> -static void
> -output_type_ref (struct output_block *ob, tree node)
> -{
> -  output_record_start (ob, LTO_type_ref);
> -  lto_output_type_ref_index (ob->decl_state, ob->main_stream, node);
> -}
> -
> -
> -/* Pack all the non-pointer fields of the TS_BASE structure of
> -   expression EXPR into bitpack BP.  */
> -
> -static void
> -pack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  bp_pack_value (bp, TREE_CODE (expr), 16);
> -  if (!TYPE_P (expr))
> -    {
> -      bp_pack_value (bp, TREE_SIDE_EFFECTS (expr), 1);
> -      bp_pack_value (bp, TREE_CONSTANT (expr), 1);
> -      bp_pack_value (bp, TREE_READONLY (expr), 1);
> -
> -      /* TREE_PUBLIC is used on types to indicate that the type
> -	 has a TYPE_CACHED_VALUES vector.  This is not streamed out,
> -	 so we skip it here.  */
> -      bp_pack_value (bp, TREE_PUBLIC (expr), 1);
> -    }
> -  else
> -    bp_pack_value (bp, 0, 4);
> -  bp_pack_value (bp, TREE_ADDRESSABLE (expr), 1);
> -  bp_pack_value (bp, TREE_THIS_VOLATILE (expr), 1);
> -  if (DECL_P (expr))
> -    bp_pack_value (bp, DECL_UNSIGNED (expr), 1);
> -  else if (TYPE_P (expr))
> -    bp_pack_value (bp, TYPE_UNSIGNED (expr), 1);
> -  else
> -    bp_pack_value (bp, 0, 1);
> -  /* We write debug info two times, do not confuse the second one.  */
> -  bp_pack_value (bp, TYPE_P (expr) ? 0 : TREE_ASM_WRITTEN (expr), 1);
> -  if (TYPE_P (expr))
> -    bp_pack_value (bp, TYPE_ARTIFICIAL (expr), 1);
> -  else
> -    bp_pack_value (bp, TREE_NO_WARNING (expr), 1);
> -  bp_pack_value (bp, TREE_USED (expr), 1);
> -  bp_pack_value (bp, TREE_NOTHROW (expr), 1);
> -  bp_pack_value (bp, TREE_STATIC (expr), 1);
> -  bp_pack_value (bp, TREE_PRIVATE (expr), 1);
> -  bp_pack_value (bp, TREE_PROTECTED (expr), 1);
> -  bp_pack_value (bp, TREE_DEPRECATED (expr), 1);
> -  if (TYPE_P (expr))
> -    bp_pack_value (bp, TYPE_SATURATING (expr), 1);
> -  else if (TREE_CODE (expr) == SSA_NAME)
> -    bp_pack_value (bp, SSA_NAME_IS_DEFAULT_DEF (expr), 1);
> -  else
> -    bp_pack_value (bp, 0, 1);
> -}
> -
> -
> -/* Pack all the non-pointer fields of the TS_REAL_CST structure of
> -   expression EXPR into bitpack BP.  */
> -
> -static void
> -pack_ts_real_cst_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  unsigned i;
> -  REAL_VALUE_TYPE r;
> -
> -  r = TREE_REAL_CST (expr);
> -  bp_pack_value (bp, r.cl, 2);
> -  bp_pack_value (bp, r.decimal, 1);
> -  bp_pack_value (bp, r.sign, 1);
> -  bp_pack_value (bp, r.signalling, 1);
> -  bp_pack_value (bp, r.canonical, 1);
> -  bp_pack_value (bp, r.uexp, EXP_BITS);
> -  for (i = 0; i < SIGSZ; i++)
> -    bp_pack_value (bp, r.sig[i], HOST_BITS_PER_LONG);
> -}
> -
> -
> -/* Pack all the non-pointer fields of the TS_FIXED_CST structure of
> -   expression EXPR into bitpack BP.  */
> -
> -static void
> -pack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  struct fixed_value fv = TREE_FIXED_CST (expr);
> -  bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, fv.mode);
> -  bp_pack_var_len_int (bp, fv.data.low);
> -  bp_pack_var_len_int (bp, fv.data.high);
> -}
> -
> -
> -/* Pack all the non-pointer fields of the TS_DECL_COMMON structure
> -   of expression EXPR into bitpack BP.  */
> -
> -static void
> -pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, DECL_MODE (expr));
> -  bp_pack_value (bp, DECL_NONLOCAL (expr), 1);
> -  bp_pack_value (bp, DECL_VIRTUAL_P (expr), 1);
> -  bp_pack_value (bp, DECL_IGNORED_P (expr), 1);
> -  bp_pack_value (bp, DECL_ABSTRACT (expr), 1);
> -  bp_pack_value (bp, DECL_ARTIFICIAL (expr), 1);
> -  bp_pack_value (bp, DECL_USER_ALIGN (expr), 1);
> -  bp_pack_value (bp, DECL_PRESERVE_P (expr), 1);
> -  bp_pack_value (bp, DECL_DEBUG_EXPR_IS_FROM (expr), 1);
> -  bp_pack_value (bp, DECL_EXTERNAL (expr), 1);
> -  bp_pack_value (bp, DECL_GIMPLE_REG_P (expr), 1);
> -  bp_pack_var_len_unsigned (bp, DECL_ALIGN (expr));
> -
> -  if (TREE_CODE (expr) == LABEL_DECL)
> -    {
> -      /* Note that we do not write LABEL_DECL_UID.  The reader will
> -	 always assume an initial value of -1 so that the
> -	 label_to_block_map is recreated by gimple_set_bb.  */
> -      bp_pack_value (bp, DECL_ERROR_ISSUED (expr), 1);
> -      bp_pack_var_len_unsigned (bp, EH_LANDING_PAD_NR (expr));
> -    }
> -
> -  if (TREE_CODE (expr) == FIELD_DECL)
> -    {
> -      bp_pack_value (bp, DECL_PACKED (expr), 1);
> -      bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
> -      bp_pack_value (bp, expr->decl_common.off_align, 8);
> -    }
> -
> -  if (TREE_CODE (expr) == RESULT_DECL
> -      || TREE_CODE (expr) == PARM_DECL
> -      || TREE_CODE (expr) == VAR_DECL)
> -    {
> -      bp_pack_value (bp, DECL_BY_REFERENCE (expr), 1);
> -      if (TREE_CODE (expr) == VAR_DECL
> -	  || TREE_CODE (expr) == PARM_DECL)
> -	bp_pack_value (bp, DECL_HAS_VALUE_EXPR_P (expr), 1);
> -      bp_pack_value (bp, DECL_RESTRICTED_P (expr), 1);
> -    }
> -}
> -
> -
> -/* Pack all the non-pointer fields of the TS_DECL_WRTL structure
> -   of expression EXPR into bitpack BP.  */
> -
> -static void
> -pack_ts_decl_wrtl_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  bp_pack_value (bp, DECL_REGISTER (expr), 1);
> -}
> -
> -
> -/* Pack all the non-pointer fields of the TS_DECL_WITH_VIS structure
> -   of expression EXPR into bitpack BP.  */
> -
> -static void
> -pack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  bp_pack_value (bp, DECL_DEFER_OUTPUT (expr), 1);
> -  bp_pack_value (bp, DECL_COMMON (expr), 1);
> -  bp_pack_value (bp, DECL_DLLIMPORT_P (expr), 1);
> -  bp_pack_value (bp, DECL_WEAK (expr), 1);
> -  bp_pack_value (bp, DECL_SEEN_IN_BIND_EXPR_P (expr),  1);
> -  bp_pack_value (bp, DECL_COMDAT (expr),  1);
> -  bp_pack_value (bp, DECL_VISIBILITY (expr),  2);
> -  bp_pack_value (bp, DECL_VISIBILITY_SPECIFIED (expr),  1);
> -
> -  if (TREE_CODE (expr) == VAR_DECL)
> -    {
> -      bp_pack_value (bp, DECL_HARD_REGISTER (expr), 1);
> -      bp_pack_value (bp, DECL_IN_TEXT_SECTION (expr), 1);
> -      bp_pack_value (bp, DECL_IN_CONSTANT_POOL (expr), 1);
> -      bp_pack_value (bp, DECL_TLS_MODEL (expr),  3);
> -    }
> -
> -  if (VAR_OR_FUNCTION_DECL_P (expr))
> -    bp_pack_var_len_unsigned (bp, DECL_INIT_PRIORITY (expr));
> -}
> -
> -
> -/* Pack all the non-pointer fields of the TS_FUNCTION_DECL structure
> -   of expression EXPR into bitpack BP.  */
> -
> -static void
> -pack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  /* For normal/md builtins we only write the class and code, so they
> -     should never be handled here.  */
> -  gcc_assert (!lto_stream_as_builtin_p (expr));
> -
> -  bp_pack_enum (bp, built_in_class, BUILT_IN_LAST,
> -		DECL_BUILT_IN_CLASS (expr));
> -  bp_pack_value (bp, DECL_STATIC_CONSTRUCTOR (expr), 1);
> -  bp_pack_value (bp, DECL_STATIC_DESTRUCTOR (expr), 1);
> -  bp_pack_value (bp, DECL_UNINLINABLE (expr), 1);
> -  bp_pack_value (bp, DECL_POSSIBLY_INLINED (expr), 1);
> -  bp_pack_value (bp, DECL_IS_NOVOPS (expr), 1);
> -  bp_pack_value (bp, DECL_IS_RETURNS_TWICE (expr), 1);
> -  bp_pack_value (bp, DECL_IS_MALLOC (expr), 1);
> -  bp_pack_value (bp, DECL_IS_OPERATOR_NEW (expr), 1);
> -  bp_pack_value (bp, DECL_DECLARED_INLINE_P (expr), 1);
> -  bp_pack_value (bp, DECL_STATIC_CHAIN (expr), 1);
> -  bp_pack_value (bp, DECL_NO_INLINE_WARNING_P (expr), 1);
> -  bp_pack_value (bp, DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr), 1);
> -  bp_pack_value (bp, DECL_NO_LIMIT_STACK (expr), 1);
> -  bp_pack_value (bp, DECL_DISREGARD_INLINE_LIMITS (expr), 1);
> -  bp_pack_value (bp, DECL_PURE_P (expr), 1);
> -  bp_pack_value (bp, DECL_LOOPING_CONST_OR_PURE_P (expr), 1);
> -  if (DECL_BUILT_IN_CLASS (expr) != NOT_BUILT_IN)
> -    bp_pack_value (bp, DECL_FUNCTION_CODE (expr), 11);
> -  if (DECL_STATIC_DESTRUCTOR (expr))
> -    bp_pack_var_len_unsigned (bp, DECL_FINI_PRIORITY (expr));
> -}
> -
> -
> -/* Pack all the non-pointer fields of the TS_TYPE_COMMON structure
> -   of expression EXPR into bitpack BP.  */
> -
> -static void
> -pack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, TYPE_MODE (expr));
> -  bp_pack_value (bp, TYPE_STRING_FLAG (expr), 1);
> -  bp_pack_value (bp, TYPE_NO_FORCE_BLK (expr), 1);
> -  bp_pack_value (bp, TYPE_NEEDS_CONSTRUCTING (expr), 1);
> -  if (RECORD_OR_UNION_TYPE_P (expr))
> -    bp_pack_value (bp, TYPE_TRANSPARENT_AGGR (expr), 1);
> -  bp_pack_value (bp, TYPE_PACKED (expr), 1);
> -  bp_pack_value (bp, TYPE_RESTRICT (expr), 1);
> -  bp_pack_value (bp, TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr), 2);
> -  bp_pack_value (bp, TYPE_USER_ALIGN (expr), 1);
> -  bp_pack_value (bp, TYPE_READONLY (expr), 1);
> -  bp_pack_var_len_unsigned (bp, TYPE_PRECISION (expr));
> -  bp_pack_var_len_unsigned (bp, TYPE_ALIGN (expr));
> -  bp_pack_var_len_int (bp, TYPE_ALIAS_SET (expr) == 0 ? 0 : -1);
> -}
> -
> -
> -/* Pack all the non-pointer fields of the TS_BLOCK structure
> -   of expression EXPR into bitpack BP.  */
> -
> -static void
> -pack_ts_block_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  bp_pack_value (bp, BLOCK_ABSTRACT (expr), 1);
> -  /* BLOCK_NUMBER is recomputed.  */
> -}
> -
> -/* Pack all the non-pointer fields of the TS_TRANSLATION_UNIT_DECL structure
> -   of expression EXPR into bitpack BP.  */
> -
> -static void
> -pack_ts_translation_unit_decl_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED, tree expr ATTRIBUTE_UNUSED)
> -{
> -}
> -
> -/* Pack all the non-pointer fields in EXPR into a bit pack.  */
> -
> -static void
> -pack_value_fields (struct bitpack_d *bp, tree expr)
> -{
> -  enum tree_code code;
> -
> -  code = TREE_CODE (expr);
> -
> -  /* Note that all these functions are highly sensitive to changes in
> -     the types and sizes of each of the fields being packed.  */
> -  pack_ts_base_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
> -    pack_ts_real_cst_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_FIXED_CST))
> -    pack_ts_fixed_cst_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
> -    pack_ts_decl_common_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL))
> -    pack_ts_decl_wrtl_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
> -    pack_ts_decl_with_vis_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
> -    pack_ts_function_decl_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
> -    pack_ts_type_common_value_fields (bp, expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
> -    pack_ts_block_value_fields (bp, 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);
> -}
> -
> -
> -/* Output info about new location into bitpack BP.
> -   After outputting bitpack, lto_output_location_data has
> -   to be done to output actual data.  */
> -
> -static inline void
> -lto_output_location_bitpack (struct bitpack_d *bp,
> -			     struct output_block *ob,
> -			     location_t loc)
> -{
> -  expanded_location xloc;
> -
> -  bp_pack_value (bp, loc == UNKNOWN_LOCATION, 1);
> -  if (loc == UNKNOWN_LOCATION)
> -    return;
> -
> -  xloc = expand_location (loc);
> -
> -  bp_pack_value (bp, ob->current_file != xloc.file, 1);
> -  if (ob->current_file != xloc.file)
> -    bp_pack_var_len_unsigned (bp, lto_string_index (ob,
> -					            xloc.file,
> -						    strlen (xloc.file) + 1,
> -						    true));
> -  ob->current_file = xloc.file;
> -
> -  bp_pack_value (bp, ob->current_line != xloc.line, 1);
> -  if (ob->current_line != xloc.line)
> -    bp_pack_var_len_unsigned (bp, xloc.line);
> -  ob->current_line = xloc.line;
> -
> -  bp_pack_value (bp, ob->current_col != xloc.column, 1);
> -  if (ob->current_col != xloc.column)
> -    bp_pack_var_len_unsigned (bp, xloc.column);
> -  ob->current_col = xloc.column;
> -}
> -
> -
> -/* Emit location LOC to output block OB.
> -   When bitpack is handy, it is more space effecient to call
> -   lto_output_location_bitpack with existing bitpack.  */
> -
> -static void
> -lto_output_location (struct output_block *ob, location_t loc)
> -{
> -  struct bitpack_d bp = bitpack_create (ob->main_stream);
> -  lto_output_location_bitpack (&bp, ob, loc);
> -  lto_output_bitpack (&bp);
> -}
> -
> -
> -/* Return true if tree node T is written to various tables.  For these
> -   nodes, we sometimes want to write their phyiscal representation
> -   (via lto_output_tree), and sometimes we need to emit an index
> -   reference into a table (via lto_output_tree_ref).  */
> -
> -static bool
> -tree_is_indexable (tree t)
> -{
> -  if (TREE_CODE (t) == PARM_DECL)
> -    return false;
> -  else if (TREE_CODE (t) == VAR_DECL && decl_function_context (t)
> -	   && !TREE_STATIC (t))
> -    return false;
> -  else
> -    return (TYPE_P (t) || DECL_P (t) || TREE_CODE (t) == SSA_NAME);
> -}
> -
> -
> -/* If EXPR is an indexable tree node, output a reference to it to
> -   output block OB.  Otherwise, output the physical representation of
> -   EXPR to OB.  */
> -
> -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);
> -      return;
> -    }
> -
> -  code = TREE_CODE (expr);
> -  switch (code)
> -    {
> -    case SSA_NAME:
> -      output_record_start (ob, LTO_ssa_name_ref);
> -      output_uleb128 (ob, SSA_NAME_VERSION (expr));
> -      break;
> -
> -    case FIELD_DECL:
> -      output_record_start (ob, LTO_field_decl_ref);
> -      lto_output_field_decl_index (ob->decl_state, ob->main_stream, expr);
> -      break;
> -
> -    case FUNCTION_DECL:
> -      output_record_start (ob, LTO_function_decl_ref);
> -      lto_output_fn_decl_index (ob->decl_state, ob->main_stream, expr);
> -      break;
> -
> -    case VAR_DECL:
> -    case DEBUG_EXPR_DECL:
> -      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;
> -
> -    case CONST_DECL:
> -      output_record_start (ob, LTO_const_decl_ref);
> -      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
> -      break;
> -
> -    case IMPORTED_DECL:
> -      gcc_assert (decl_function_context (expr) == NULL);
> -      output_record_start (ob, LTO_imported_decl_ref);
> -      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
> -      break;
> -
> -    case TYPE_DECL:
> -      output_record_start (ob, LTO_type_decl_ref);
> -      lto_output_type_decl_index (ob->decl_state, ob->main_stream, expr);
> -      break;
> -
> -    case NAMESPACE_DECL:
> -      output_record_start (ob, LTO_namespace_decl_ref);
> -      lto_output_namespace_decl_index (ob->decl_state, ob->main_stream, expr);
> -      break;
> -
> -    case LABEL_DECL:
> -      output_record_start (ob, LTO_label_decl_ref);
> -      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
> -      break;
> -
> -    case RESULT_DECL:
> -      output_record_start (ob, LTO_result_decl_ref);
> -      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
> -      break;
> -
> -    case TRANSLATION_UNIT_DECL:
> -      output_record_start (ob, LTO_translation_unit_decl_ref);
> -      lto_output_var_decl_index (ob->decl_state, ob->main_stream, 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 ();
> -	  }
> -      }
> -    }
> -}
> -
> -
> -/* 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);
> -}
> -
> -
> -/* 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.  */
> -
> -static void
> -lto_output_chain (struct output_block *ob, tree t, bool ref_p)
> -{
> -  int i, count;
> -
> -  count = list_length (t);
> -  output_sleb128 (ob, count);
> -  for (i = 0; i < count; i++)
> -    {
> -      tree saved_chain;
> -
> -      /* Clear TREE_CHAIN to avoid blindly recursing into the rest
> -	 of the list.  */
> -      saved_chain = TREE_CHAIN (t);
> -      TREE_CHAIN (t) = NULL_TREE;
> -
> -      lto_output_tree_or_ref (ob, t, ref_p);
> -
> -      TREE_CHAIN (t) = saved_chain;
> -      t = TREE_CHAIN (t);
> -    }
> -}
> -
> -
> -/* Write all pointer fields in the TS_COMMON structure of EXPR to output
> -   block OB.  If REF_P is true, write a reference to EXPR's pointer
> -   fields.  */
> -
> -static void
> -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);
> -}
> -
> -
> -/* Write all pointer fields in the TS_VECTOR structure of EXPR to output
> -   block OB.  If REF_P is true, write a reference to EXPR's pointer
> -   fields.  */
> -
> -static void
> -lto_output_ts_vector_tree_pointers (struct output_block *ob, tree expr,
> -				    bool ref_p)
> -{
> -  lto_output_chain (ob, TREE_VECTOR_CST_ELTS (expr), ref_p);
> -}
> -
> -
> -/* Write all pointer fields in the TS_COMPLEX structure of EXPR to output
> -   block OB.  If REF_P is true, write a reference to EXPR's pointer
> -   fields.  */
> -
> -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);
> -}
> -
> -
> -/* Write all pointer fields in the TS_DECL_MINIMAL structure of EXPR
> -   to output block OB.  If REF_P is true, write a reference to EXPR's
> -   pointer fields.  */
> -
> -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);
> -  lto_output_location (ob, DECL_SOURCE_LOCATION (expr));
> -}
> -
> -
> -/* Write all pointer fields in the TS_DECL_COMMON structure of EXPR to
> -   output block OB.  If REF_P is true, write a reference to EXPR's
> -   pointer fields.  */
> -
> -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);
> -
> -  /* 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);
> -
> -  /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
> -     for early inlining so drop it on the floor instead of ICEing in
> -     dwarf2out.c.  */
> -
> -  if (TREE_CODE (expr) == PARM_DECL)
> -    lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
> -
> -  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);
> -
> -  if (TREE_CODE (expr) == VAR_DECL)
> -    lto_output_tree_or_ref (ob, DECL_DEBUG_EXPR (expr), ref_p);
> -}
> -
> -
> -/* Write all pointer fields in the TS_DECL_NON_COMMON structure of
> -   EXPR to output block OB.  If REF_P is true, write a reference to EXPR's
> -   pointer fields.  */
> -
> -static void
> -lto_output_ts_decl_non_common_tree_pointers (struct output_block *ob,
> -					     tree expr, bool ref_p)
> -{
> -  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);
> -    }
> -  lto_output_tree_or_ref (ob, DECL_VINDEX (expr), ref_p);
> -}
> -
> -
> -/* Write all pointer fields in the TS_DECL_WITH_VIS structure of EXPR
> -   to output block OB.  If REF_P is true, write a reference to EXPR's
> -   pointer fields.  */
> -
> -static void
> -lto_output_ts_decl_with_vis_tree_pointers (struct output_block *ob, tree expr,
> -					   bool ref_p)
> -{
> -  /* 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);
> -  else
> -    output_record_start (ob, LTO_null);
> -
> -  lto_output_tree_or_ref (ob, DECL_SECTION_NAME (expr), ref_p);
> -  lto_output_tree_or_ref (ob, DECL_COMDAT_GROUP (expr), ref_p);
> -}
> -
> -
> -/* Write all pointer fields in the TS_FIELD_DECL structure of EXPR to
> -   output block OB.  If REF_P is true, write a reference to EXPR's
> -   pointer fields.  */
> -
> -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);
> -  lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
> -}
> -
> -
> -/* Write all pointer fields in the TS_FUNCTION_DECL structure of EXPR
> -   to output block OB.  If REF_P is true, write a reference to EXPR's
> -   pointer fields.  */
> -
> -static void
> -lto_output_ts_function_decl_tree_pointers (struct output_block *ob, tree expr,
> -					   bool ref_p)
> -{
> -  /* DECL_STRUCT_FUNCTION is handled by lto_output_function.  FIXME lto,
> -     maybe it should be handled here?  */
> -  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);
> -}
> -
> -
> -/* Write all pointer fields in the TS_TYPE_COMMON structure of EXPR to
> -   output block OB.  If REF_P is true, write a reference to EXPR's
> -   pointer fields.  */
> -
> -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);
> -  /* 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);
> -  /* 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);
> -}
> -
> -/* Write all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
> -   to output block OB.  If REF_P is true, write a reference to EXPR's
> -   pointer fields.  */
> -
> -static void
> -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);
> -  else if (TREE_CODE (expr) == ARRAY_TYPE)
> -    lto_output_tree_or_ref (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);
> -  else if (TREE_CODE (expr) == FUNCTION_TYPE
> -	   || TREE_CODE (expr) == METHOD_TYPE)
> -    lto_output_tree_or_ref (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);
> -  if (RECORD_OR_UNION_TYPE_P (expr))
> -    lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p);
> -}
> -
> -
> -/* Write all pointer fields in the TS_LIST structure of EXPR to output
> -   block OB.  If REF_P is true, write a reference to EXPR's pointer
> -   fields.  */
> -
> -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);
> -  lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
> -}
> -
> -
> -/* Write all pointer fields in the TS_VEC structure of EXPR to output
> -   block OB.  If REF_P is true, write a reference to EXPR's pointer
> -   fields.  */
> -
> -static void
> -lto_output_ts_vec_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
> -{
> -  int i;
> -
> -  /* 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);
> -}
> -
> -
> -/* Write all pointer fields in the TS_EXP structure of EXPR to output
> -   block OB.  If REF_P is true, write a reference to EXPR's pointer
> -   fields.  */
> -
> -static void
> -lto_output_ts_exp_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
> -{
> -  int i;
> -
> -  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);
> -  lto_output_location (ob, EXPR_LOCATION (expr));
> -  lto_output_tree_or_ref (ob, TREE_BLOCK (expr), ref_p);
> -}
> -
> -
> -/* Write all pointer fields in the TS_BLOCK structure of EXPR to output
> -   block OB.  If REF_P is true, write a reference to EXPR's pointer
> -   fields.  */
> -
> -static void
> -lto_output_ts_block_tree_pointers (struct output_block *ob, tree expr,
> -				   bool ref_p)
> -{
> -  /* Do not stream BLOCK_SOURCE_LOCATION.  We cannot handle debug information
> -     for early inlining so drop it on the floor instead of ICEing in
> -     dwarf2out.c.  */
> -  lto_output_chain (ob, BLOCK_VARS (expr), ref_p);
> -
> -  /* Do not stream BLOCK_NONLOCALIZED_VARS.  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_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);
> -  /* Do not output BLOCK_SUBBLOCKS.  Instead on streaming-in this
> -     list is re-constructed from BLOCK_SUPERCONTEXT.  */
> -}
> -
> -
> -/* Write all pointer fields in the TS_BINFO structure of EXPR to output
> -   block OB.  If REF_P is true, write a reference to EXPR's pointer
> -   fields.  */
> -
> -static void
> -lto_output_ts_binfo_tree_pointers (struct output_block *ob, tree expr,
> -				   bool ref_p)
> -{
> -  unsigned i;
> -  tree t;
> -
> -  /* Note that the number of BINFO slots has already been emitted in
> -     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);
> -
> -  lto_output_tree_or_ref (ob, BINFO_OFFSET (expr), ref_p);
> -  lto_output_tree_or_ref (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);
> -
> -  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);
> -
> -  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);
> -}
> -
> -
> -/* Write all pointer fields in the TS_CONSTRUCTOR structure of EXPR to
> -   output block OB.  If REF_P is true, write a reference to EXPR's
> -   pointer fields.  */
> -
> -static void
> -lto_output_ts_constructor_tree_pointers (struct output_block *ob, tree expr,
> -					 bool ref_p)
> -{
> -  unsigned i;
> -  tree index, value;
> -
> -  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);
> -    }
> -}
> -
> -/* Write a TS_TARGET_OPTION tree in EXPR to OB.  */
> -
> -static void
> -lto_output_ts_target_option (struct output_block *ob, tree expr)
> -{
> -  struct cl_target_option *t = TREE_TARGET_OPTION (expr);
> -  struct bitpack_d bp;
> -  unsigned i, len;
> -
> -  /* The cl_target_option is target specific and generated by the options
> -     awk script, so we just recreate a byte-by-byte copy here. */
> -
> -  bp = bitpack_create (ob->main_stream);
> -  len = sizeof (struct cl_target_option);
> -  for (i = 0; i < len; i++)
> -    bp_pack_value (&bp, ((unsigned char *)t)[i], 8);
> -  /* Catch struct size mismatches between reader and writer. */
> -  bp_pack_value (&bp, 0x12345678, 32);
> -  lto_output_bitpack (&bp);
> -}
> -
> -/* Write a TS_TRANSLATION_UNIT_DECL tree in EXPR to OB.  */
> -
> -static void
> -lto_output_ts_translation_unit_decl_tree_pointers (struct output_block *ob,
> -						   tree expr)
> -{
> -  lto_output_string (ob, ob->main_stream,
> -		     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.  */
> -
> -static void
> -lto_output_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
> -{
> -  enum tree_code code;
> -
> -  code = TREE_CODE (expr);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
> -    lto_output_ts_common_tree_pointers (ob, expr, ref_p);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_VECTOR))
> -    lto_output_ts_vector_tree_pointers (ob, expr, ref_p);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX))
> -    lto_output_ts_complex_tree_pointers (ob, expr, ref_p);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL))
> -    lto_output_ts_decl_minimal_tree_pointers (ob, expr, ref_p);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
> -    lto_output_ts_decl_common_tree_pointers (ob, expr, ref_p);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
> -    lto_output_ts_decl_non_common_tree_pointers (ob, expr, ref_p);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
> -    lto_output_ts_decl_with_vis_tree_pointers (ob, expr, ref_p);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL))
> -    lto_output_ts_field_decl_tree_pointers (ob, expr, ref_p);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
> -    lto_output_ts_function_decl_tree_pointers (ob, expr, ref_p);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
> -    lto_output_ts_type_common_tree_pointers (ob, expr, ref_p);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON))
> -    lto_output_ts_type_non_common_tree_pointers (ob, expr, ref_p);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_LIST))
> -    lto_output_ts_list_tree_pointers (ob, expr, ref_p);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_VEC))
> -    lto_output_ts_vec_tree_pointers (ob, expr, ref_p);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_EXP))
> -    lto_output_ts_exp_tree_pointers (ob, expr, ref_p);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
> -    lto_output_ts_block_tree_pointers (ob, expr, ref_p);
> -
> -  if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
> -    lto_output_ts_binfo_tree_pointers (ob, expr, ref_p);
> +    ob->cfg_stream = XCNEW (struct lto_output_stream);
>  
> -  if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
> -    lto_output_ts_constructor_tree_pointers (ob, expr, ref_p);
> +  clear_line_info (ob);
>  
> -  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
> -    lto_output_ts_target_option (ob, expr);
> +  ob->string_hash_table = htab_create (37, hash_string_slot_node,
> +				       eq_string_slot_node, NULL);
> +  gcc_obstack_init (&ob->obstack);
>  
> -  if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
> -    lto_output_ts_translation_unit_decl_tree_pointers (ob, expr);
> +  return ob;
>  }
>  
>  
> -/* 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.  */
> +/* Destroy the output block OB.  */
>  
> -static void
> -lto_output_tree_header (struct output_block *ob, tree expr)
> +void
> +destroy_output_block (struct output_block *ob)
>  {
> -  enum LTO_tags tag;
> -  enum tree_code code;
> +  enum lto_section_type section_type = ob->section_type;
>  
> -  /* 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
> -     EXPR on the reading side (such as the number of slots in
> -     variable sized nodes).  */
> -  tag = lto_tree_code_to_tag (code);
> -  output_record_start (ob, tag);
> +  htab_delete (ob->string_hash_table);
>  
> -  /* The following will cause bootstrap miscomparisons.  Enable with care.  */
> -#ifdef LTO_STREAMER_DEBUG
> -  /* This is used mainly for debugging purposes.  When the reader
> -     and the writer do not agree on a streamed node, the pointer
> -     value for EXPR can be used to track down the differences in
> -     the debugger.  */
> -  gcc_assert ((HOST_WIDEST_INT) (intptr_t) expr == (intptr_t) expr);
> -  output_sleb128 (ob, (HOST_WIDEST_INT) (intptr_t) expr);
> -#endif
> +  free (ob->main_stream);
> +  free (ob->string_stream);
> +  if (section_type == LTO_section_function_body)
> +    free (ob->cfg_stream);
> +
> +  lto_streamer_cache_delete (ob->writer_cache);
> +  obstack_free (&ob->obstack, NULL);
>  
> -  /* The text in strings and identifiers are completely emitted in
> -     the header.  */
> -  if (CODE_CONTAINS_STRUCT (code, TS_STRING))
> -    output_string_cst (ob, ob->main_stream, expr);
> -  else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER))
> -    output_identifier (ob, ob->main_stream, expr);
> -  else if (CODE_CONTAINS_STRUCT (code, TS_VEC))
> -    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);
> +  free (ob);
>  }
>  
>  
> -/* Write the code and class of builtin EXPR to output block OB.  IX is
> -   the index into the streamer cache where EXPR is stored.*/
> +/* Look up NODE in the type table and write the index for it to OB.  */
>  
>  static void
> -lto_output_builtin_tree (struct output_block *ob, tree expr)
> +output_type_ref (struct output_block *ob, tree node)
>  {
> -  gcc_assert (lto_stream_as_builtin_p (expr));
> +  output_record_start (ob, LTO_type_ref);
> +  lto_output_type_ref_index (ob->decl_state, ob->main_stream, node);
> +}
>  
> -  if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD
> -      && !targetm.builtin_decl)
> -    sorry ("gimple bytecode streams do not support machine specific builtin "
> -	   "functions on this target");
>  
> -  output_record_start (ob, LTO_builtin_decl);
> -  lto_output_enum (ob->main_stream, built_in_class, BUILT_IN_LAST,
> -		   DECL_BUILT_IN_CLASS (expr));
> -  output_uleb128 (ob, DECL_FUNCTION_CODE (expr));
> +/* Return true if tree node T is written to various tables.  For these
> +   nodes, we sometimes want to write their phyiscal representation
> +   (via lto_output_tree), and sometimes we need to emit an index
> +   reference into a table (via lto_output_tree_ref).  */
>  
> -  if (DECL_ASSEMBLER_NAME_SET_P (expr))
> -    {
> -      /* When the assembler name of a builtin gets a user name,
> -	 the new name is always prefixed with '*' by
> -	 set_builtin_user_assembler_name.  So, to prevent the
> -	 reader side from adding a second '*', we omit it here.  */
> -      const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (expr));
> -      if (strlen (str) > 1 && str[0] == '*')
> -	lto_output_string (ob, ob->main_stream, &str[1], true);
> -      else
> -	lto_output_string (ob, ob->main_stream, NULL, true);
> -    }
> +static bool
> +tree_is_indexable (tree t)
> +{
> +  if (TREE_CODE (t) == PARM_DECL)
> +    return false;
> +  else if (TREE_CODE (t) == VAR_DECL && decl_function_context (t)
> +	   && !TREE_STATIC (t))
> +    return false;
>    else
> -    lto_output_string (ob, ob->main_stream, NULL, true);
> +    return (TYPE_P (t) || DECL_P (t) || TREE_CODE (t) == SSA_NAME);
>  }
>  
>  
> -/* 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.  */
> +/* Output info about new location into bitpack BP.
> +   After outputting bitpack, lto_output_location_data has
> +   to be done to output actual data.  */
>  
> -static void
> -lto_write_tree (struct output_block *ob, tree expr, bool ref_p)
> +static inline void
> +lto_output_location_bitpack (struct bitpack_d *bp,
> +			     struct output_block *ob,
> +			     location_t loc)
>  {
> -  struct bitpack_d bp;
> +  expanded_location xloc;
>  
> -  /* Write the header, containing everything needed to materialize
> -     EXPR on the reading side.  */
> -  lto_output_tree_header (ob, expr);
> +  bp_pack_value (bp, loc == UNKNOWN_LOCATION, 1);
> +  if (loc == UNKNOWN_LOCATION)
> +    return;
>  
> -  /* 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);
> +  xloc = expand_location (loc);
>  
> -  /* Write all the pointer fields in EXPR.  */
> -  lto_output_tree_pointers (ob, expr, ref_p);
> +  bp_pack_value (bp, ob->current_file != xloc.file, 1);
> +  if (ob->current_file != xloc.file)
> +    bp_pack_var_len_unsigned (bp, lto_string_index (ob,
> +					            xloc.file,
> +						    strlen (xloc.file) + 1,
> +						    true));
> +  ob->current_file = xloc.file;
>  
> -  /* 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);
> +  bp_pack_value (bp, ob->current_line != xloc.line, 1);
> +  if (ob->current_line != xloc.line)
> +    bp_pack_var_len_unsigned (bp, xloc.line);
> +  ob->current_line = xloc.line;
>  
> -  /* Mark the end of EXPR.  */
> -  output_zero (ob);
> +  bp_pack_value (bp, ob->current_col != xloc.column, 1);
> +  if (ob->current_col != xloc.column)
> +    bp_pack_var_len_unsigned (bp, xloc.column);
> +  ob->current_col = xloc.column;
>  }
>  
>  
> -/* GIMPLE hook for writing GIMPLE-specific parts of trees.  OB, EXPR
> -   and REF_P are as in lto_write_tree.  */
> +/* Emit location LOC to output block OB.
> +   When bitpack is handy, it is more space effecient to call
> +   lto_output_location_bitpack with existing bitpack.  */
>  
>  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 integer constant CST to output block OB.  If REF_P is true,
> -   CST's type will be emitted as a reference.  */
> -
> -static void
> -lto_output_integer_cst (struct output_block *ob, tree cst, bool ref_p)
> +lto_output_location (struct output_block *ob, location_t loc)
>  {
> -  output_record_start (ob, lto_tree_code_to_tag (INTEGER_CST));
> -  lto_output_tree_or_ref (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));
> +  struct bitpack_d bp = bitpack_create (ob->main_stream);
> +  lto_output_location_bitpack (&bp, ob, loc);
> +  lto_output_bitpack (&bp);
>  }
>  
>  
> -/* 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.  */
> +/* If EXPR is an indexable tree node, output a reference to it to
> +   output block OB.  Otherwise, output the physical representation of
> +   EXPR to OB.  */
>  
>  void
> -lto_output_tree (struct output_block *ob, tree expr, bool ref_p)
> +lto_output_tree_ref (struct output_block *ob, tree expr)
>  {
> -  unsigned ix;
> -  bool existed_p;
> +  enum tree_code code;
>  
>    if (expr == NULL_TREE)
>      {
> @@ -1440,39 +199,99 @@ lto_output_tree (struct output_block *ob, tree expr, bool ref_p)
>        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)
> +  if (!tree_is_indexable (expr))
>      {
> -      lto_output_integer_cst (ob, expr, ref_p);
> +      /* Even though we are emitting the physical representation of
> +	 EXPR, its leaves must be emitted as references.  */
> +      lto_output_tree (ob, expr, true);
>        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))
> +  if (TYPE_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);
> +      output_type_ref (ob, expr);
> +      return;
>      }
> -  else
> +
> +  code = TREE_CODE (expr);
> +  switch (code)
>      {
> -      /* This is the first time we see EXPR, write its fields
> -	 to OB.  */
> -      lto_write_tree (ob, expr, ref_p);
> +    case SSA_NAME:
> +      output_record_start (ob, LTO_ssa_name_ref);
> +      output_uleb128 (ob, SSA_NAME_VERSION (expr));
> +      break;
> +
> +    case FIELD_DECL:
> +      output_record_start (ob, LTO_field_decl_ref);
> +      lto_output_field_decl_index (ob->decl_state, ob->main_stream, expr);
> +      break;
> +
> +    case FUNCTION_DECL:
> +      output_record_start (ob, LTO_function_decl_ref);
> +      lto_output_fn_decl_index (ob->decl_state, ob->main_stream, expr);
> +      break;
> +
> +    case VAR_DECL:
> +    case DEBUG_EXPR_DECL:
> +      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;
> +
> +    case CONST_DECL:
> +      output_record_start (ob, LTO_const_decl_ref);
> +      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
> +      break;
> +
> +    case IMPORTED_DECL:
> +      gcc_assert (decl_function_context (expr) == NULL);
> +      output_record_start (ob, LTO_imported_decl_ref);
> +      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
> +      break;
> +
> +    case TYPE_DECL:
> +      output_record_start (ob, LTO_type_decl_ref);
> +      lto_output_type_decl_index (ob->decl_state, ob->main_stream, expr);
> +      break;
> +
> +    case NAMESPACE_DECL:
> +      output_record_start (ob, LTO_namespace_decl_ref);
> +      lto_output_namespace_decl_index (ob->decl_state, ob->main_stream, expr);
> +      break;
> +
> +    case LABEL_DECL:
> +      output_record_start (ob, LTO_label_decl_ref);
> +      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
> +      break;
> +
> +    case RESULT_DECL:
> +      output_record_start (ob, LTO_result_decl_ref);
> +      lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
> +      break;
> +
> +    case TRANSLATION_UNIT_DECL:
> +      output_record_start (ob, LTO_translation_unit_decl_ref);
> +      lto_output_var_decl_index (ob->decl_state, ob->main_stream, 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 ();
> +	  }
> +      }
>      }
>  }
>  
> @@ -1722,190 +541,6 @@ output_cfg (struct output_block *ob, struct function *fn)
>  }
>  
>  
> -/* Output PHI function PHI to the main stream in OB.  */
> -
> -static void
> -output_phi (struct output_block *ob, gimple phi)
> -{
> -  unsigned i, len = gimple_phi_num_args (phi);
> -
> -  output_record_start (ob, lto_gimple_code_to_tag (GIMPLE_PHI));
> -  output_uleb128 (ob, SSA_NAME_VERSION (PHI_RESULT (phi)));
> -
> -  for (i = 0; i < len; i++)
> -    {
> -      lto_output_tree_ref (ob, gimple_phi_arg_def (phi, i));
> -      output_uleb128 (ob, gimple_phi_arg_edge (phi, i)->src->index);
> -      lto_output_location (ob, gimple_phi_arg_location (phi, i));
> -    }
> -}
> -
> -
> -/* Emit statement STMT on the main stream of output block OB.  */
> -
> -static void
> -output_gimple_stmt (struct output_block *ob, gimple stmt)
> -{
> -  unsigned i;
> -  enum gimple_code code;
> -  enum LTO_tags tag;
> -  struct bitpack_d bp;
> -
> -  /* Emit identifying tag.  */
> -  code = gimple_code (stmt);
> -  tag = lto_gimple_code_to_tag (code);
> -  output_record_start (ob, tag);
> -
> -  /* Emit the tuple header.  */
> -  bp = bitpack_create (ob->main_stream);
> -  bp_pack_var_len_unsigned (&bp, gimple_num_ops (stmt));
> -  bp_pack_value (&bp, gimple_no_warning_p (stmt), 1);
> -  if (is_gimple_assign (stmt))
> -    bp_pack_value (&bp, gimple_assign_nontemporal_move_p (stmt), 1);
> -  bp_pack_value (&bp, gimple_has_volatile_ops (stmt), 1);
> -  bp_pack_var_len_unsigned (&bp, stmt->gsbase.subcode);
> -  lto_output_bitpack (&bp);
> -
> -  /* Emit location information for the statement.  */
> -  lto_output_location (ob, gimple_location (stmt));
> -
> -  /* Emit the lexical block holding STMT.  */
> -  lto_output_tree (ob, gimple_block (stmt), true);
> -
> -  /* Emit the operands.  */
> -  switch (gimple_code (stmt))
> -    {
> -    case GIMPLE_RESX:
> -      output_sleb128 (ob, gimple_resx_region (stmt));
> -      break;
> -
> -    case GIMPLE_EH_MUST_NOT_THROW:
> -      lto_output_tree_ref (ob, gimple_eh_must_not_throw_fndecl (stmt));
> -      break;
> -
> -    case GIMPLE_EH_DISPATCH:
> -      output_sleb128 (ob, gimple_eh_dispatch_region (stmt));
> -      break;
> -
> -    case GIMPLE_ASM:
> -      lto_output_uleb128_stream (ob->main_stream, gimple_asm_ninputs (stmt));
> -      lto_output_uleb128_stream (ob->main_stream, gimple_asm_noutputs (stmt));
> -      lto_output_uleb128_stream (ob->main_stream, gimple_asm_nclobbers (stmt));
> -      lto_output_uleb128_stream (ob->main_stream, gimple_asm_nlabels (stmt));
> -      lto_output_string (ob, ob->main_stream, gimple_asm_string (stmt), true);
> -      /* Fallthru  */
> -
> -    case GIMPLE_ASSIGN:
> -    case GIMPLE_CALL:
> -    case GIMPLE_RETURN:
> -    case GIMPLE_SWITCH:
> -    case GIMPLE_LABEL:
> -    case GIMPLE_COND:
> -    case GIMPLE_GOTO:
> -    case GIMPLE_DEBUG:
> -      for (i = 0; i < gimple_num_ops (stmt); i++)
> -	{
> -	  tree op = gimple_op (stmt, i);
> -	  /* Wrap all uses of non-automatic variables inside MEM_REFs
> -	     so that we do not have to deal with type mismatches on
> -	     merged symbols during IL read in.  The first operand
> -	     of GIMPLE_DEBUG must be a decl, not MEM_REF, though.  */
> -	  if (op && (i || !is_gimple_debug (stmt)))
> -	    {
> -	      tree *basep = &op;
> -	      while (handled_component_p (*basep))
> -		basep = &TREE_OPERAND (*basep, 0);
> -	      if (TREE_CODE (*basep) == VAR_DECL
> -		  && !auto_var_in_fn_p (*basep, current_function_decl)
> -		  && !DECL_REGISTER (*basep))
> -		{
> -		  bool volatilep = TREE_THIS_VOLATILE (*basep);
> -		  *basep = build2 (MEM_REF, TREE_TYPE (*basep),
> -				   build_fold_addr_expr (*basep),
> -				   build_int_cst (build_pointer_type
> -						  (TREE_TYPE (*basep)), 0));
> -		  TREE_THIS_VOLATILE (*basep) = volatilep;
> -		}
> -	    }
> -	  lto_output_tree_ref (ob, op);
> -	}
> -      if (is_gimple_call (stmt))
> -	{
> -	  if (gimple_call_internal_p (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));
> -	}
> -      break;
> -
> -    case GIMPLE_NOP:
> -    case GIMPLE_PREDICT:
> -      break;
> -
> -    default:
> -      gcc_unreachable ();
> -    }
> -}
> -
> -
> -/* Output a basic block BB to the main stream in OB for this FN.  */
> -
> -static void
> -output_bb (struct output_block *ob, basic_block bb, struct function *fn)
> -{
> -  gimple_stmt_iterator bsi = gsi_start_bb (bb);
> -
> -  output_record_start (ob,
> -		       (!gsi_end_p (bsi)) || phi_nodes (bb)
> -		        ? LTO_bb1
> -			: LTO_bb0);
> -
> -  output_uleb128 (ob, bb->index);
> -  output_sleb128 (ob, bb->count);
> -  output_sleb128 (ob, bb->loop_depth);
> -  output_sleb128 (ob, bb->frequency);
> -  output_sleb128 (ob, bb->flags);
> -
> -  if (!gsi_end_p (bsi) || phi_nodes (bb))
> -    {
> -      /* Output the statements.  The list of statements is terminated
> -	 with a zero.  */
> -      for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
> -	{
> -	  int region;
> -	  gimple stmt = gsi_stmt (bsi);
> -
> -	  output_gimple_stmt (ob, stmt);
> -
> -	  /* Emit the EH region holding STMT.  */
> -	  region = lookup_stmt_eh_lp_fn (fn, stmt);
> -	  if (region != 0)
> -	    {
> -	      output_record_start (ob, LTO_eh_region);
> -	      output_sleb128 (ob, region);
> -	    }
> -	  else
> -	    output_record_start (ob, LTO_null);
> -	}
> -
> -      output_record_start (ob, LTO_null);
> -
> -      for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
> -	{
> -	  gimple phi = gsi_stmt (bsi);
> -
> -	  /* Only emit PHIs for gimple registers.  PHI nodes for .MEM
> -	     will be filled in on reading when the SSA form is
> -	     updated.  */
> -	  if (is_gimple_reg (gimple_phi_result (phi)))
> -	    output_phi (ob, phi);
> -	}
> -
> -      output_record_start (ob, LTO_null);
> -    }
> -}
> -
>  /* Create the header in the file using OB.  If the section type is for
>     a function, set FN to the decl for that function.  */
>  
> diff --git a/gcc/lto-streamer.c b/gcc/lto-streamer.c
> index 0608b33..328e654 100644
> --- a/gcc/lto-streamer.c
> +++ b/gcc/lto-streamer.c
> @@ -32,14 +32,13 @@ along with GCC; see the file COPYING3.  If not see
>  #include "diagnostic-core.h"
>  #include "bitmap.h"
>  #include "vec.h"
> +#include "tree-streamer.h"
>  #include "lto-streamer.h"
> +#include "streamer-hooks.h"
>  
>  /* Statistics gathered during LTO, WPA and LTRANS.  */
>  struct lto_stats_d lto_stats;
>  
> -/* Streamer hooks.  */
> -struct streamer_hooks streamer_hooks;
> -
>  /* LTO uses bitmaps with different life-times.  So use a seperate
>     obstack for all LTO bitmaps.  */
>  static bitmap_obstack lto_obstack;
> @@ -258,226 +257,6 @@ print_lto_report (void)
>  }
>  
>  
> -/* Check that all the TS_* structures handled by the lto_output_* and
> -   lto_input_* routines are exactly ALL the structures defined in
> -   treestruct.def.  */
> -
> -static void
> -check_handled_ts_structures (void)
> -{
> -  bool handled_p[LAST_TS_ENUM];
> -  unsigned i;
> -
> -  memset (&handled_p, 0, sizeof (handled_p));
> -
> -  /* These are the TS_* structures that are either handled or
> -     explicitly ignored by the streamer routines.  */
> -  handled_p[TS_BASE] = true;
> -  handled_p[TS_TYPED] = true;
> -  handled_p[TS_COMMON] = true;
> -  handled_p[TS_INT_CST] = true;
> -  handled_p[TS_REAL_CST] = true;
> -  handled_p[TS_FIXED_CST] = true;
> -  handled_p[TS_VECTOR] = true;
> -  handled_p[TS_STRING] = true;
> -  handled_p[TS_COMPLEX] = true;
> -  handled_p[TS_IDENTIFIER] = true;
> -  handled_p[TS_DECL_MINIMAL] = true;
> -  handled_p[TS_DECL_COMMON] = true;
> -  handled_p[TS_DECL_WRTL] = true;
> -  handled_p[TS_DECL_NON_COMMON] = true;
> -  handled_p[TS_DECL_WITH_VIS] = true;
> -  handled_p[TS_FIELD_DECL] = true;
> -  handled_p[TS_VAR_DECL] = true;
> -  handled_p[TS_PARM_DECL] = true;
> -  handled_p[TS_LABEL_DECL] = true;
> -  handled_p[TS_RESULT_DECL] = true;
> -  handled_p[TS_CONST_DECL] = true;
> -  handled_p[TS_TYPE_DECL] = true;
> -  handled_p[TS_FUNCTION_DECL] = true;
> -  handled_p[TS_TYPE_COMMON] = true;
> -  handled_p[TS_TYPE_WITH_LANG_SPECIFIC] = true;
> -  handled_p[TS_TYPE_NON_COMMON] = true;
> -  handled_p[TS_LIST] = true;
> -  handled_p[TS_VEC] = true;
> -  handled_p[TS_EXP] = true;
> -  handled_p[TS_SSA_NAME] = true;
> -  handled_p[TS_BLOCK] = true;
> -  handled_p[TS_BINFO] = true;
> -  handled_p[TS_STATEMENT_LIST] = true;
> -  handled_p[TS_CONSTRUCTOR] = true;
> -  handled_p[TS_OMP_CLAUSE] = true;
> -  handled_p[TS_OPTIMIZATION] = true;
> -  handled_p[TS_TARGET_OPTION] = true;
> -  handled_p[TS_TRANSLATION_UNIT_DECL] = true;
> -
> -  /* Anything not marked above will trigger the following assertion.
> -     If this assertion triggers, it means that there is a new TS_*
> -     structure that should be handled by the streamer.  */
> -  for (i = 0; i < LAST_TS_ENUM; i++)
> -    gcc_assert (handled_p[i]);
> -}
> -
> -
> -/* Helper for lto_streamer_cache_insert_1.  Add T to CACHE->NODES at
> -   slot IX.  */
> -
> -static void
> -lto_streamer_cache_add_to_node_array (struct lto_streamer_cache_d *cache,
> -				      unsigned ix, tree t)
> -{
> -  /* Make sure we're either replacing an old element or
> -     appending consecutively.  */
> -  gcc_assert (ix <= VEC_length (tree, cache->nodes));
> -
> -  if (ix == VEC_length (tree, cache->nodes))
> -    VEC_safe_push (tree, heap, cache->nodes, t);
> -  else
> -    VEC_replace (tree, cache->nodes, ix, t);
> -}
> -
> -
> -/* Helper for lto_streamer_cache_insert and lto_streamer_cache_insert_at.
> -   CACHE, T, and IX_P are as in lto_streamer_cache_insert.
> -
> -   If INSERT_AT_NEXT_SLOT_P is true, T is inserted at the next available
> -   slot in the cache.  Otherwise, T is inserted at the position indicated
> -   in *IX_P.
> -
> -   If T already existed in CACHE, return true.  Otherwise,
> -   return false.  */
> -
> -static bool
> -lto_streamer_cache_insert_1 (struct lto_streamer_cache_d *cache,
> -			     tree t, unsigned *ix_p,
> -			     bool insert_at_next_slot_p)
> -{
> -  void **slot;
> -  unsigned ix;
> -  bool existed_p;
> -
> -  gcc_assert (t);
> -
> -  slot = pointer_map_insert (cache->node_map, t);
> -  if (!*slot)
> -    {
> -      /* Determine the next slot to use in the cache.  */
> -      if (insert_at_next_slot_p)
> -	ix = VEC_length (tree, cache->nodes);
> -      else
> -	ix = *ix_p;
> -       *slot = (void *)(size_t) (ix + 1);
> -
> -      lto_streamer_cache_add_to_node_array (cache, ix, t);
> -
> -      /* Indicate that the item was not present in the cache.  */
> -      existed_p = false;
> -    }
> -  else
> -    {
> -      ix = (size_t) *slot - 1;
> -
> -      if (!insert_at_next_slot_p && ix != *ix_p)
> -	{
> -	  /* If the caller wants to insert T at a specific slot
> -	     location, and ENTRY->TO does not match *IX_P, add T to
> -	     the requested location slot.  */
> -	  ix = *ix_p;
> -	  lto_streamer_cache_add_to_node_array (cache, ix, t);
> -	}
> -
> -      /* Indicate that T was already in the cache.  */
> -      existed_p = true;
> -    }
> -
> -  if (ix_p)
> -    *ix_p = ix;
> -
> -  return existed_p;
> -}
> -
> -
> -/* Insert tree node T in CACHE.  If T already existed in the cache
> -   return true.  Otherwise, return false.
> -
> -   If IX_P is non-null, update it with the index into the cache where
> -   T has been stored.  */
> -
> -bool
> -lto_streamer_cache_insert (struct lto_streamer_cache_d *cache, tree t,
> -			   unsigned *ix_p)
> -{
> -  return lto_streamer_cache_insert_1 (cache, t, ix_p, true);
> -}
> -
> -
> -/* Insert tree node T in CACHE at slot IX.  If T already
> -   existed in the cache return true.  Otherwise, return false.  */
> -
> -bool
> -lto_streamer_cache_insert_at (struct lto_streamer_cache_d *cache,
> -			      tree t, unsigned ix)
> -{
> -  return lto_streamer_cache_insert_1 (cache, t, &ix, false);
> -}
> -
> -
> -/* Appends tree node T to CACHE, even if T already existed in it.  */
> -
> -void
> -lto_streamer_cache_append (struct lto_streamer_cache_d *cache, tree t)
> -{
> -  unsigned ix = VEC_length (tree, cache->nodes);
> -  lto_streamer_cache_insert_1 (cache, t, &ix, false);
> -}
> -
> -/* Return true if tree node T exists in CACHE, otherwise false.  If IX_P is
> -   not NULL, write to *IX_P the index into the cache where T is stored
> -   ((unsigned)-1 if T is not found).  */
> -
> -bool
> -lto_streamer_cache_lookup (struct lto_streamer_cache_d *cache, tree t,
> -			   unsigned *ix_p)
> -{
> -  void **slot;
> -  bool retval;
> -  unsigned ix;
> -
> -  gcc_assert (t);
> -
> -  slot = pointer_map_contains  (cache->node_map, t);
> -  if (slot == NULL)
> -    {
> -      retval = false;
> -      ix = -1;
> -    }
> -  else
> -    {
> -      retval = true;
> -      ix = (size_t) *slot - 1;
> -    }
> -
> -  if (ix_p)
> -    *ix_p = ix;
> -
> -  return retval;
> -}
> -
> -
> -/* Return the tree node at slot IX in CACHE.  */
> -
> -tree
> -lto_streamer_cache_get (struct lto_streamer_cache_d *cache, unsigned ix)
> -{
> -  gcc_assert (cache);
> -
> -  /* Make sure we're not requesting something we don't have.  */
> -  gcc_assert (ix < VEC_length (tree, cache->nodes));
> -
> -  return VEC_index (tree, cache->nodes, ix);
> -}
> -
> -
>  /* Record NODE in CACHE.  */
>  
>  static void
> @@ -557,39 +336,6 @@ lto_preload_common_nodes (struct lto_streamer_cache_d *cache)
>        lto_record_common_node (cache, global_trees[i]);
>  }
>  
> -/* Create a cache of pickled nodes.  */
> -
> -struct lto_streamer_cache_d *
> -lto_streamer_cache_create (void)
> -{
> -  struct lto_streamer_cache_d *cache;
> -
> -  cache = XCNEW (struct lto_streamer_cache_d);
> -
> -  cache->node_map = pointer_map_create ();
> -
> -  /* 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);
> -
> -  return cache;
> -}
> -
> -
> -/* Delete the streamer cache C.  */
> -
> -void
> -lto_streamer_cache_delete (struct lto_streamer_cache_d *c)
> -{
> -  if (c == NULL)
> -    return;
> -
> -  pointer_map_destroy (c->node_map);
> -  VEC_free (tree, heap, c->nodes);
> -  free (c);
> -}
> -
>  
>  #ifdef LTO_STREAMER_DEBUG
>  static htab_t tree_htab;
> @@ -756,12 +502,3 @@ lto_streamer_hooks_init (void)
>    streamer_hooks.write_tree = lto_streamer_write_tree;
>    streamer_hooks.read_tree = lto_streamer_read_tree;
>  }
> -
> -
> -/* Initialize the current set of streamer hooks.  */
> -
> -void
> -streamer_hooks_init (void)
> -{
> -  memset (&streamer_hooks, 0, sizeof (streamer_hooks));
> -}
> diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
> index 157e5c0..230838b 100644
> --- a/gcc/lto-streamer.h
> +++ b/gcc/lto-streamer.h
> @@ -32,12 +32,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "vecprim.h"
>  #include "alloc-pool.h"
>  #include "gcov-io.h"
> -
> -/* Forward declarations to avoid including unnecessary headers.  */
> -struct output_block;
> -struct lto_input_block;
> -struct data_in;
> -struct bitpack_d;
> +#include "diagnostic.h"
>  
>  /* Define when debugging the LTO streamer.  This causes the writer
>     to output the numeric value for the memory address of the tree node
> @@ -152,27 +147,6 @@ struct bitpack_d;
>  typedef unsigned char	lto_decl_flags_t;
>  
>  
> -/* Data structures used to pack values and bitflags into a vector of
> -   words.  Used to stream values of a fixed number of bits in a space
> -   efficient way.  */
> -static unsigned const BITS_PER_BITPACK_WORD = HOST_BITS_PER_WIDE_INT;
> -
> -typedef unsigned HOST_WIDE_INT bitpack_word_t;
> -DEF_VEC_I(bitpack_word_t);
> -DEF_VEC_ALLOC_I(bitpack_word_t, heap);
> -
> -struct bitpack_d
> -{
> -  /* The position of the first unused or unconsumed bit in the word.  */
> -  unsigned pos;
> -
> -  /* The current word we are (un)packing.  */
> -  bitpack_word_t word;
> -
> -  /* The lto_output_stream or the lto_input_block we are streaming to/from.  */
> -  void *stream;
> -};
> -
>  /* Tags representing the various IL objects written to the bytecode file
>     (GIMPLE statements, basic blocks, EH regions, tree nodes, etc).
>  
> @@ -332,33 +306,6 @@ typedef void (lto_free_section_data_f) (struct lto_file_decl_data *,
>  					const char *,
>  					size_t);
>  
> -/* Cache of pickled nodes.  Used to avoid writing the same node more
> -   than once.  The first time a tree node is streamed out, it is
> -   entered in this cache.  Subsequent references to the same node are
> -   resolved by looking it up in this cache.
> -
> -   This is used in two ways:
> -
> -   - On the writing side, the first time T is added to STREAMER_CACHE,
> -     a new reference index is created for T and T is emitted on the
> -     stream.  If T needs to be emitted again to the stream, instead of
> -     pickling it again, the reference index is emitted.
> -
> -   - On the reading side, the first time T is read from the stream, it
> -     is reconstructed in memory and a new reference index created for
> -     T.  The reconstructed T is inserted in some array so that when
> -     the reference index for T is found in the input stream, it can be
> -     used to look up into the array to get the reconstructed T.  */
> -struct lto_streamer_cache_d
> -{
> -  /* The mapping between tree nodes and slots into the nodes array.  */
> -  struct pointer_map_t *node_map;
> -
> -  /* The nodes pickled so far.  */
> -  VEC(tree,heap) *nodes;
> -};
> -
> -
>  /* Structure used as buffer for reading an LTO file.  */
>  struct lto_input_block
>  {
> @@ -747,86 +694,6 @@ struct data_in
>  };
>  
>  
> -/* Streamer hooks.  These functions do additional processing as
> -   needed by the module.  There are two types of callbacks, those that
> -   replace the default behavior and those that supplement it.
> -
> -   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.  */
> -  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);
> -};
> -
> -/* Streamer hooks.  */
> -extern struct streamer_hooks streamer_hooks;
> -
>  /* In lto-section-in.c  */
>  extern struct lto_input_block * lto_create_simple_input_block (
>  			       struct lto_file_decl_data *,
> @@ -864,10 +731,6 @@ extern void lto_section_overrun (struct lto_input_block *) ATTRIBUTE_NORETURN;
>  extern void lto_value_range_error (const char *,
>  				   HOST_WIDE_INT, HOST_WIDE_INT,
>  				   HOST_WIDE_INT) ATTRIBUTE_NORETURN;
> -extern void bp_pack_var_len_unsigned (struct bitpack_d *, unsigned HOST_WIDE_INT);
> -extern void bp_pack_var_len_int (struct bitpack_d *, HOST_WIDE_INT);
> -extern unsigned HOST_WIDE_INT bp_unpack_var_len_unsigned (struct bitpack_d *);
> -extern HOST_WIDE_INT bp_unpack_var_len_int (struct bitpack_d *);
>  
>  /* In lto-section-out.c  */
>  extern hashval_t lto_hash_decl_slot_node (const void *);
> @@ -919,16 +782,6 @@ extern bitmap lto_bitmap_alloc (void);
>  extern void lto_bitmap_free (bitmap);
>  extern char *lto_get_section_name (int, const char *, struct lto_file_decl_data *);
>  extern void print_lto_report (void);
> -extern bool lto_streamer_cache_insert (struct lto_streamer_cache_d *, tree,
> -				       unsigned *);
> -extern bool lto_streamer_cache_insert_at (struct lto_streamer_cache_d *, tree,
> -					  unsigned);
> -extern void lto_streamer_cache_append (struct lto_streamer_cache_d *, tree);
> -extern bool lto_streamer_cache_lookup (struct lto_streamer_cache_d *, tree,
> -				       unsigned *);
> -extern tree lto_streamer_cache_get (struct lto_streamer_cache_d *, unsigned);
> -extern struct lto_streamer_cache_d *lto_streamer_cache_create (void);
> -extern void lto_streamer_cache_delete (struct lto_streamer_cache_d *);
>  extern void lto_streamer_init (void);
>  extern bool gate_lto_out (void);
>  #ifdef LTO_STREAMER_DEBUG
> @@ -938,15 +791,10 @@ extern void lto_orig_address_remove (tree);
>  #endif
>  extern void lto_check_version (int, int);
>  extern void lto_streamer_hooks_init (void);
> -extern void lto_streamer_write_tree (struct output_block *, tree, bool);
> -extern void lto_streamer_read_tree (struct lto_input_block *,
> -				     struct data_in *, tree);
> -extern void streamer_hooks_init (void);
>  
>  /* In lto-streamer-in.c */
>  extern void lto_input_cgraph (struct lto_file_decl_data *, const char *);
>  extern void lto_reader_init (void);
> -extern tree lto_input_tree (struct lto_input_block *, struct data_in *);
>  extern void lto_input_function_body (struct lto_file_decl_data *, tree,
>  				     const char *);
>  extern void lto_input_constructors_and_inits (struct lto_file_decl_data *,
> @@ -955,9 +803,12 @@ extern struct data_in *lto_data_in_create (struct lto_file_decl_data *,
>  				    const char *, unsigned,
>  				    VEC(ld_plugin_symbol_resolution_t,heap) *);
>  extern void lto_data_in_delete (struct data_in *);
> -extern const char *lto_input_string (struct data_in *,
> -				     struct lto_input_block *);
>  extern void lto_input_data_block (struct lto_input_block *, void *, size_t);
> +location_t lto_input_location (struct lto_input_block *, struct data_in *);
> +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);
>  
>  
>  /* In lto-streamer-out.c  */
> @@ -971,6 +822,8 @@ 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);
>  
>  
>  /* In lto-cgraph.c  */
> @@ -1096,6 +949,28 @@ lto_tag_to_tree_code (enum LTO_tags tag)
>    return (enum tree_code) ((unsigned) tag - 1);
>  }
>  
> +/* Check that tag ACTUAL == EXPECTED.  */
> +static inline void
> +lto_tag_check (enum LTO_tags actual, enum LTO_tags expected)
> +{
> +  if (actual != expected)
> +    internal_error ("bytecode stream: expected tag %s instead of %s",
> +		    lto_tag_name (expected), lto_tag_name (actual));
> +}
> +
> +/* Check that tag ACTUAL is in the range [TAG1, TAG2].  */
> +static inline void
> +lto_tag_check_range (enum LTO_tags actual, enum LTO_tags tag1,
> +		     enum LTO_tags tag2)
> +{
> +  if (actual < tag1 || actual > tag2)
> +    internal_error ("bytecode stream: tag %s is not in the expected range "
> +		    "[%s, %s]",
> +		    lto_tag_name (actual),
> +		    lto_tag_name (tag1),
> +		    lto_tag_name (tag2));
> +}
> +
>  /* Initialize an lto_out_decl_buffer ENCODER.  */
>  static inline void
>  lto_init_tree_ref_encoder (struct lto_tree_ref_encoder *encoder,
> @@ -1160,232 +1035,4 @@ DEFINE_DECL_STREAM_FUNCS (TYPE_DECL, type_decl)
>  DEFINE_DECL_STREAM_FUNCS (NAMESPACE_DECL, namespace_decl)
>  DEFINE_DECL_STREAM_FUNCS (LABEL_DECL, label_decl)
>  
> -/* Returns a new bit-packing context for bit-packing into S.  */
> -static inline struct bitpack_d
> -bitpack_create (struct lto_output_stream *s)
> -{
> -  struct bitpack_d bp;
> -  bp.pos = 0;
> -  bp.word = 0;
> -  bp.stream = (void *)s;
> -  return bp;
> -}
> -
> -/* Pack the NBITS bit sized value VAL into the bit-packing context BP.  */
> -static inline void
> -bp_pack_value (struct bitpack_d *bp, bitpack_word_t val, unsigned nbits)
> -{
> -  bitpack_word_t word = bp->word;
> -  int pos = bp->pos;
> -
> -  /* Verify that VAL fits in the NBITS.  */
> -  gcc_checking_assert (nbits == BITS_PER_BITPACK_WORD
> -		       || !(val & ~(((bitpack_word_t)1<<nbits)-1)));
> -
> -  /* If val does not fit into the current bitpack word switch to the
> -     next one.  */
> -  if (pos + nbits > BITS_PER_BITPACK_WORD)
> -    {
> -      lto_output_uleb128_stream ((struct lto_output_stream *) bp->stream, word);
> -      word = val;
> -      pos = nbits;
> -    }
> -  else
> -    {
> -      word |= val << pos;
> -      pos += nbits;
> -    }
> -  bp->word = word;
> -  bp->pos = pos;
> -}
> -
> -/* Finishes bit-packing of BP.  */
> -static inline void
> -lto_output_bitpack (struct bitpack_d *bp)
> -{
> -  lto_output_uleb128_stream ((struct lto_output_stream *) bp->stream,
> -			     bp->word);
> -  bp->word = 0;
> -  bp->pos = 0;
> -}
> -
> -/* Returns a new bit-packing context for bit-unpacking from IB.  */
> -static inline struct bitpack_d
> -lto_input_bitpack (struct lto_input_block *ib)
> -{
> -  struct bitpack_d bp;
> -  bp.word = lto_input_uleb128 (ib);
> -  bp.pos = 0;
> -  bp.stream = (void *)ib;
> -  return bp;
> -}
> -
> -/* Unpacks NBITS bits from the bit-packing context BP and returns them.  */
> -static inline bitpack_word_t
> -bp_unpack_value (struct bitpack_d *bp, unsigned nbits)
> -{
> -  bitpack_word_t mask, val;
> -  int pos = bp->pos;
> -
> -  mask = (nbits == BITS_PER_BITPACK_WORD
> -	  ? (bitpack_word_t) -1
> -	  : ((bitpack_word_t) 1 << nbits) - 1);
> -
> -  /* If there are not continuous nbits in the current bitpack word
> -     switch to the next one.  */
> -  if (pos + nbits > BITS_PER_BITPACK_WORD)
> -    {
> -      bp->word = val = lto_input_uleb128 ((struct lto_input_block *)bp->stream);
> -      bp->pos = nbits;
> -      return val & mask;
> -    }
> -  val = bp->word;
> -  val >>= pos;
> -  bp->pos = pos + nbits;
> -
> -  return val & mask;
> -}
> -
> -
> -/* Write a character to the output block.  */
> -
> -static inline void
> -lto_output_1_stream (struct lto_output_stream *obs, char c)
> -{
> -  /* No space left.  */
> -  if (obs->left_in_block == 0)
> -    lto_append_block (obs);
> -
> -  /* Write the actual character.  */
> -  *obs->current_pointer = c;
> -  obs->current_pointer++;
> -  obs->total_size++;
> -  obs->left_in_block--;
> -}
> -
> -
> -/* Read byte from the input block.  */
> -
> -static inline unsigned char
> -lto_input_1_unsigned (struct lto_input_block *ib)
> -{
> -  if (ib->p >= ib->len)
> -    lto_section_overrun (ib);
> -  return (ib->data[ib->p++]);
> -}
> -
> -/* Output VAL into OBS and verify it is in range MIN...MAX that is supposed
> -   to be compile time constant.
> -   Be host independent, limit range to 31bits.  */
> -
> -static inline void
> -lto_output_int_in_range (struct lto_output_stream *obs,
> -			 HOST_WIDE_INT min,
> -			 HOST_WIDE_INT max,
> -			 HOST_WIDE_INT val)
> -{
> -  HOST_WIDE_INT range = max - min;
> -
> -  gcc_checking_assert (val >= min && val <= max && range > 0
> -		       && range < 0x7fffffff);
> -
> -  val -= min;
> -  lto_output_1_stream (obs, val & 255);
> -  if (range >= 0xff)
> -    lto_output_1_stream (obs, (val >> 8) & 255);
> -  if (range >= 0xffff)
> -    lto_output_1_stream (obs, (val >> 16) & 255);
> -  if (range >= 0xffffff)
> -    lto_output_1_stream (obs, (val >> 24) & 255);
> -}
> -
> -/* Input VAL into OBS and verify it is in range MIN...MAX that is supposed
> -   to be compile time constant.  PURPOSE is used for error reporting.  */
> -
> -static inline HOST_WIDE_INT
> -lto_input_int_in_range (struct lto_input_block *ib,
> -			const char *purpose,
> -			HOST_WIDE_INT min,
> -			HOST_WIDE_INT max)
> -{
> -  HOST_WIDE_INT range = max - min;
> -  HOST_WIDE_INT val = lto_input_1_unsigned (ib);
> -
> -  gcc_checking_assert (range > 0 && range < 0x7fffffff);
> -
> -  if (range >= 0xff)
> -    val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 8;
> -  if (range >= 0xffff)
> -    val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 16;
> -  if (range >= 0xffffff)
> -    val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 24;
> -  val += min;
> -  if (val < min || val > max)
> -    lto_value_range_error (purpose, val, min, max);
> -  return val;
> -}
> -
> -
> -/* Output VAL into BP and verify it is in range MIN...MAX that is supposed
> -   to be compile time constant.
> -   Be host independent, limit range to 31bits.  */
> -
> -static inline void
> -bp_pack_int_in_range (struct bitpack_d *bp,
> -		      HOST_WIDE_INT min,
> -		      HOST_WIDE_INT max,
> -		      HOST_WIDE_INT val)
> -{
> -  HOST_WIDE_INT range = max - min;
> -  int nbits = floor_log2 (range) + 1;
> -
> -  gcc_checking_assert (val >= min && val <= max && range > 0
> -		       && range < 0x7fffffff);
> -
> -  val -= min;
> -  bp_pack_value (bp, val, nbits);
> -}
> -
> -/* Input VAL into BP and verify it is in range MIN...MAX that is supposed
> -   to be compile time constant.  PURPOSE is used for error reporting.  */
> -
> -static inline HOST_WIDE_INT
> -bp_unpack_int_in_range (struct bitpack_d *bp,
> -		        const char *purpose,
> -		        HOST_WIDE_INT min,
> -		        HOST_WIDE_INT max)
> -{
> -  HOST_WIDE_INT range = max - min;
> -  int nbits = floor_log2 (range) + 1;
> -  HOST_WIDE_INT val = bp_unpack_value (bp, nbits);
> -
> -  gcc_checking_assert (range > 0 && range < 0x7fffffff);
> -
> -  if (val < min || val > max)
> -    lto_value_range_error (purpose, val, min, max);
> -  return val;
> -}
> -
> -/* Output VAL of type "enum enum_name" into OBS.
> -   Assume range 0...ENUM_LAST - 1.  */
> -#define lto_output_enum(obs,enum_name,enum_last,val) \
> -  lto_output_int_in_range ((obs), 0, (int)(enum_last) - 1, (int)(val))
> -
> -/* Input enum of type "enum enum_name" from IB.
> -   Assume range 0...ENUM_LAST - 1.  */
> -#define lto_input_enum(ib,enum_name,enum_last) \
> -  (enum enum_name)lto_input_int_in_range ((ib), #enum_name, 0, \
> -					  (int)(enum_last) - 1)
> -
> -/* Output VAL of type "enum enum_name" into BP.
> -   Assume range 0...ENUM_LAST - 1.  */
> -#define bp_pack_enum(bp,enum_name,enum_last,val) \
> -  bp_pack_int_in_range ((bp), 0, (int)(enum_last) - 1, (int)(val))
> -
> -/* Input enum of type "enum enum_name" from BP.
> -   Assume range 0...ENUM_LAST - 1.  */
> -#define bp_unpack_enum(bp,enum_name,enum_last) \
> -  (enum enum_name)bp_unpack_int_in_range ((bp), #enum_name, 0, \
> -					(int)(enum_last) - 1)
> -
>  #endif /* GCC_LTO_STREAMER_H  */
> diff --git a/gcc/lto/Make-lang.in b/gcc/lto/Make-lang.in
> index d5a15f8..c48c8d2 100644
> --- a/gcc/lto/Make-lang.in
> +++ b/gcc/lto/Make-lang.in
> @@ -86,7 +86,7 @@ lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \
>  	langhooks.h $(VEC_H) $(BITMAP_H) pointer-set.h $(IPA_PROP_H) \
>  	$(COMMON_H) debug.h $(TIMEVAR_H) $(GIMPLE_H) $(LTO_H) $(LTO_TREE_H) \
>  	$(LTO_TAGS_H) $(LTO_STREAMER_H) $(SPLAY_TREE_H) gt-lto-lto.h $(PARAMS_H) \
> -	ipa-inline.h $(IPA_UTILS_H)
> +	ipa-inline.h $(IPA_UTILS_H) $(TREE_STREAMER_H)
>  lto/lto-object.o: lto/lto-object.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
>  	$(DIAGNOSTIC_CORE_H) $(LTO_H) $(TM_H) $(LTO_STREAMER_H) \
>  	../include/simple-object.h
> diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
> index 4323c4f..93ff805 100644
> --- a/gcc/lto/lto.c
> +++ b/gcc/lto/lto.c
> @@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "lto.h"
>  #include "lto-tree.h"
>  #include "lto-streamer.h"
> +#include "tree-streamer.h"
>  #include "splay-tree.h"
>  #include "params.h"
>  #include "ipa-inline.h"
> diff --git a/gcc/streamer-hooks.c b/gcc/streamer-hooks.c
> new file mode 100644
> index 0000000..ef5fee3
> --- /dev/null
> +++ b/gcc/streamer-hooks.c
> @@ -0,0 +1,37 @@
> +/* Streamer hooks.  Support for adding streamer-specific callbacks to
> +   generic streaming routines.
> +
> +   Copyright 2011 Free Software Foundation, Inc.
> +   Contributed by Diego Novillo <dnovillo@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "streamer-hooks.h"
> +
> +/* Streamer hooks.  */
> +struct streamer_hooks streamer_hooks;
> +
> +/* Initialize the current set of streamer hooks.  */
> +
> +void
> +streamer_hooks_init (void)
> +{
> +  memset (&streamer_hooks, 0, sizeof (streamer_hooks));
> +}
> diff --git a/gcc/streamer-hooks.h b/gcc/streamer-hooks.h
> new file mode 100644
> index 0000000..29a6591
> --- /dev/null
> +++ b/gcc/streamer-hooks.h
> @@ -0,0 +1,118 @@
> +/* Streamer hooks.  Support for adding streamer-specific callbacks to
> +   generic streaming routines.
> +
> +   Copyright 2011 Free Software Foundation, Inc.
> +   Contributed by Diego Novillo <dnovillo@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GCC_STREAMER_HOOKS_H
> +#define GCC_STREAMER_HOOKS_H
> +
> +#include "tree.h"
> +
> +/* Forward declarations to avoid including unnecessary headers.  */
> +struct output_block;
> +struct lto_input_block;
> +struct data_in;
> +struct bitpack_d;
> +struct lto_streamer_cache_d;
> +
> +/* Streamer hooks.  These functions do additional processing as
> +   needed by the module.  There are two types of callbacks, those that
> +   replace the default behavior and those that supplement it.
> +
> +   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.  */
> +  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);
> +};
> +
> +/* Streamer hooks.  */
> +extern struct streamer_hooks streamer_hooks;
> +
> +/* In streamer-hooks.c.  */
> +void streamer_hooks_init (void);
> +
> +#endif  /* GCC_STREAMER_HOOKS_H  */
> diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
> new file mode 100644
> index 0000000..cd2f221
> --- /dev/null
> +++ b/gcc/tree-streamer-in.c
> @@ -0,0 +1,1153 @@
> +/* Routines for reading trees from a file stream.
> +
> +   Copyright 2011 Free Software Foundation, Inc.
> +   Contributed by Diego Novillo <dnovillo@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "diagnostic.h"
> +#include "tree.h"
> +#include "tree-flow.h"
> +#include "tree-streamer.h"
> +#include "data-streamer.h"
> +#include "streamer-hooks.h"
> +#include "lto-streamer.h"
> +
> +/* Read a STRING_CST from the string table in DATA_IN using input
> +   block IB.  */
> +
> +tree
> +input_string_cst (struct data_in *data_in, struct lto_input_block *ib)
> +{
> +  unsigned int len;
> +  const char * ptr;
> +
> +  ptr = input_string_internal (data_in, ib, &len);
> +  if (!ptr)
> +    return NULL;
> +  return build_string (len, ptr);
> +}
> +
> +
> +/* Read an IDENTIFIER from the string table in DATA_IN using input
> +   block IB.  */
> +
> +static tree
> +input_identifier (struct data_in *data_in, struct lto_input_block *ib)
> +{
> +  unsigned int len;
> +  const char *ptr;
> +
> +  ptr = input_string_internal (data_in, ib, &len);
> +  if (!ptr)
> +    return NULL;
> +  return get_identifier_with_length (ptr, len);
> +}
> +
> +
> +/* Read a chain of tree nodes from input block IB. DATA_IN contains
> +   tables and descriptors for the file being read.  */
> +
> +static tree
> +lto_input_chain (struct lto_input_block *ib, struct data_in *data_in)
> +{
> +  int i, count;
> +  tree first, prev, curr;
> +
> +  first = prev = NULL_TREE;
> +  count = lto_input_sleb128 (ib);
> +  for (i = 0; i < count; i++)
> +    {
> +      curr = lto_input_tree (ib, data_in);
> +      if (prev)
> +	TREE_CHAIN (prev) = curr;
> +      else
> +	first = curr;
> +
> +      TREE_CHAIN (curr) = NULL_TREE;
> +      prev = curr;
> +    }
> +
> +  return first;
> +}
> +
> +
> +/* Unpack all the non-pointer fields of the TS_BASE structure of
> +   expression EXPR from bitpack BP.  */
> +
> +static void
> +unpack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  /* Note that the code for EXPR has already been unpacked to create EXPR in
> +     lto_materialize_tree.  */
> +  if (!TYPE_P (expr))
> +    {
> +      TREE_SIDE_EFFECTS (expr) = (unsigned) bp_unpack_value (bp, 1);
> +      TREE_CONSTANT (expr) = (unsigned) bp_unpack_value (bp, 1);
> +      TREE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1);
> +
> +      /* TREE_PUBLIC is used on types to indicate that the type
> +	 has a TYPE_CACHED_VALUES vector.  This is not streamed out,
> +	 so we skip it here.  */
> +      TREE_PUBLIC (expr) = (unsigned) bp_unpack_value (bp, 1);
> +    }
> +  else
> +    bp_unpack_value (bp, 4);
> +  TREE_ADDRESSABLE (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  TREE_THIS_VOLATILE (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  if (DECL_P (expr))
> +    DECL_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  else if (TYPE_P (expr))
> +    TYPE_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  else
> +    bp_unpack_value (bp, 1);
> +  TREE_ASM_WRITTEN (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  if (TYPE_P (expr))
> +    TYPE_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  else
> +    TREE_NO_WARNING (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  TREE_USED (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  TREE_NOTHROW (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  TREE_STATIC (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  TREE_PRIVATE (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  TREE_PROTECTED (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  TREE_DEPRECATED (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  if (TYPE_P (expr))
> +    TYPE_SATURATING (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  else if (TREE_CODE (expr) == SSA_NAME)
> +    SSA_NAME_IS_DEFAULT_DEF (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  else
> +    bp_unpack_value (bp, 1);
> +}
> +
> +
> +/* Unpack all the non-pointer fields of the TS_REAL_CST structure of
> +   expression EXPR from bitpack BP.  */
> +
> +static void
> +unpack_ts_real_cst_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  unsigned i;
> +  REAL_VALUE_TYPE r;
> +  REAL_VALUE_TYPE *rp;
> +
> +  r.cl = (unsigned) bp_unpack_value (bp, 2);
> +  r.decimal = (unsigned) bp_unpack_value (bp, 1);
> +  r.sign = (unsigned) bp_unpack_value (bp, 1);
> +  r.signalling = (unsigned) bp_unpack_value (bp, 1);
> +  r.canonical = (unsigned) bp_unpack_value (bp, 1);
> +  r.uexp = (unsigned) bp_unpack_value (bp, EXP_BITS);
> +  for (i = 0; i < SIGSZ; i++)
> +    r.sig[i] = (unsigned long) bp_unpack_value (bp, HOST_BITS_PER_LONG);
> +
> +  rp = ggc_alloc_real_value ();
> +  memcpy (rp, &r, sizeof (REAL_VALUE_TYPE));
> +  TREE_REAL_CST_PTR (expr) = rp;
> +}
> +
> +
> +/* Unpack all the non-pointer fields of the TS_FIXED_CST structure of
> +   expression EXPR from bitpack BP.  */
> +
> +static void
> +unpack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  struct fixed_value fv;
> +
> +  fv.mode = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
> +  fv.data.low = bp_unpack_var_len_int (bp);
> +  fv.data.high = bp_unpack_var_len_int (bp);
> +  TREE_FIXED_CST (expr) = fv;
> +}
> +
> +
> +/* Unpack all the non-pointer fields of the TS_DECL_COMMON structure
> +   of expression EXPR from bitpack BP.  */
> +
> +static void
> +unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  DECL_MODE (expr) = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
> +  DECL_NONLOCAL (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_VIRTUAL_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_IGNORED_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_ABSTRACT (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_USER_ALIGN (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_PRESERVE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_DEBUG_EXPR_IS_FROM (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_EXTERNAL (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_GIMPLE_REG_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_ALIGN (expr) = (unsigned) bp_unpack_var_len_unsigned (bp);
> +
> +  if (TREE_CODE (expr) == LABEL_DECL)
> +    {
> +      DECL_ERROR_ISSUED (expr) = (unsigned) bp_unpack_value (bp, 1);
> +      EH_LANDING_PAD_NR (expr) = (int) bp_unpack_var_len_unsigned (bp);
> +
> +      /* Always assume an initial value of -1 for LABEL_DECL_UID to
> +	 force gimple_set_bb to recreate label_to_block_map.  */
> +      LABEL_DECL_UID (expr) = -1;
> +    }
> +
> +  if (TREE_CODE (expr) == FIELD_DECL)
> +    {
> +      DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
> +      DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +      expr->decl_common.off_align = bp_unpack_value (bp, 8);
> +    }
> +
> +  if (TREE_CODE (expr) == RESULT_DECL
> +      || TREE_CODE (expr) == PARM_DECL
> +      || TREE_CODE (expr) == VAR_DECL)
> +    {
> +      DECL_BY_REFERENCE (expr) = (unsigned) bp_unpack_value (bp, 1);
> +      if (TREE_CODE (expr) == VAR_DECL
> +	  || TREE_CODE (expr) == PARM_DECL)
> +	DECL_HAS_VALUE_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +      DECL_RESTRICTED_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +    }
> +}
> +
> +
> +/* Unpack all the non-pointer fields of the TS_DECL_WRTL structure
> +   of expression EXPR from bitpack BP.  */
> +
> +static void
> +unpack_ts_decl_wrtl_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  DECL_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1);
> +}
> +
> +
> +/* Unpack all the non-pointer fields of the TS_DECL_WITH_VIS structure
> +   of expression EXPR from bitpack BP.  */
> +
> +static void
> +unpack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  DECL_DEFER_OUTPUT (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_COMMON (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_DLLIMPORT_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_WEAK (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_SEEN_IN_BIND_EXPR_P (expr) = (unsigned) bp_unpack_value (bp,  1);
> +  DECL_COMDAT (expr) = (unsigned) bp_unpack_value (bp,  1);
> +  DECL_VISIBILITY (expr) = (enum symbol_visibility) bp_unpack_value (bp,  2);
> +  DECL_VISIBILITY_SPECIFIED (expr) = (unsigned) bp_unpack_value (bp,  1);
> +
> +  if (TREE_CODE (expr) == VAR_DECL)
> +    {
> +      DECL_HARD_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1);
> +      DECL_IN_TEXT_SECTION (expr) = (unsigned) bp_unpack_value (bp, 1);
> +      DECL_IN_CONSTANT_POOL (expr) = (unsigned) bp_unpack_value (bp, 1);
> +      DECL_TLS_MODEL (expr) = (enum tls_model) bp_unpack_value (bp,  3);
> +    }
> +
> +  if (VAR_OR_FUNCTION_DECL_P (expr))
> +    {
> +      priority_type p;
> +      p = (priority_type) bp_unpack_var_len_unsigned (bp);
> +      SET_DECL_INIT_PRIORITY (expr, p);
> +    }
> +}
> +
> +
> +/* Unpack all the non-pointer fields of the TS_FUNCTION_DECL structure
> +   of expression EXPR from bitpack BP.  */
> +
> +static void
> +unpack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  DECL_BUILT_IN_CLASS (expr) = bp_unpack_enum (bp, built_in_class,
> +					       BUILT_IN_LAST);
> +  DECL_STATIC_CONSTRUCTOR (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_STATIC_DESTRUCTOR (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_UNINLINABLE (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_POSSIBLY_INLINED (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_IS_NOVOPS (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_IS_RETURNS_TWICE (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_IS_MALLOC (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_IS_OPERATOR_NEW (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_DECLARED_INLINE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_STATIC_CHAIN (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_NO_INLINE_WARNING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr)
> +    			= (unsigned) bp_unpack_value (bp, 1);
> +  DECL_NO_LIMIT_STACK (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_DISREGARD_INLINE_LIMITS (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  DECL_LOOPING_CONST_OR_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  if (DECL_BUILT_IN_CLASS (expr) != NOT_BUILT_IN)
> +    {
> +      DECL_FUNCTION_CODE (expr) = (enum built_in_function) bp_unpack_value (bp,
> +	                                                                    11);
> +      if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_NORMAL
> +	  && DECL_FUNCTION_CODE (expr) >= END_BUILTINS)
> +	fatal_error ("machine independent builtin code out of range");
> +      else if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD)
> +	{
> +          tree result = targetm.builtin_decl (DECL_FUNCTION_CODE (expr), true);
> +	  if (!result || result == error_mark_node)
> +	    fatal_error ("target specific builtin not available");
> +	}
> +    }
> +  if (DECL_STATIC_DESTRUCTOR (expr))
> +    {
> +      priority_type p;
> +      p = (priority_type) bp_unpack_var_len_unsigned (bp);
> +      SET_DECL_FINI_PRIORITY (expr, p);
> +    }
> +}
> +
> +
> +/* Unpack all the non-pointer fields of the TS_TYPE_COMMON structure
> +   of expression EXPR from bitpack BP.  */
> +
> +static void
> +unpack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  enum machine_mode mode;
> +
> +  mode = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
> +  SET_TYPE_MODE (expr, mode);
> +  TYPE_STRING_FLAG (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  TYPE_NO_FORCE_BLK (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  TYPE_NEEDS_CONSTRUCTING (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  if (RECORD_OR_UNION_TYPE_P (expr))
> +    TYPE_TRANSPARENT_AGGR (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  TYPE_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  TYPE_RESTRICT (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr)
> +    	= (unsigned) bp_unpack_value (bp, 2);
> +  TYPE_USER_ALIGN (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  TYPE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  TYPE_PRECISION (expr) = bp_unpack_var_len_unsigned (bp);
> +  TYPE_ALIGN (expr) = bp_unpack_var_len_unsigned (bp);
> +  TYPE_ALIAS_SET (expr) = bp_unpack_var_len_int (bp);
> +}
> +
> +
> +/* Unpack all the non-pointer fields of the TS_BLOCK structure
> +   of expression EXPR from bitpack BP.  */
> +
> +static void
> +unpack_ts_block_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  BLOCK_ABSTRACT (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  /* BLOCK_NUMBER is recomputed.  */
> +}
> +
> +/* Unpack all the non-pointer fields of the TS_TRANSLATION_UNIT_DECL
> +   structure of expression EXPR from bitpack BP.  */
> +
> +static void
> +unpack_ts_translation_unit_decl_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED, tree expr ATTRIBUTE_UNUSED)
> +{
> +}
> +
> +/* Unpack all the non-pointer fields in EXPR into a bit pack.  */
> +
> +static void
> +unpack_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  enum tree_code code;
> +
> +  code = TREE_CODE (expr);
> +
> +  /* Note that all these functions are highly sensitive to changes in
> +     the types and sizes of each of the fields being packed.  */
> +  unpack_ts_base_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
> +    unpack_ts_real_cst_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_FIXED_CST))
> +    unpack_ts_fixed_cst_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
> +    unpack_ts_decl_common_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL))
> +    unpack_ts_decl_wrtl_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
> +    unpack_ts_decl_with_vis_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
> +    unpack_ts_function_decl_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
> +    unpack_ts_type_common_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
> +    unpack_ts_block_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
> +    unpack_ts_translation_unit_decl_value_fields (bp, expr);
> +
> +  if (streamer_hooks.unpack_value_fields)
> +    streamer_hooks.unpack_value_fields (bp, expr);
> +}
> +
> +
> +/* Materialize a new tree from input block IB using descriptors in
> +   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
> +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
> +  HOST_WIDEST_INT orig_address_in_writer;
> +#endif
> +
> +  result = NULL_TREE;
> +
> +#ifdef LTO_STREAMER_DEBUG
> +  /* Read the word representing the memory address for the tree
> +     as it was written by the writer.  This is useful when
> +     debugging differences between the writer and reader.  */
> +  orig_address_in_writer = lto_input_sleb128 (ib);
> +  gcc_assert ((intptr_t) orig_address_in_writer == orig_address_in_writer);
> +#endif
> +
> +  code = lto_tag_to_tree_code (tag);
> +
> +  /* We should never see an SSA_NAME tree.  Only the version numbers of
> +     SSA names are ever written out.  See input_ssa_names.  */
> +  gcc_assert (code != SSA_NAME);
> +
> +  /* Instantiate a new tree using the header data.  */
> +  if (CODE_CONTAINS_STRUCT (code, TS_STRING))
> +    result = input_string_cst (data_in, ib);
> +  else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER))
> +    result = input_identifier (data_in, ib);
> +  else if (CODE_CONTAINS_STRUCT (code, TS_VEC))
> +    {
> +      HOST_WIDE_INT len = lto_input_sleb128 (ib);
> +      result = make_tree_vec (len);
> +    }
> +  else if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
> +    {
> +      unsigned HOST_WIDE_INT len = lto_input_uleb128 (ib);
> +      result = make_tree_binfo (len);
> +    }
> +  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
> +	 make_node call.  */
> +      if (result == NULL_TREE)
> +	result = make_node (code);
> +    }
> +
> +#ifdef LTO_STREAMER_DEBUG
> +  /* Store the original address of the tree as seen by the writer
> +     in RESULT's aux field.  This is useful when debugging streaming
> +     problems.  This way, a debugging session can be started on
> +     both writer and reader with a breakpoint using this address
> +     value in both.  */
> +  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;
> +}
> +
> +
> +/* Read all pointer fields in the TS_COMMON structure of EXPR from input
> +   block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +
> +static void
> +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);
> +}
> +
> +
> +/* Read all pointer fields in the TS_VECTOR structure of EXPR from input
> +   block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +static void
> +lto_input_ts_vector_tree_pointers (struct lto_input_block *ib,
> +				   struct data_in *data_in, tree expr)
> +{
> +  TREE_VECTOR_CST_ELTS (expr) = lto_input_chain (ib, data_in);
> +}
> +
> +
> +/* Read all pointer fields in the TS_COMPLEX structure of EXPR from input
> +   block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +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);
> +}
> +
> +
> +/* Read all pointer fields in the TS_DECL_MINIMAL structure of EXPR
> +   from input block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +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_SOURCE_LOCATION (expr) = lto_input_location (ib, data_in);
> +}
> +
> +
> +/* Read all pointer fields in the TS_DECL_COMMON structure of EXPR from
> +   input block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +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);
> +
> +  /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
> +     for early inlining so drop it on the floor instead of ICEing in
> +     dwarf2out.c.  */
> +
> +  if (TREE_CODE (expr) == PARM_DECL)
> +    TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
> +
> +  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));
> +
> +  if (TREE_CODE (expr) == VAR_DECL)
> +    {
> +      tree dexpr = lto_input_tree (ib, data_in);
> +      if (dexpr)
> +	SET_DECL_DEBUG_EXPR (expr, dexpr);
> +    }
> +}
> +
> +
> +/* Read all pointer fields in the TS_DECL_NON_COMMON structure of
> +   EXPR from input block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +static void
> +lto_input_ts_decl_non_common_tree_pointers (struct lto_input_block *ib,
> +					    struct data_in *data_in, tree expr)
> +{
> +  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_VINDEX (expr) = lto_input_tree (ib, data_in);
> +}
> +
> +
> +/* Read all pointer fields in the TS_DECL_WITH_VIS structure of EXPR
> +   from input block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +static void
> +lto_input_ts_decl_with_vis_tree_pointers (struct lto_input_block *ib,
> +				          struct data_in *data_in, tree expr)
> +{
> +  tree id;
> +
> +  id = lto_input_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);
> +}
> +
> +
> +/* Read all pointer fields in the TS_FIELD_DECL structure of EXPR from
> +   input block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +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);
> +  TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
> +}
> +
> +
> +/* Read all pointer fields in the TS_FUNCTION_DECL structure of EXPR
> +   from input block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +static void
> +lto_input_ts_function_decl_tree_pointers (struct lto_input_block *ib,
> +					  struct data_in *data_in, tree expr)
> +{
> +  /* 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);
> +
> +  /* If the file contains a function with an EH personality set,
> +     then it was compiled with -fexceptions.  In that case, initialize
> +     the backend EH machinery.  */
> +  if (DECL_FUNCTION_PERSONALITY (expr))
> +    lto_init_eh ();
> +}
> +
> +
> +/* Read all pointer fields in the TS_TYPE_COMMON structure of EXPR from
> +   input block IB.  DATA_IN contains tables and descriptors for the file
> +   being read.  */
> +
> +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);
> +  /* 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_CANONICAL gets re-computed during type merging.  */
> +  TYPE_CANONICAL (expr) = NULL_TREE;
> +  TYPE_STUB_DECL (expr) = lto_input_tree (ib, data_in);
> +}
> +
> +/* Read all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
> +   from input block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +static void
> +lto_input_ts_type_non_common_tree_pointers (struct lto_input_block *ib,
> +					    struct data_in *data_in,
> +					    tree expr)
> +{
> +  if (TREE_CODE (expr) == ENUMERAL_TYPE)
> +    TYPE_VALUES (expr) = lto_input_tree (ib, data_in);
> +  else if (TREE_CODE (expr) == ARRAY_TYPE)
> +    TYPE_DOMAIN (expr) = lto_input_tree (ib, data_in);
> +  else if (RECORD_OR_UNION_TYPE_P (expr))
> +    TYPE_FIELDS (expr) = lto_input_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);
> +
> +  if (!POINTER_TYPE_P (expr))
> +    TYPE_MINVAL (expr) = lto_input_tree (ib, data_in);
> +  TYPE_MAXVAL (expr) = lto_input_tree (ib, data_in);
> +  if (RECORD_OR_UNION_TYPE_P (expr))
> +    TYPE_BINFO (expr) = lto_input_tree (ib, data_in);
> +}
> +
> +
> +/* Read all pointer fields in the TS_LIST structure of EXPR from input
> +   block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +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_CHAIN (expr) = lto_input_chain (ib, data_in);
> +}
> +
> +
> +/* Read all pointer fields in the TS_VEC structure of EXPR from input
> +   block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +static void
> +lto_input_ts_vec_tree_pointers (struct lto_input_block *ib,
> +				struct data_in *data_in, tree expr)
> +{
> +  int i;
> +
> +  /* 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);
> +}
> +
> +
> +/* Read all pointer fields in the TS_EXP structure of EXPR from input
> +   block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +
> +static void
> +lto_input_ts_exp_tree_pointers (struct lto_input_block *ib,
> +			        struct data_in *data_in, tree expr)
> +{
> +  int i, length;
> +  location_t loc;
> +
> +  length = lto_input_sleb128 (ib);
> +  gcc_assert (length == TREE_OPERAND_LENGTH (expr));
> +
> +  for (i = 0; i < length; i++)
> +    TREE_OPERAND (expr, i) = lto_input_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);
> +}
> +
> +
> +/* Read all pointer fields in the TS_BLOCK structure of EXPR from input
> +   block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +static void
> +lto_input_ts_block_tree_pointers (struct lto_input_block *ib,
> +				  struct data_in *data_in, tree expr)
> +{
> +  /* Do not stream BLOCK_SOURCE_LOCATION.  We cannot handle debug information
> +     for early inlining so drop it on the floor instead of ICEing in
> +     dwarf2out.c.  */
> +  BLOCK_VARS (expr) = lto_input_chain (ib, data_in);
> +
> +  /* Do not stream BLOCK_NONLOCALIZED_VARS.  We cannot handle debug information
> +     for early inlining so drop it on the floor instead of ICEing in
> +     dwarf2out.c.  */
> +
> +  BLOCK_SUPERCONTEXT (expr) = lto_input_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);
> +
> +  /* We re-compute BLOCK_SUBBLOCKS of our parent here instead
> +     of streaming it.  For non-BLOCK BLOCK_SUPERCONTEXTs we still
> +     stream the child relationship explicitly.  */
> +  if (BLOCK_SUPERCONTEXT (expr)
> +      && TREE_CODE (BLOCK_SUPERCONTEXT (expr)) == BLOCK)
> +    {
> +      BLOCK_CHAIN (expr) = BLOCK_SUBBLOCKS (BLOCK_SUPERCONTEXT (expr));
> +      BLOCK_SUBBLOCKS (BLOCK_SUPERCONTEXT (expr)) = expr;
> +    }
> +
> +  /* The global block is rooted at the TU decl.  Hook it here to
> +     avoid the need to stream in this block during WPA time.  */
> +  else if (BLOCK_SUPERCONTEXT (expr)
> +	   && TREE_CODE (BLOCK_SUPERCONTEXT (expr)) == TRANSLATION_UNIT_DECL)
> +    DECL_INITIAL (BLOCK_SUPERCONTEXT (expr)) = expr;
> +
> +  /* The function-level block is connected at the time we read in
> +     function bodies for the same reason.  */
> +}
> +
> +
> +/* Read all pointer fields in the TS_BINFO structure of EXPR from input
> +   block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +static void
> +lto_input_ts_binfo_tree_pointers (struct lto_input_block *ib,
> +				  struct data_in *data_in, tree expr)
> +{
> +  unsigned i, len;
> +  tree t;
> +
> +  /* Note that the number of slots in EXPR was read in
> +     lto_materialize_tree when instantiating EXPR.  However, the
> +     vector is empty so we cannot rely on VEC_length to know how many
> +     elements to read.  So, this list is emitted as a 0-terminated
> +     list on the writer side.  */
> +  do
> +    {
> +      t = lto_input_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);
> +
> +  len = lto_input_uleb128 (ib);
> +  if (len > 0)
> +    {
> +      VEC_reserve_exact (tree, gc, BINFO_BASE_ACCESSES (expr), len);
> +      for (i = 0; i < len; i++)
> +	{
> +	  tree a = lto_input_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);
> +}
> +
> +
> +/* Read all pointer fields in the TS_CONSTRUCTOR structure of EXPR from
> +   input block IB.  DATA_IN contains tables and descriptors for the
> +   file being read.  */
> +
> +static void
> +lto_input_ts_constructor_tree_pointers (struct lto_input_block *ib,
> +				        struct data_in *data_in, tree expr)
> +{
> +  unsigned i, len;
> +
> +  len = lto_input_uleb128 (ib);
> +  for (i = 0; i < len; i++)
> +    {
> +      tree index, value;
> +
> +      index = lto_input_tree (ib, data_in);
> +      value = lto_input_tree (ib, data_in);
> +      CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (expr), index, value);
> +    }
> +}
> +
> +
> +/* Input a TS_TARGET_OPTION tree from IB into EXPR.  */
> +
> +static void
> +lto_input_ts_target_option (struct lto_input_block *ib, tree expr)
> +{
> +  unsigned i, len;
> +  struct bitpack_d bp;
> +  struct cl_target_option *t = TREE_TARGET_OPTION (expr);
> +
> +  bp = lto_input_bitpack (ib);
> +  len = sizeof (struct cl_target_option);
> +  for (i = 0; i < len; i++)
> +    ((unsigned char *)t)[i] = bp_unpack_value (&bp, 8);
> +  if (bp_unpack_value (&bp, 32) != 0x12345678)
> +    fatal_error ("cl_target_option size mismatch in LTO reader and writer");
> +}
> +
> +/* Input a TS_TRANSLATION_UNIT_DECL tree from IB and DATA_IN into EXPR.  */
> +
> +static void
> +lto_input_ts_translation_unit_decl_tree_pointers (struct lto_input_block *ib,
> +						  struct data_in *data_in,
> +						  tree expr)
> +{
> +  TRANSLATION_UNIT_LANGUAGE (expr) = xstrdup (lto_input_string (data_in, 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.  */
> +
> +static void
> +lto_input_tree_pointers (struct lto_input_block *ib, struct data_in *data_in,
> +			 tree expr)
> +{
> +  enum tree_code code;
> +
> +  code = TREE_CODE (expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
> +    lto_input_ts_common_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_VECTOR))
> +    lto_input_ts_vector_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX))
> +    lto_input_ts_complex_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL))
> +    lto_input_ts_decl_minimal_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
> +    lto_input_ts_decl_common_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
> +    lto_input_ts_decl_non_common_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
> +    lto_input_ts_decl_with_vis_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL))
> +    lto_input_ts_field_decl_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
> +    lto_input_ts_function_decl_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
> +    lto_input_ts_type_common_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON))
> +    lto_input_ts_type_non_common_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_LIST))
> +    lto_input_ts_list_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_VEC))
> +    lto_input_ts_vec_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_EXP))
> +    lto_input_ts_exp_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
> +    lto_input_ts_block_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
> +    lto_input_ts_binfo_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
> +    lto_input_ts_constructor_tree_pointers (ib, data_in, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
> +    lto_input_ts_target_option (ib, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
> +    lto_input_ts_translation_unit_decl_tree_pointers (ib, data_in, expr);
> +}
> +
> +
> +/* 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
> +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);
> +  overflow_p = (lto_input_1_unsigned (ib) != 0);
> +  low = lto_input_uleb128 (ib);
> +  high = lto_input_uleb128 (ib);
> +  result = build_int_cst_wide (type, low, high);
> +
> +  /* If the original constant had overflown, build a replica of RESULT to
> +     avoid modifying the shared constant returned by build_int_cst_wide.  */
> +  if (overflow_p)
> +    {
> +      result = copy_node (result);
> +      TREE_OVERFLOW (result) = 1;
> +    }
> +
> +  return result;
> +}
> +
> +
> +/* Read an index IX from input block IB and return the tree node at
> +   DATA_IN->FILE_DATA->GLOBALS_INDEX[IX].  */
> +
> +static tree
> +lto_get_pickled_tree (struct lto_input_block *ib, struct data_in *data_in)
> +{
> +  unsigned HOST_WIDE_INT ix;
> +  tree result;
> +  enum LTO_tags expected_tag;
> +
> +  ix = lto_input_uleb128 (ib);
> +  expected_tag = lto_input_enum (ib, LTO_tags, LTO_NUM_TAGS);
> +
> +  result = lto_streamer_cache_get (data_in->reader_cache, ix);
> +  gcc_assert (result
> +              && TREE_CODE (result) == lto_tag_to_tree_code (expected_tag));
> +
> +  return result;
> +}
> +
> +
> +/* Read a code and class from input block IB and return the
> +   corresponding builtin.  DATA_IN is as in lto_input_tree.  */
> +
> +static tree
> +lto_get_builtin_tree (struct lto_input_block *ib, struct data_in *data_in)
> +{
> +  enum built_in_class fclass;
> +  enum built_in_function fcode;
> +  const char *asmname;
> +  tree result;
> +
> +  fclass = lto_input_enum (ib, built_in_class, BUILT_IN_LAST);
> +  gcc_assert (fclass == BUILT_IN_NORMAL || fclass == BUILT_IN_MD);
> +
> +  fcode = (enum built_in_function) lto_input_uleb128 (ib);
> +
> +  if (fclass == BUILT_IN_NORMAL)
> +    {
> +      if (fcode >= END_BUILTINS)
> +	fatal_error ("machine independent builtin code out of range");
> +      result = built_in_decls[fcode];
> +      gcc_assert (result);
> +    }
> +  else if (fclass == BUILT_IN_MD)
> +    {
> +      result = targetm.builtin_decl (fcode, true);
> +      if (!result || result == error_mark_node)
> +	fatal_error ("target specific builtin not available");
> +    }
> +  else
> +    gcc_unreachable ();
> +
> +  asmname = lto_input_string (data_in, ib);
> +  if (asmname)
> +    set_builtin_user_assembler_name (result, asmname);
> +
> +  lto_streamer_cache_append (data_in->reader_cache, result);
> +
> +  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
> new file mode 100644
> index 0000000..ace8430
> --- /dev/null
> +++ b/gcc/tree-streamer-out.c
> @@ -0,0 +1,1045 @@
> +/* Routines for emitting trees to a file stream.
> +
> +   Copyright 2011 Free Software Foundation, Inc.
> +   Contributed by Diego Novillo <dnovillo@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "diagnostic.h"
> +#include "tree.h"
> +#include "tree-streamer.h"
> +#include "data-streamer.h"
> +#include "streamer-hooks.h"
> +
> +/* Output the STRING constant to the string
> +   table in OB.  Then put the index onto the INDEX_STREAM.  */
> +
> +static void
> +output_string_cst (struct output_block *ob,
> +		   struct lto_output_stream *index_stream,
> +		   tree string)
> +{
> +  lto_output_string_with_length (ob, index_stream,
> +				 TREE_STRING_POINTER (string),
> +				 TREE_STRING_LENGTH (string),
> +				 true);
> +}
> +
> +
> +/* Output the identifier ID to the string
> +   table in OB.  Then put the index onto the INDEX_STREAM.  */
> +
> +static void
> +output_identifier (struct output_block *ob,
> +		   struct lto_output_stream *index_stream,
> +		   tree id)
> +{
> +  lto_output_string_with_length (ob, index_stream,
> +				 IDENTIFIER_POINTER (id),
> +				 IDENTIFIER_LENGTH (id),
> +				 true);
> +}
> +
> +
> +/* Pack all the non-pointer fields of the TS_BASE structure of
> +   expression EXPR into bitpack BP.  */
> +
> +static void
> +pack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  bp_pack_value (bp, TREE_CODE (expr), 16);
> +  if (!TYPE_P (expr))
> +    {
> +      bp_pack_value (bp, TREE_SIDE_EFFECTS (expr), 1);
> +      bp_pack_value (bp, TREE_CONSTANT (expr), 1);
> +      bp_pack_value (bp, TREE_READONLY (expr), 1);
> +
> +      /* TREE_PUBLIC is used on types to indicate that the type
> +	 has a TYPE_CACHED_VALUES vector.  This is not streamed out,
> +	 so we skip it here.  */
> +      bp_pack_value (bp, TREE_PUBLIC (expr), 1);
> +    }
> +  else
> +    bp_pack_value (bp, 0, 4);
> +  bp_pack_value (bp, TREE_ADDRESSABLE (expr), 1);
> +  bp_pack_value (bp, TREE_THIS_VOLATILE (expr), 1);
> +  if (DECL_P (expr))
> +    bp_pack_value (bp, DECL_UNSIGNED (expr), 1);
> +  else if (TYPE_P (expr))
> +    bp_pack_value (bp, TYPE_UNSIGNED (expr), 1);
> +  else
> +    bp_pack_value (bp, 0, 1);
> +  /* We write debug info two times, do not confuse the second one.  */
> +  bp_pack_value (bp, TYPE_P (expr) ? 0 : TREE_ASM_WRITTEN (expr), 1);
> +  if (TYPE_P (expr))
> +    bp_pack_value (bp, TYPE_ARTIFICIAL (expr), 1);
> +  else
> +    bp_pack_value (bp, TREE_NO_WARNING (expr), 1);
> +  bp_pack_value (bp, TREE_USED (expr), 1);
> +  bp_pack_value (bp, TREE_NOTHROW (expr), 1);
> +  bp_pack_value (bp, TREE_STATIC (expr), 1);
> +  bp_pack_value (bp, TREE_PRIVATE (expr), 1);
> +  bp_pack_value (bp, TREE_PROTECTED (expr), 1);
> +  bp_pack_value (bp, TREE_DEPRECATED (expr), 1);
> +  if (TYPE_P (expr))
> +    bp_pack_value (bp, TYPE_SATURATING (expr), 1);
> +  else if (TREE_CODE (expr) == SSA_NAME)
> +    bp_pack_value (bp, SSA_NAME_IS_DEFAULT_DEF (expr), 1);
> +  else
> +    bp_pack_value (bp, 0, 1);
> +}
> +
> +
> +/* Pack all the non-pointer fields of the TS_REAL_CST structure of
> +   expression EXPR into bitpack BP.  */
> +
> +static void
> +pack_ts_real_cst_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  unsigned i;
> +  REAL_VALUE_TYPE r;
> +
> +  r = TREE_REAL_CST (expr);
> +  bp_pack_value (bp, r.cl, 2);
> +  bp_pack_value (bp, r.decimal, 1);
> +  bp_pack_value (bp, r.sign, 1);
> +  bp_pack_value (bp, r.signalling, 1);
> +  bp_pack_value (bp, r.canonical, 1);
> +  bp_pack_value (bp, r.uexp, EXP_BITS);
> +  for (i = 0; i < SIGSZ; i++)
> +    bp_pack_value (bp, r.sig[i], HOST_BITS_PER_LONG);
> +}
> +
> +
> +/* Pack all the non-pointer fields of the TS_FIXED_CST structure of
> +   expression EXPR into bitpack BP.  */
> +
> +static void
> +pack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  struct fixed_value fv = TREE_FIXED_CST (expr);
> +  bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, fv.mode);
> +  bp_pack_var_len_int (bp, fv.data.low);
> +  bp_pack_var_len_int (bp, fv.data.high);
> +}
> +
> +
> +/* Pack all the non-pointer fields of the TS_DECL_COMMON structure
> +   of expression EXPR into bitpack BP.  */
> +
> +static void
> +pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, DECL_MODE (expr));
> +  bp_pack_value (bp, DECL_NONLOCAL (expr), 1);
> +  bp_pack_value (bp, DECL_VIRTUAL_P (expr), 1);
> +  bp_pack_value (bp, DECL_IGNORED_P (expr), 1);
> +  bp_pack_value (bp, DECL_ABSTRACT (expr), 1);
> +  bp_pack_value (bp, DECL_ARTIFICIAL (expr), 1);
> +  bp_pack_value (bp, DECL_USER_ALIGN (expr), 1);
> +  bp_pack_value (bp, DECL_PRESERVE_P (expr), 1);
> +  bp_pack_value (bp, DECL_DEBUG_EXPR_IS_FROM (expr), 1);
> +  bp_pack_value (bp, DECL_EXTERNAL (expr), 1);
> +  bp_pack_value (bp, DECL_GIMPLE_REG_P (expr), 1);
> +  bp_pack_var_len_unsigned (bp, DECL_ALIGN (expr));
> +
> +  if (TREE_CODE (expr) == LABEL_DECL)
> +    {
> +      /* Note that we do not write LABEL_DECL_UID.  The reader will
> +	 always assume an initial value of -1 so that the
> +	 label_to_block_map is recreated by gimple_set_bb.  */
> +      bp_pack_value (bp, DECL_ERROR_ISSUED (expr), 1);
> +      bp_pack_var_len_unsigned (bp, EH_LANDING_PAD_NR (expr));
> +    }
> +
> +  if (TREE_CODE (expr) == FIELD_DECL)
> +    {
> +      bp_pack_value (bp, DECL_PACKED (expr), 1);
> +      bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
> +      bp_pack_value (bp, expr->decl_common.off_align, 8);
> +    }
> +
> +  if (TREE_CODE (expr) == RESULT_DECL
> +      || TREE_CODE (expr) == PARM_DECL
> +      || TREE_CODE (expr) == VAR_DECL)
> +    {
> +      bp_pack_value (bp, DECL_BY_REFERENCE (expr), 1);
> +      if (TREE_CODE (expr) == VAR_DECL
> +	  || TREE_CODE (expr) == PARM_DECL)
> +	bp_pack_value (bp, DECL_HAS_VALUE_EXPR_P (expr), 1);
> +      bp_pack_value (bp, DECL_RESTRICTED_P (expr), 1);
> +    }
> +}
> +
> +
> +/* Pack all the non-pointer fields of the TS_DECL_WRTL structure
> +   of expression EXPR into bitpack BP.  */
> +
> +static void
> +pack_ts_decl_wrtl_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  bp_pack_value (bp, DECL_REGISTER (expr), 1);
> +}
> +
> +
> +/* Pack all the non-pointer fields of the TS_DECL_WITH_VIS structure
> +   of expression EXPR into bitpack BP.  */
> +
> +static void
> +pack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  bp_pack_value (bp, DECL_DEFER_OUTPUT (expr), 1);
> +  bp_pack_value (bp, DECL_COMMON (expr), 1);
> +  bp_pack_value (bp, DECL_DLLIMPORT_P (expr), 1);
> +  bp_pack_value (bp, DECL_WEAK (expr), 1);
> +  bp_pack_value (bp, DECL_SEEN_IN_BIND_EXPR_P (expr),  1);
> +  bp_pack_value (bp, DECL_COMDAT (expr),  1);
> +  bp_pack_value (bp, DECL_VISIBILITY (expr),  2);
> +  bp_pack_value (bp, DECL_VISIBILITY_SPECIFIED (expr),  1);
> +
> +  if (TREE_CODE (expr) == VAR_DECL)
> +    {
> +      bp_pack_value (bp, DECL_HARD_REGISTER (expr), 1);
> +      bp_pack_value (bp, DECL_IN_TEXT_SECTION (expr), 1);
> +      bp_pack_value (bp, DECL_IN_CONSTANT_POOL (expr), 1);
> +      bp_pack_value (bp, DECL_TLS_MODEL (expr),  3);
> +    }
> +
> +  if (VAR_OR_FUNCTION_DECL_P (expr))
> +    bp_pack_var_len_unsigned (bp, DECL_INIT_PRIORITY (expr));
> +}
> +
> +
> +/* Pack all the non-pointer fields of the TS_FUNCTION_DECL structure
> +   of expression EXPR into bitpack BP.  */
> +
> +static void
> +pack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  /* For normal/md builtins we only write the class and code, so they
> +     should never be handled here.  */
> +  gcc_assert (!lto_stream_as_builtin_p (expr));
> +
> +  bp_pack_enum (bp, built_in_class, BUILT_IN_LAST,
> +		DECL_BUILT_IN_CLASS (expr));
> +  bp_pack_value (bp, DECL_STATIC_CONSTRUCTOR (expr), 1);
> +  bp_pack_value (bp, DECL_STATIC_DESTRUCTOR (expr), 1);
> +  bp_pack_value (bp, DECL_UNINLINABLE (expr), 1);
> +  bp_pack_value (bp, DECL_POSSIBLY_INLINED (expr), 1);
> +  bp_pack_value (bp, DECL_IS_NOVOPS (expr), 1);
> +  bp_pack_value (bp, DECL_IS_RETURNS_TWICE (expr), 1);
> +  bp_pack_value (bp, DECL_IS_MALLOC (expr), 1);
> +  bp_pack_value (bp, DECL_IS_OPERATOR_NEW (expr), 1);
> +  bp_pack_value (bp, DECL_DECLARED_INLINE_P (expr), 1);
> +  bp_pack_value (bp, DECL_STATIC_CHAIN (expr), 1);
> +  bp_pack_value (bp, DECL_NO_INLINE_WARNING_P (expr), 1);
> +  bp_pack_value (bp, DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr), 1);
> +  bp_pack_value (bp, DECL_NO_LIMIT_STACK (expr), 1);
> +  bp_pack_value (bp, DECL_DISREGARD_INLINE_LIMITS (expr), 1);
> +  bp_pack_value (bp, DECL_PURE_P (expr), 1);
> +  bp_pack_value (bp, DECL_LOOPING_CONST_OR_PURE_P (expr), 1);
> +  if (DECL_BUILT_IN_CLASS (expr) != NOT_BUILT_IN)
> +    bp_pack_value (bp, DECL_FUNCTION_CODE (expr), 11);
> +  if (DECL_STATIC_DESTRUCTOR (expr))
> +    bp_pack_var_len_unsigned (bp, DECL_FINI_PRIORITY (expr));
> +}
> +
> +
> +/* Pack all the non-pointer fields of the TS_TYPE_COMMON structure
> +   of expression EXPR into bitpack BP.  */
> +
> +static void
> +pack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, TYPE_MODE (expr));
> +  bp_pack_value (bp, TYPE_STRING_FLAG (expr), 1);
> +  bp_pack_value (bp, TYPE_NO_FORCE_BLK (expr), 1);
> +  bp_pack_value (bp, TYPE_NEEDS_CONSTRUCTING (expr), 1);
> +  if (RECORD_OR_UNION_TYPE_P (expr))
> +    bp_pack_value (bp, TYPE_TRANSPARENT_AGGR (expr), 1);
> +  bp_pack_value (bp, TYPE_PACKED (expr), 1);
> +  bp_pack_value (bp, TYPE_RESTRICT (expr), 1);
> +  bp_pack_value (bp, TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr), 2);
> +  bp_pack_value (bp, TYPE_USER_ALIGN (expr), 1);
> +  bp_pack_value (bp, TYPE_READONLY (expr), 1);
> +  bp_pack_var_len_unsigned (bp, TYPE_PRECISION (expr));
> +  bp_pack_var_len_unsigned (bp, TYPE_ALIGN (expr));
> +  bp_pack_var_len_int (bp, TYPE_ALIAS_SET (expr) == 0 ? 0 : -1);
> +}
> +
> +
> +/* Pack all the non-pointer fields of the TS_BLOCK structure
> +   of expression EXPR into bitpack BP.  */
> +
> +static void
> +pack_ts_block_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  bp_pack_value (bp, BLOCK_ABSTRACT (expr), 1);
> +  /* BLOCK_NUMBER is recomputed.  */
> +}
> +
> +/* Pack all the non-pointer fields of the TS_TRANSLATION_UNIT_DECL structure
> +   of expression EXPR into bitpack BP.  */
> +
> +static void
> +pack_ts_translation_unit_decl_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED, tree expr ATTRIBUTE_UNUSED)
> +{
> +}
> +
> +/* Pack all the non-pointer fields in EXPR into a bit pack.  */
> +
> +static void
> +pack_value_fields (struct bitpack_d *bp, tree expr)
> +{
> +  enum tree_code code;
> +
> +  code = TREE_CODE (expr);
> +
> +  /* Note that all these functions are highly sensitive to changes in
> +     the types and sizes of each of the fields being packed.  */
> +  pack_ts_base_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
> +    pack_ts_real_cst_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_FIXED_CST))
> +    pack_ts_fixed_cst_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
> +    pack_ts_decl_common_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL))
> +    pack_ts_decl_wrtl_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
> +    pack_ts_decl_with_vis_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
> +    pack_ts_function_decl_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
> +    pack_ts_type_common_value_fields (bp, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
> +    pack_ts_block_value_fields (bp, 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
> +lto_output_builtin_tree (struct output_block *ob, tree expr)
> +{
> +  gcc_assert (lto_stream_as_builtin_p (expr));
> +
> +  if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD
> +      && !targetm.builtin_decl)
> +    sorry ("gimple bytecode streams do not support machine specific builtin "
> +	   "functions on this target");
> +
> +  output_record_start (ob, LTO_builtin_decl);
> +  lto_output_enum (ob->main_stream, built_in_class, BUILT_IN_LAST,
> +		   DECL_BUILT_IN_CLASS (expr));
> +  output_uleb128 (ob, DECL_FUNCTION_CODE (expr));
> +
> +  if (DECL_ASSEMBLER_NAME_SET_P (expr))
> +    {
> +      /* When the assembler name of a builtin gets a user name,
> +	 the new name is always prefixed with '*' by
> +	 set_builtin_user_assembler_name.  So, to prevent the
> +	 reader side from adding a second '*', we omit it here.  */
> +      const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (expr));
> +      if (strlen (str) > 1 && str[0] == '*')
> +	lto_output_string (ob, ob->main_stream, &str[1], true);
> +      else
> +	lto_output_string (ob, ob->main_stream, NULL, true);
> +    }
> +  else
> +    lto_output_string (ob, ob->main_stream, NULL, true);
> +}
> +
> +
> +/* 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.  */
> +
> +static void
> +lto_output_chain (struct output_block *ob, tree t, bool ref_p)
> +{
> +  int i, count;
> +
> +  count = list_length (t);
> +  output_sleb128 (ob, count);
> +  for (i = 0; i < count; i++)
> +    {
> +      tree saved_chain;
> +
> +      /* Clear TREE_CHAIN to avoid blindly recursing into the rest
> +	 of the list.  */
> +      saved_chain = TREE_CHAIN (t);
> +      TREE_CHAIN (t) = NULL_TREE;
> +
> +      lto_output_tree_or_ref (ob, t, ref_p);
> +
> +      TREE_CHAIN (t) = saved_chain;
> +      t = TREE_CHAIN (t);
> +    }
> +}
> +
> +
> +/* Write all pointer fields in the TS_COMMON structure of EXPR to output
> +   block OB.  If REF_P is true, write a reference to EXPR's pointer
> +   fields.  */
> +
> +static void
> +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);
> +}
> +
> +
> +/* Write all pointer fields in the TS_VECTOR structure of EXPR to output
> +   block OB.  If REF_P is true, write a reference to EXPR's pointer
> +   fields.  */
> +
> +static void
> +lto_output_ts_vector_tree_pointers (struct output_block *ob, tree expr,
> +				    bool ref_p)
> +{
> +  lto_output_chain (ob, TREE_VECTOR_CST_ELTS (expr), ref_p);
> +}
> +
> +
> +/* Write all pointer fields in the TS_COMPLEX structure of EXPR to output
> +   block OB.  If REF_P is true, write a reference to EXPR's pointer
> +   fields.  */
> +
> +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);
> +}
> +
> +
> +/* Write all pointer fields in the TS_DECL_MINIMAL structure of EXPR
> +   to output block OB.  If REF_P is true, write a reference to EXPR's
> +   pointer fields.  */
> +
> +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);
> +  lto_output_location (ob, DECL_SOURCE_LOCATION (expr));
> +}
> +
> +
> +/* Write all pointer fields in the TS_DECL_COMMON structure of EXPR to
> +   output block OB.  If REF_P is true, write a reference to EXPR's
> +   pointer fields.  */
> +
> +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);
> +
> +  /* 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);
> +
> +  /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
> +     for early inlining so drop it on the floor instead of ICEing in
> +     dwarf2out.c.  */
> +
> +  if (TREE_CODE (expr) == PARM_DECL)
> +    lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
> +
> +  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);
> +
> +  if (TREE_CODE (expr) == VAR_DECL)
> +    lto_output_tree_or_ref (ob, DECL_DEBUG_EXPR (expr), ref_p);
> +}
> +
> +
> +/* Write all pointer fields in the TS_DECL_NON_COMMON structure of
> +   EXPR to output block OB.  If REF_P is true, write a reference to EXPR's
> +   pointer fields.  */
> +
> +static void
> +lto_output_ts_decl_non_common_tree_pointers (struct output_block *ob,
> +					     tree expr, bool ref_p)
> +{
> +  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);
> +    }
> +  lto_output_tree_or_ref (ob, DECL_VINDEX (expr), ref_p);
> +}
> +
> +
> +/* Write all pointer fields in the TS_DECL_WITH_VIS structure of EXPR
> +   to output block OB.  If REF_P is true, write a reference to EXPR's
> +   pointer fields.  */
> +
> +static void
> +lto_output_ts_decl_with_vis_tree_pointers (struct output_block *ob, tree expr,
> +					   bool ref_p)
> +{
> +  /* 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);
> +  else
> +    output_record_start (ob, LTO_null);
> +
> +  lto_output_tree_or_ref (ob, DECL_SECTION_NAME (expr), ref_p);
> +  lto_output_tree_or_ref (ob, DECL_COMDAT_GROUP (expr), ref_p);
> +}
> +
> +
> +/* Write all pointer fields in the TS_FIELD_DECL structure of EXPR to
> +   output block OB.  If REF_P is true, write a reference to EXPR's
> +   pointer fields.  */
> +
> +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);
> +  lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
> +}
> +
> +
> +/* Write all pointer fields in the TS_FUNCTION_DECL structure of EXPR
> +   to output block OB.  If REF_P is true, write a reference to EXPR's
> +   pointer fields.  */
> +
> +static void
> +lto_output_ts_function_decl_tree_pointers (struct output_block *ob, tree expr,
> +					   bool ref_p)
> +{
> +  /* DECL_STRUCT_FUNCTION is handled by lto_output_function.  FIXME lto,
> +     maybe it should be handled here?  */
> +  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);
> +}
> +
> +
> +/* Write all pointer fields in the TS_TYPE_COMMON structure of EXPR to
> +   output block OB.  If REF_P is true, write a reference to EXPR's
> +   pointer fields.  */
> +
> +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);
> +  /* 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);
> +  /* 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);
> +}
> +
> +/* Write all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
> +   to output block OB.  If REF_P is true, write a reference to EXPR's
> +   pointer fields.  */
> +
> +static void
> +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);
> +  else if (TREE_CODE (expr) == ARRAY_TYPE)
> +    lto_output_tree_or_ref (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);
> +  else if (TREE_CODE (expr) == FUNCTION_TYPE
> +	   || TREE_CODE (expr) == METHOD_TYPE)
> +    lto_output_tree_or_ref (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);
> +  if (RECORD_OR_UNION_TYPE_P (expr))
> +    lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p);
> +}
> +
> +
> +/* Write all pointer fields in the TS_LIST structure of EXPR to output
> +   block OB.  If REF_P is true, write a reference to EXPR's pointer
> +   fields.  */
> +
> +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);
> +  lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
> +}
> +
> +
> +/* Write all pointer fields in the TS_VEC structure of EXPR to output
> +   block OB.  If REF_P is true, write a reference to EXPR's pointer
> +   fields.  */
> +
> +static void
> +lto_output_ts_vec_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
> +{
> +  int i;
> +
> +  /* 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);
> +}
> +
> +
> +/* Write all pointer fields in the TS_EXP structure of EXPR to output
> +   block OB.  If REF_P is true, write a reference to EXPR's pointer
> +   fields.  */
> +
> +static void
> +lto_output_ts_exp_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
> +{
> +  int i;
> +
> +  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);
> +  lto_output_location (ob, EXPR_LOCATION (expr));
> +  lto_output_tree_or_ref (ob, TREE_BLOCK (expr), ref_p);
> +}
> +
> +
> +/* Write all pointer fields in the TS_BLOCK structure of EXPR to output
> +   block OB.  If REF_P is true, write a reference to EXPR's pointer
> +   fields.  */
> +
> +static void
> +lto_output_ts_block_tree_pointers (struct output_block *ob, tree expr,
> +				   bool ref_p)
> +{
> +  /* Do not stream BLOCK_SOURCE_LOCATION.  We cannot handle debug information
> +     for early inlining so drop it on the floor instead of ICEing in
> +     dwarf2out.c.  */
> +  lto_output_chain (ob, BLOCK_VARS (expr), ref_p);
> +
> +  /* Do not stream BLOCK_NONLOCALIZED_VARS.  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_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);
> +  /* Do not output BLOCK_SUBBLOCKS.  Instead on streaming-in this
> +     list is re-constructed from BLOCK_SUPERCONTEXT.  */
> +}
> +
> +
> +/* Write all pointer fields in the TS_BINFO structure of EXPR to output
> +   block OB.  If REF_P is true, write a reference to EXPR's pointer
> +   fields.  */
> +
> +static void
> +lto_output_ts_binfo_tree_pointers (struct output_block *ob, tree expr,
> +				   bool ref_p)
> +{
> +  unsigned i;
> +  tree t;
> +
> +  /* Note that the number of BINFO slots has already been emitted in
> +     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);
> +
> +  lto_output_tree_or_ref (ob, BINFO_OFFSET (expr), ref_p);
> +  lto_output_tree_or_ref (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);
> +
> +  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);
> +
> +  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);
> +}
> +
> +
> +/* Write all pointer fields in the TS_CONSTRUCTOR structure of EXPR to
> +   output block OB.  If REF_P is true, write a reference to EXPR's
> +   pointer fields.  */
> +
> +static void
> +lto_output_ts_constructor_tree_pointers (struct output_block *ob, tree expr,
> +					 bool ref_p)
> +{
> +  unsigned i;
> +  tree index, value;
> +
> +  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);
> +    }
> +}
> +
> +/* Write a TS_TARGET_OPTION tree in EXPR to OB.  */
> +
> +static void
> +lto_output_ts_target_option (struct output_block *ob, tree expr)
> +{
> +  struct cl_target_option *t = TREE_TARGET_OPTION (expr);
> +  struct bitpack_d bp;
> +  unsigned i, len;
> +
> +  /* The cl_target_option is target specific and generated by the options
> +     awk script, so we just recreate a byte-by-byte copy here. */
> +
> +  bp = bitpack_create (ob->main_stream);
> +  len = sizeof (struct cl_target_option);
> +  for (i = 0; i < len; i++)
> +    bp_pack_value (&bp, ((unsigned char *)t)[i], 8);
> +  /* Catch struct size mismatches between reader and writer. */
> +  bp_pack_value (&bp, 0x12345678, 32);
> +  lto_output_bitpack (&bp);
> +}
> +
> +/* Write a TS_TRANSLATION_UNIT_DECL tree in EXPR to OB.  */
> +
> +static void
> +lto_output_ts_translation_unit_decl_tree_pointers (struct output_block *ob,
> +						   tree expr)
> +{
> +  lto_output_string (ob, ob->main_stream,
> +		     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.  */
> +
> +static void
> +lto_output_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
> +{
> +  enum tree_code code;
> +
> +  code = TREE_CODE (expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
> +    lto_output_ts_common_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_VECTOR))
> +    lto_output_ts_vector_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX))
> +    lto_output_ts_complex_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL))
> +    lto_output_ts_decl_minimal_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
> +    lto_output_ts_decl_common_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
> +    lto_output_ts_decl_non_common_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
> +    lto_output_ts_decl_with_vis_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL))
> +    lto_output_ts_field_decl_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
> +    lto_output_ts_function_decl_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
> +    lto_output_ts_type_common_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON))
> +    lto_output_ts_type_non_common_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_LIST))
> +    lto_output_ts_list_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_VEC))
> +    lto_output_ts_vec_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_EXP))
> +    lto_output_ts_exp_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
> +    lto_output_ts_block_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
> +    lto_output_ts_binfo_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
> +    lto_output_ts_constructor_tree_pointers (ob, expr, ref_p);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
> +    lto_output_ts_target_option (ob, expr);
> +
> +  if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
> +    lto_output_ts_translation_unit_decl_tree_pointers (ob, expr);
> +}
> +
> +
> +/* 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.  */
> +
> +static void
> +lto_output_tree_header (struct output_block *ob, tree expr)
> +{
> +  enum LTO_tags tag;
> +  enum tree_code code;
> +
> +  /* 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
> +     EXPR on the reading side (such as the number of slots in
> +     variable sized nodes).  */
> +  tag = lto_tree_code_to_tag (code);
> +  output_record_start (ob, tag);
> +
> +  /* The following will cause bootstrap miscomparisons.  Enable with care.  */
> +#ifdef LTO_STREAMER_DEBUG
> +  /* This is used mainly for debugging purposes.  When the reader
> +     and the writer do not agree on a streamed node, the pointer
> +     value for EXPR can be used to track down the differences in
> +     the debugger.  */
> +  gcc_assert ((HOST_WIDEST_INT) (intptr_t) expr == (intptr_t) expr);
> +  output_sleb128 (ob, (HOST_WIDEST_INT) (intptr_t) expr);
> +#endif
> +
> +  /* The text in strings and identifiers are completely emitted in
> +     the header.  */
> +  if (CODE_CONTAINS_STRUCT (code, TS_STRING))
> +    output_string_cst (ob, ob->main_stream, expr);
> +  else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER))
> +    output_identifier (ob, ob->main_stream, expr);
> +  else if (CODE_CONTAINS_STRUCT (code, TS_VEC))
> +    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);
> +}
> +
> +
> +/* 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
> +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);
> +  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)
> +    {
> +      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
> new file mode 100644
> index 0000000..d5fe93a
> --- /dev/null
> +++ b/gcc/tree-streamer.c
> @@ -0,0 +1,279 @@
> +/* Miscellaneous utilities for tree streaming.  Things that are used
> +   in both input and output are here.
> +
> +   Copyright 2011 Free Software Foundation, Inc.
> +   Contributed by Diego Novillo <dnovillo@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "streamer-hooks.h"
> +#include "tree-streamer.h"
> +
> +/* Check that all the TS_* structures handled by the lto_output_* and
> +   lto_input_* routines are exactly ALL the structures defined in
> +   treestruct.def.  */
> +
> +void
> +check_handled_ts_structures (void)
> +{
> +  bool handled_p[LAST_TS_ENUM];
> +  unsigned i;
> +
> +  memset (&handled_p, 0, sizeof (handled_p));
> +
> +  /* These are the TS_* structures that are either handled or
> +     explicitly ignored by the streamer routines.  */
> +  handled_p[TS_BASE] = true;
> +  handled_p[TS_TYPED] = true;
> +  handled_p[TS_COMMON] = true;
> +  handled_p[TS_INT_CST] = true;
> +  handled_p[TS_REAL_CST] = true;
> +  handled_p[TS_FIXED_CST] = true;
> +  handled_p[TS_VECTOR] = true;
> +  handled_p[TS_STRING] = true;
> +  handled_p[TS_COMPLEX] = true;
> +  handled_p[TS_IDENTIFIER] = true;
> +  handled_p[TS_DECL_MINIMAL] = true;
> +  handled_p[TS_DECL_COMMON] = true;
> +  handled_p[TS_DECL_WRTL] = true;
> +  handled_p[TS_DECL_NON_COMMON] = true;
> +  handled_p[TS_DECL_WITH_VIS] = true;
> +  handled_p[TS_FIELD_DECL] = true;
> +  handled_p[TS_VAR_DECL] = true;
> +  handled_p[TS_PARM_DECL] = true;
> +  handled_p[TS_LABEL_DECL] = true;
> +  handled_p[TS_RESULT_DECL] = true;
> +  handled_p[TS_CONST_DECL] = true;
> +  handled_p[TS_TYPE_DECL] = true;
> +  handled_p[TS_FUNCTION_DECL] = true;
> +  handled_p[TS_TYPE_COMMON] = true;
> +  handled_p[TS_TYPE_WITH_LANG_SPECIFIC] = true;
> +  handled_p[TS_TYPE_NON_COMMON] = true;
> +  handled_p[TS_LIST] = true;
> +  handled_p[TS_VEC] = true;
> +  handled_p[TS_EXP] = true;
> +  handled_p[TS_SSA_NAME] = true;
> +  handled_p[TS_BLOCK] = true;
> +  handled_p[TS_BINFO] = true;
> +  handled_p[TS_STATEMENT_LIST] = true;
> +  handled_p[TS_CONSTRUCTOR] = true;
> +  handled_p[TS_OMP_CLAUSE] = true;
> +  handled_p[TS_OPTIMIZATION] = true;
> +  handled_p[TS_TARGET_OPTION] = true;
> +  handled_p[TS_TRANSLATION_UNIT_DECL] = true;
> +
> +  /* Anything not marked above will trigger the following assertion.
> +     If this assertion triggers, it means that there is a new TS_*
> +     structure that should be handled by the streamer.  */
> +  for (i = 0; i < LAST_TS_ENUM; i++)
> +    gcc_assert (handled_p[i]);
> +}
> +
> +
> +/* Helper for lto_streamer_cache_insert_1.  Add T to CACHE->NODES at
> +   slot IX.  */
> +
> +static void
> +lto_streamer_cache_add_to_node_array (struct lto_streamer_cache_d *cache,
> +				      unsigned ix, tree t)
> +{
> +  /* Make sure we're either replacing an old element or
> +     appending consecutively.  */
> +  gcc_assert (ix <= VEC_length (tree, cache->nodes));
> +
> +  if (ix == VEC_length (tree, cache->nodes))
> +    VEC_safe_push (tree, heap, cache->nodes, t);
> +  else
> +    VEC_replace (tree, cache->nodes, ix, t);
> +}
> +
> +
> +/* Helper for lto_streamer_cache_insert and lto_streamer_cache_insert_at.
> +   CACHE, T, and IX_P are as in lto_streamer_cache_insert.
> +
> +   If INSERT_AT_NEXT_SLOT_P is true, T is inserted at the next available
> +   slot in the cache.  Otherwise, T is inserted at the position indicated
> +   in *IX_P.
> +
> +   If T already existed in CACHE, return true.  Otherwise,
> +   return false.  */
> +
> +static bool
> +lto_streamer_cache_insert_1 (struct lto_streamer_cache_d *cache,
> +			     tree t, unsigned *ix_p,
> +			     bool insert_at_next_slot_p)
> +{
> +  void **slot;
> +  unsigned ix;
> +  bool existed_p;
> +
> +  gcc_assert (t);
> +
> +  slot = pointer_map_insert (cache->node_map, t);
> +  if (!*slot)
> +    {
> +      /* Determine the next slot to use in the cache.  */
> +      if (insert_at_next_slot_p)
> +	ix = VEC_length (tree, cache->nodes);
> +      else
> +	ix = *ix_p;
> +       *slot = (void *)(size_t) (ix + 1);
> +
> +      lto_streamer_cache_add_to_node_array (cache, ix, t);
> +
> +      /* Indicate that the item was not present in the cache.  */
> +      existed_p = false;
> +    }
> +  else
> +    {
> +      ix = (size_t) *slot - 1;
> +
> +      if (!insert_at_next_slot_p && ix != *ix_p)
> +	{
> +	  /* If the caller wants to insert T at a specific slot
> +	     location, and ENTRY->TO does not match *IX_P, add T to
> +	     the requested location slot.  */
> +	  ix = *ix_p;
> +	  lto_streamer_cache_add_to_node_array (cache, ix, t);
> +	}
> +
> +      /* Indicate that T was already in the cache.  */
> +      existed_p = true;
> +    }
> +
> +  if (ix_p)
> +    *ix_p = ix;
> +
> +  return existed_p;
> +}
> +
> +
> +/* Insert tree node T in CACHE.  If T already existed in the cache
> +   return true.  Otherwise, return false.
> +
> +   If IX_P is non-null, update it with the index into the cache where
> +   T has been stored.  */
> +
> +bool
> +lto_streamer_cache_insert (struct lto_streamer_cache_d *cache, tree t,
> +			   unsigned *ix_p)
> +{
> +  return lto_streamer_cache_insert_1 (cache, t, ix_p, true);
> +}
> +
> +
> +/* Insert tree node T in CACHE at slot IX.  If T already
> +   existed in the cache return true.  Otherwise, return false.  */
> +
> +bool
> +lto_streamer_cache_insert_at (struct lto_streamer_cache_d *cache,
> +			      tree t, unsigned ix)
> +{
> +  return lto_streamer_cache_insert_1 (cache, t, &ix, false);
> +}
> +
> +
> +/* Appends tree node T to CACHE, even if T already existed in it.  */
> +
> +void
> +lto_streamer_cache_append (struct lto_streamer_cache_d *cache, tree t)
> +{
> +  unsigned ix = VEC_length (tree, cache->nodes);
> +  lto_streamer_cache_insert_1 (cache, t, &ix, false);
> +}
> +
> +/* Return true if tree node T exists in CACHE, otherwise false.  If IX_P is
> +   not NULL, write to *IX_P the index into the cache where T is stored
> +   ((unsigned)-1 if T is not found).  */
> +
> +bool
> +lto_streamer_cache_lookup (struct lto_streamer_cache_d *cache, tree t,
> +			   unsigned *ix_p)
> +{
> +  void **slot;
> +  bool retval;
> +  unsigned ix;
> +
> +  gcc_assert (t);
> +
> +  slot = pointer_map_contains  (cache->node_map, t);
> +  if (slot == NULL)
> +    {
> +      retval = false;
> +      ix = -1;
> +    }
> +  else
> +    {
> +      retval = true;
> +      ix = (size_t) *slot - 1;
> +    }
> +
> +  if (ix_p)
> +    *ix_p = ix;
> +
> +  return retval;
> +}
> +
> +
> +/* Return the tree node at slot IX in CACHE.  */
> +
> +tree
> +lto_streamer_cache_get (struct lto_streamer_cache_d *cache, unsigned ix)
> +{
> +  gcc_assert (cache);
> +
> +  /* Make sure we're not requesting something we don't have.  */
> +  gcc_assert (ix < VEC_length (tree, cache->nodes));
> +
> +  return VEC_index (tree, cache->nodes, ix);
> +}
> +
> +/* Create a cache of pickled nodes.  */
> +
> +struct lto_streamer_cache_d *
> +lto_streamer_cache_create (void)
> +{
> +  struct lto_streamer_cache_d *cache;
> +
> +  cache = XCNEW (struct lto_streamer_cache_d);
> +
> +  cache->node_map = pointer_map_create ();
> +
> +  /* 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);
> +
> +  return cache;
> +}
> +
> +
> +/* Delete the streamer cache C.  */
> +
> +void
> +lto_streamer_cache_delete (struct lto_streamer_cache_d *c)
> +{
> +  if (c == NULL)
> +    return;
> +
> +  pointer_map_destroy (c->node_map);
> +  VEC_free (tree, heap, c->nodes);
> +  free (c);
> +}
> diff --git a/gcc/tree-streamer.h b/gcc/tree-streamer.h
> new file mode 100644
> index 0000000..9d4740f
> --- /dev/null
> +++ b/gcc/tree-streamer.h
> @@ -0,0 +1,76 @@
> +/* Data structures and functions for streaming trees.
> +
> +   Copyright 2011 Free Software Foundation, Inc.
> +   Contributed by Diego Novillo <dnovillo@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GCC_TREE_STREAMER_H
> +#define GCC_TREE_STREAMER_H
> +
> +#include "tree.h"
> +#include "lto-streamer.h"
> +
> +/* Cache of pickled nodes.  Used to avoid writing the same node more
> +   than once.  The first time a tree node is streamed out, it is
> +   entered in this cache.  Subsequent references to the same node are
> +   resolved by looking it up in this cache.
> +
> +   This is used in two ways:
> +
> +   - On the writing side, the first time T is added to STREAMER_CACHE,
> +     a new reference index is created for T and T is emitted on the
> +     stream.  If T needs to be emitted again to the stream, instead of
> +     pickling it again, the reference index is emitted.
> +
> +   - On the reading side, the first time T is read from the stream, it
> +     is reconstructed in memory and a new reference index created for
> +     T.  The reconstructed T is inserted in some array so that when
> +     the reference index for T is found in the input stream, it can be
> +     used to look up into the array to get the reconstructed T.  */
> +struct lto_streamer_cache_d
> +{
> +  /* The mapping between tree nodes and slots into the nodes array.  */
> +  struct pointer_map_t *node_map;
> +
> +  /* The nodes pickled so far.  */
> +  VEC(tree,heap) *nodes;
> +};
> +
> +/* 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);
> +
> +/* In tree-streamer-out.c.  */
> +void lto_streamer_write_tree (struct output_block *, tree, bool);
> +
> +/* In tree-streamer.c.  */
> +void check_handled_ts_structures (void);
> +bool lto_streamer_cache_insert (struct lto_streamer_cache_d *, tree,
> + 			        unsigned *);
> +bool lto_streamer_cache_insert_at (struct lto_streamer_cache_d *, tree,
> + 				   unsigned);
> +void lto_streamer_cache_append (struct lto_streamer_cache_d *, tree);
> +bool lto_streamer_cache_lookup (struct lto_streamer_cache_d *, tree,
> + 			        unsigned *);
> +tree lto_streamer_cache_get (struct lto_streamer_cache_d *, unsigned);
> +struct lto_streamer_cache_d *lto_streamer_cache_create (void);
> +void lto_streamer_cache_delete (struct lto_streamer_cache_d *);
> +
> +#endif  /* GCC_TREE_STREAMER_H  */
> 
> --
> This patch is available for review at http://codereview.appspot.com/4809083

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [lto] Refactor streamer (1/N) (issue4809083)
  2011-08-08 14:37 [lto] Refactor streamer (1/N) (issue4809083) Diego Novillo
  2011-08-08 14:52 ` Jack Howarth
@ 2011-08-08 14:59 ` Michael Matz
  2011-08-08 15:17   ` Diego Novillo
  1 sibling, 1 reply; 11+ messages in thread
From: Michael Matz @ 2011-08-08 14:59 UTC (permalink / raw)
  To: Diego Novillo; +Cc: reply, rguenther, jh, gcc-patches

Hi,

On Mon, 8 Aug 2011, Diego Novillo wrote:

> With these patches I'd like to:
> 
> 1 Create independent facilities to stream trees, gimple and other
>   data structures independently of LTO.  This first patch creates
>   the files data-streamer*.[ch], tree-streamer*.[ch] and
>   gimple-streamer*.[ch]. There are no other changes yet.  This simply
>   moves functions out of lto-streamer*[ch], but no functions or data
>   structures have been renamed.  This comes in a separate patch.
> 
> 2 Make the naming scheme consistent.  We use a mix of names to mean
>   the same thing (_out_, _output_, _write_, etc).  We have lto_
>   prefixes for functions that are actually generic.  And we still have
>   references to dwarf names (uleb, sleb, etc).
> 
> 3 Abstract the LTO data structures.  The buffering and
>   descriptor data structures used for LTO are somewhat confusing.  The
>   generic streaming routines should simply work on bytecode buffers
>   that are independent of LTO, PPH or other streamers we may want to
>   create in the future.
> 
> 4 Reduce the number of callbacks.  Ideally, I'd like to eliminate them
>   completely.  The API we need to use from PPH is more settled now, so
>   it should be easier to decide what needs a callback and what can be
>   exposed.
> 
> Richard, Michael, Jan, how does this plan sound?

Sound.  ;)  Looking forward to some bikeshedding about naming in (2) and 
overabstraction in (3) :)


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [lto] Refactor streamer (1/N) (issue4809083)
  2011-08-08 14:59 ` Michael Matz
@ 2011-08-08 15:17   ` Diego Novillo
  2011-08-08 15:30     ` Richard Guenther
  0 siblings, 1 reply; 11+ messages in thread
From: Diego Novillo @ 2011-08-08 15:17 UTC (permalink / raw)
  To: Michael Matz; +Cc: reply, rguenther, jh, gcc-patches

On Mon, Aug 8, 2011 at 10:52, Michael Matz <matz@suse.de> wrote:

> Sound.  ;)  Looking forward to some bikeshedding about naming in (2) and
> overabstraction in (3) :)

Heh, yeah.

I am going to be sending the renaming patch later today or tomorrow.
In principle, the things I want to abstract are those that are forcing
me to include lto-streamer.h from {tree,gimple,data}-streamer.*.
I will know better when I merge this into the pph branch, though.


Diego.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [lto] Refactor streamer (1/N) (issue4809083)
  2011-08-08 14:52 ` Jack Howarth
@ 2011-08-08 15:17   ` Diego Novillo
  0 siblings, 0 replies; 11+ messages in thread
From: Diego Novillo @ 2011-08-08 15:17 UTC (permalink / raw)
  To: Jack Howarth; +Cc: reply, rguenther, jh, matz, gcc-patches

On Mon, Aug 8, 2011 at 10:35, Jack Howarth <howarth@bromo.med.uc.edu> wrote:
> On Mon, Aug 08, 2011 at 10:23:34AM -0400, Diego Novillo wrote:
>>
>> This is the first patch in a series of refactoring patches to cleanup
>> the API for the LTO streamer.  I need this cleanup so I can change the
>> way things like caching and external references work in PPH.  With the
>> current code, I would need to introduce even more streamer hooks.  But
>> if we simplify the API and create smaller low-level streaming
>> functions, then we can have the LTO and PPH streamer use these
>> functions without having to resort to a lot of callbacks.
>
> Diego,
>   While you are cleaning up the streamer can you also take a look at..
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49992
>
> to see if these duplicate symbols also exist on linux in a non-fatal manner?
> The change in r177358 broke the ability to do a lto-bootstrap on darwin.
> While the lto-bootstrap appears to still work on linux (from the gcc-testresults
> postings), it is unclear if any of these is using the lto-streamer instead
> of the lto linker plugin. I think this should be fixed ASP since darwin is
> probably one of the last targets to still use the lto-streamer instead of
> the linker plugin.

I think we are talking about different things.  The streamer is the
set of low-level functions that pickle and unpickle GCC data
structures.  It has nothing to do with the linker plugin.  All I'm
doing is moving functions around and renaming things.  None of these
patches will change any existing functionality (least of all anything
related to higher-level modules).


Diego.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [lto] Refactor streamer (1/N) (issue4809083)
  2011-08-08 15:17   ` Diego Novillo
@ 2011-08-08 15:30     ` Richard Guenther
  2011-08-26 10:28       ` Richard Guenther
  0 siblings, 1 reply; 11+ messages in thread
From: Richard Guenther @ 2011-08-08 15:30 UTC (permalink / raw)
  To: Diego Novillo; +Cc: Michael Matz, reply, jh, gcc-patches

[-- Attachment #1: Type: TEXT/PLAIN, Size: 617 bytes --]

On Mon, 8 Aug 2011, Diego Novillo wrote:

> On Mon, Aug 8, 2011 at 10:52, Michael Matz <matz@suse.de> wrote:
> 
> > Sound.  ;)  Looking forward to some bikeshedding about naming in (2) and
> > overabstraction in (3) :)
> 
> Heh, yeah.
> 
> I am going to be sending the renaming patch later today or tomorrow.
> In principle, the things I want to abstract are those that are forcing
> me to include lto-streamer.h from {tree,gimple,data}-streamer.*.
> I will know better when I merge this into the pph branch, though.

Yeah, I think we discussed this already and agreed on that this is
a sensible plan.

Richard.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [lto] Refactor streamer (1/N) (issue4809083)
  2011-08-08 15:30     ` Richard Guenther
@ 2011-08-26 10:28       ` Richard Guenther
  2011-08-26 12:50         ` Michael Matz
  2011-08-26 12:51         ` Diego Novillo
  0 siblings, 2 replies; 11+ messages in thread
From: Richard Guenther @ 2011-08-26 10:28 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Diego Novillo, Michael Matz, reply, jh, gcc-patches

On Mon, Aug 8, 2011 at 5:17 PM, Richard Guenther <rguenther@suse.de> wrote:
> On Mon, 8 Aug 2011, Diego Novillo wrote:
>
>> On Mon, Aug 8, 2011 at 10:52, Michael Matz <matz@suse.de> wrote:
>>
>> > Sound.  ;)  Looking forward to some bikeshedding about naming in (2) and
>> > overabstraction in (3) :)
>>
>> Heh, yeah.
>>
>> I am going to be sending the renaming patch later today or tomorrow.
>> In principle, the things I want to abstract are those that are forcing
>> me to include lto-streamer.h from {tree,gimple,data}-streamer.*.
>> I will know better when I merge this into the pph branch, though.
>
> Yeah, I think we discussed this already and agreed on that this is
> a sensible plan.

This patch caused http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50165
it seems that LTO string hashing is seriously broken now.

Richard.

> Richard.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [lto] Refactor streamer (1/N) (issue4809083)
  2011-08-26 10:28       ` Richard Guenther
@ 2011-08-26 12:50         ` Michael Matz
  2011-08-26 12:57           ` Jakub Jelinek
  2011-08-26 12:51         ` Diego Novillo
  1 sibling, 1 reply; 11+ messages in thread
From: Michael Matz @ 2011-08-26 12:50 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Richard Guenther, Diego Novillo, reply, jh, gcc-patches

Hi,

On Fri, 26 Aug 2011, Richard Guenther wrote:

> >> I am going to be sending the renaming patch later today or tomorrow. 
> >> In principle, the things I want to abstract are those that are 
> >> forcing me to include lto-streamer.h from 
> >> {tree,gimple,data}-streamer.*. I will know better when I merge this 
> >> into the pph branch, though.
> >
> > Yeah, I think we discussed this already and agreed on that this is a 
> > sensible plan.
> 
> This patch caused http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50165 it 
> seems that LTO string hashing is seriously broken now.

Once regstrap passes on x86_64-linux I'm checking this in as obvious.


Ciao,
Michael.
-- 
	PR lto/50165
	* lto-streamer-in.c (canon_file_name): Initialize new_slot->len.

Index: lto-streamer-in.c
===================================================================
--- lto-streamer-in.c	(revision 178040)
+++ lto-streamer-in.c	(working copy)
@@ -113,6 +113,7 @@ canon_file_name (const char *string)
       new_slot = XCNEW (struct string_slot);
       strcpy (saved_string, string);
       new_slot->s = saved_string;
+      new_slot->len = len;
       *slot = new_slot;
       return saved_string;
     }

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [lto] Refactor streamer (1/N) (issue4809083)
  2011-08-26 10:28       ` Richard Guenther
  2011-08-26 12:50         ` Michael Matz
@ 2011-08-26 12:51         ` Diego Novillo
  1 sibling, 0 replies; 11+ messages in thread
From: Diego Novillo @ 2011-08-26 12:51 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Richard Guenther, Michael Matz, reply, jh, gcc-patches

On 11-08-26 04:24 , Richard Guenther wrote:

> This patch caused http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50165
> it seems that LTO string hashing is seriously broken now.

Sorry about this.  Bad timing as I will be away until 7/Sep.  Would it 
make things easier if the commit that introduced this was reverted?


Diego.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [lto] Refactor streamer (1/N) (issue4809083)
  2011-08-26 12:50         ` Michael Matz
@ 2011-08-26 12:57           ` Jakub Jelinek
  2011-08-26 17:11             ` Michael Matz
  0 siblings, 1 reply; 11+ messages in thread
From: Jakub Jelinek @ 2011-08-26 12:57 UTC (permalink / raw)
  To: Michael Matz
  Cc: Richard Guenther, Richard Guenther, Diego Novillo, reply, jh,
	gcc-patches

On Fri, Aug 26, 2011 at 02:34:29PM +0200, Michael Matz wrote:
> Hi,
> 
> On Fri, 26 Aug 2011, Richard Guenther wrote:
> 
> > >> I am going to be sending the renaming patch later today or tomorrow. 
> > >> In principle, the things I want to abstract are those that are 
> > >> forcing me to include lto-streamer.h from 
> > >> {tree,gimple,data}-streamer.*. I will know better when I merge this 
> > >> into the pph branch, though.
> > >
> > > Yeah, I think we discussed this already and agreed on that this is a 
> > > sensible plan.
> > 
> > This patch caused http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50165 it 
> > seems that LTO string hashing is seriously broken now.
> 
> Once regstrap passes on x86_64-linux I'm checking this in as obvious.

While you are touching it, I think we should also optimize it as in the
patch below.  I'm afraid no string length optimization would be able to
figure out that it doesn't have to call strlen twice, because the
htab_find_slot isn't pure.

2011-08-26  Jakub Jelinek  <jakub@redhat.com>

	* lto-streamer-in.c (canon_file_name): Avoid calling strlen twice,
	use memcpy instead of strcpy.

--- gcc/lto-streamer-in.c.jj	2011-08-26 14:39:52.000000000 +0200
+++ gcc/lto-streamer-in.c	2011-08-26 14:40:59.543884012 +0200
@@ -98,21 +98,20 @@ canon_file_name (const char *string)
 {
   void **slot;
   struct string_slot s_slot;
+  size_t len = strlen (string);
   s_slot.s = string;
-  s_slot.len = strlen (string);
+  s_slot.len = len;
 
   slot = htab_find_slot (file_name_hash_table, &s_slot, INSERT);
   if (*slot == NULL)
     {
-      size_t len;
       char *saved_string;
       struct string_slot *new_slot;
 
-      len = strlen (string);
       saved_string = (char *) xmalloc (len + 1);
       new_slot = XCNEW (struct string_slot);
       new_slot->len = len;
-      strcpy (saved_string, string);
+      memcpy (saved_string, string, len + 1);
       new_slot->s = saved_string;
       *slot = new_slot;
       return saved_string;

	Jakub

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [lto] Refactor streamer (1/N) (issue4809083)
  2011-08-26 12:57           ` Jakub Jelinek
@ 2011-08-26 17:11             ` Michael Matz
  0 siblings, 0 replies; 11+ messages in thread
From: Michael Matz @ 2011-08-26 17:11 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Richard Guenther, Richard Guenther, Diego Novillo, reply, jh,
	gcc-patches

Hi,

On Fri, 26 Aug 2011, Jakub Jelinek wrote:

> While you are touching it, I think we should also optimize it as in the 
> patch below.  I'm afraid no string length optimization would be able to 
> figure out that it doesn't have to call strlen twice, because the 
> htab_find_slot isn't pure.

Sure.  Regstrapped the below patch and checked in as r178118.


Ciao,
Michael.
-- 
Index: lto-streamer-in.c
===================================================================
--- lto-streamer-in.c   (revision 178117)
+++ lto-streamer-in.c   (revision 178118)
@@ -98,21 +98,22 @@ canon_file_name (const char *string)
 {
   void **slot;
   struct string_slot s_slot;
+  size_t len = strlen (string);
+
   s_slot.s = string;
-  s_slot.len = strlen (string);
+  s_slot.len = len;

   slot = htab_find_slot (file_name_hash_table, &s_slot, INSERT);
   if (*slot == NULL)
     {
-      size_t len;
       char *saved_string;
       struct string_slot *new_slot;

-      len = strlen (string);
       saved_string = (char *) xmalloc (len + 1);
       new_slot = XCNEW (struct string_slot);
-      strcpy (saved_string, string);
+      memcpy (saved_string, string, len + 1);
       new_slot->s = saved_string;
+      new_slot->len = len;
       *slot = new_slot;
       return saved_string;
     }

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2011-08-26 16:04 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-08 14:37 [lto] Refactor streamer (1/N) (issue4809083) Diego Novillo
2011-08-08 14:52 ` Jack Howarth
2011-08-08 15:17   ` Diego Novillo
2011-08-08 14:59 ` Michael Matz
2011-08-08 15:17   ` Diego Novillo
2011-08-08 15:30     ` Richard Guenther
2011-08-26 10:28       ` Richard Guenther
2011-08-26 12:50         ` Michael Matz
2011-08-26 12:57           ` Jakub Jelinek
2011-08-26 17:11             ` Michael Matz
2011-08-26 12:51         ` Diego Novillo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).