This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][RFC] Re-organize how we stream trees in LTO


This patch shows work-in-progress (read: implementation uglyness
hopefully to vanish ...) regarding to moving LTO type merging
work from WPA to compile stage.

The patch re-organizes lto_output_tree (the write_tree streamer
hook for LTO) in a way so that we output all tree fields
in easy to discover places.  This means that we have forward
references to trees not yet (fully) written, something the
current state avoids by "inline-expanding" forward referenced
trees at the point of reference (which results in interweaved
trees on disk).  To be able to achieve this lto_output_tree
now performs a DFS walk along tree edges to collect trees
that need to be output and outputs them in SCC chunks
in a new LTO stream container, LTO_tree_scc.

This will allow the reader side at WPA stage to call uniquify
nodes on each tree SCC, avoiding completely the DFS walks done
there (hopefully, we do DFS walks for both hashing and comparing
there - note that WPA gathers type SCCs, not tree SCCs - a subtle
difference that remains to be seen on whether it is important ...)

One complication is how we handle streaming INTEGER_CSTs.
When an INTEGER_CST refers to an already input type we can
allocate it using the build_int_cst_wide routine which takes
care of putting it into the appropriate hashtables for caching.
If an INTEGER_CST is part of a SCC (TYPE_DOMAIN values are
the most obvious cases) we now stream them as regular trees
(they cannot already exist in any cache as the type is being
read in) - but the patch does not yet populate the caches
in case the type ends up prevailing (thus it will produce
some unshared INTEGER_CSTs for now).

One uglyness of the patch is how I mis-use the streamer hooks
to switch the tree streamer routines from actually writing
tree references to performing the DFS walk.  For the DFS walk
I need information on the edge, thus a 'from' tree argument
is added to the write_tree hook.  Eventually my plan was
to transform this to a walk_tree-like interface.

Diego - is PTH still live?  Thus, do I need to bother about
inventing things in a way that can be hook-ized?  Do you
forsee any complication for PTH or C++ modules the way
I re-arranged things?  Any good (C++) ideas on how to
design this lto_walk_tree?

The patch below survives LTO bootstrap (ok, we are only
in stage2 yet ...) so it serves as suitable vehicle for
gathering statistics about tree SCC sizes.  It's probably
the state I'll build on re-organizing uniquify_nodes to
avoid the various DFS walks done there.

Any comments welcome.

Thanks,
Richard.

Index: trunk/gcc/streamer-hooks.h
===================================================================
*** trunk.orig/gcc/streamer-hooks.h	2012-10-15 16:17:56.000000000 +0200
--- trunk/gcc/streamer-hooks.h	2012-10-16 14:42:15.571464478 +0200
*************** struct streamer_hooks {
*** 44,50 ****
       tree itself.  The second boolean parameter specifies this for
       the tree itself, the first for all siblings that are streamed.
       The referencing mechanism is up to each streamer to implement.  */
!   void (*write_tree) (struct output_block *, tree, bool, bool);
  
    /* [REQ] Called by every tree streaming routine that needs to read
       a tree node.  It takes two arguments: an lto_input_block pointing
--- 44,50 ----
       tree itself.  The second boolean parameter specifies this for
       the tree itself, the first for all siblings that are streamed.
       The referencing mechanism is up to each streamer to implement.  */
!   void (*write_tree) (struct output_block *, tree, tree, bool, bool);
  
    /* [REQ] Called by every tree streaming routine that needs to read
       a tree node.  It takes two arguments: an lto_input_block pointing
*************** struct streamer_hooks {
*** 61,70 ****
  };
  
  #define stream_write_tree(OB, EXPR, REF_P) \
!     streamer_hooks.write_tree(OB, EXPR, REF_P, REF_P)
  
  #define stream_write_tree_shallow_non_ref(OB, EXPR, REF_P) \
!     streamer_hooks.write_tree(OB, EXPR, REF_P, false)
  
  #define stream_read_tree(IB, DATA_IN) \
      streamer_hooks.read_tree(IB, DATA_IN)
--- 61,76 ----
  };
  
  #define stream_write_tree(OB, EXPR, REF_P) \
!     streamer_hooks.write_tree(OB, NULL_TREE, EXPR, REF_P, REF_P)
  
  #define stream_write_tree_shallow_non_ref(OB, EXPR, REF_P) \
!     streamer_hooks.write_tree(OB, NULL_TREE, EXPR, REF_P, false)
! 
! #define stream_write_tree_edge(OB, FROM, TO, REF_P) \
!     streamer_hooks.write_tree(OB, FROM, TO, REF_P, REF_P)
! 
! #define stream_write_tree_edge_shallow_non_ref(OB, FROM, TO, REF_P) \
!     streamer_hooks.write_tree(OB, FROM, TO, REF_P, false)
  
  #define stream_read_tree(IB, DATA_IN) \
      streamer_hooks.read_tree(IB, DATA_IN)
Index: trunk/gcc/tree-streamer-out.c
===================================================================
*** trunk.orig/gcc/tree-streamer-out.c	2012-10-15 16:17:56.000000000 +0200
--- trunk/gcc/tree-streamer-out.c	2012-10-16 15:44:51.688240278 +0200
*************** pack_ts_base_value_fields (struct bitpac
*** 112,117 ****
--- 112,128 ----
  }
  
  
+ /* Pack all the non-pointer fields of the TS_INTEGER_CST structure of
+    expression EXPR into bitpack BP.  */
+ 
+ static void
+ pack_ts_int_cst_value_fields (struct bitpack_d *bp, tree expr)
+ {
+   bp_pack_var_len_unsigned (bp, TREE_INT_CST_LOW (expr));
+   bp_pack_var_len_int (bp, TREE_INT_CST_HIGH (expr));
+ }
+ 
+ 
  /* Pack all the non-pointer fields of the TS_REAL_CST structure of
     expression EXPR into bitpack BP.  */
  
*************** streamer_pack_tree_bitfields (struct out
*** 373,378 ****
--- 384,392 ----
       the types and sizes of each of the fields being packed.  */
    pack_ts_base_value_fields (bp, expr);
  
+   if (CODE_CONTAINS_STRUCT (code, TS_INT_CST))
+     pack_ts_int_cst_value_fields (bp, expr);
+ 
    if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
      pack_ts_real_cst_value_fields (bp, expr);
  
*************** streamer_write_builtin (struct output_bl
*** 460,466 ****
     as references.  */
  
  void
! streamer_write_chain (struct output_block *ob, tree t, bool ref_p)
  {
    while (t)
      {
--- 474,480 ----
     as references.  */
  
  void
! streamer_write_chain (struct output_block *ob, tree from, tree t, bool ref_p)
  {
    while (t)
      {
*************** streamer_write_chain (struct output_bloc
*** 477,485 ****
  	 for streaming BLOCK_VARS, but other callers are safe.  */
        if (VAR_OR_FUNCTION_DECL_P (t)
  	  && DECL_EXTERNAL (t))
! 	stream_write_tree_shallow_non_ref (ob, t, ref_p);
        else
! 	stream_write_tree (ob, t, ref_p);
  
        TREE_CHAIN (t) = saved_chain;
        t = TREE_CHAIN (t);
--- 491,499 ----
  	 for streaming BLOCK_VARS, but other callers are safe.  */
        if (VAR_OR_FUNCTION_DECL_P (t)
  	  && DECL_EXTERNAL (t))
! 	stream_write_tree_edge_shallow_non_ref (ob, from, t, ref_p);
        else
! 	stream_write_tree_edge (ob, from, t, ref_p);
  
        TREE_CHAIN (t) = saved_chain;
        t = TREE_CHAIN (t);
*************** static void
*** 498,504 ****
  write_ts_common_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
  {
    if (TREE_CODE (expr) != IDENTIFIER_NODE)
!     stream_write_tree (ob, TREE_TYPE (expr), ref_p);
  }
  
  
--- 512,518 ----
  write_ts_common_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
  {
    if (TREE_CODE (expr) != IDENTIFIER_NODE)
!     stream_write_tree_edge (ob, expr, TREE_TYPE (expr), ref_p);
  }
  
  
*************** write_ts_vector_tree_pointers (struct ou
*** 513,519 ****
    /* Note that the number of elements for EXPR has already been emitted
       in EXPR's header (see streamer_write_tree_header).  */
    for (i = 0; i < VECTOR_CST_NELTS (expr); ++i)
!     stream_write_tree (ob, VECTOR_CST_ELT (expr, i), ref_p);
  }
  
  
--- 527,533 ----
    /* Note that the number of elements for EXPR has already been emitted
       in EXPR's header (see streamer_write_tree_header).  */
    for (i = 0; i < VECTOR_CST_NELTS (expr); ++i)
!     stream_write_tree_edge (ob, expr, VECTOR_CST_ELT (expr, i), ref_p);
  }
  
  
*************** write_ts_vector_tree_pointers (struct ou
*** 524,531 ****
  static void
  write_ts_complex_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
  {
!   stream_write_tree (ob, TREE_REALPART (expr), ref_p);
!   stream_write_tree (ob, TREE_IMAGPART (expr), ref_p);
  }
  
  
--- 538,545 ----
  static void
  write_ts_complex_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
  {
!   stream_write_tree_edge (ob, expr, TREE_REALPART (expr), ref_p);
!   stream_write_tree_edge (ob, expr, TREE_IMAGPART (expr), ref_p);
  }
  
  
*************** static void
*** 537,544 ****
  write_ts_decl_minimal_tree_pointers (struct output_block *ob, tree expr,
  				     bool ref_p)
  {
!   stream_write_tree (ob, DECL_NAME (expr), ref_p);
!   stream_write_tree (ob, DECL_CONTEXT (expr), ref_p);
  }
  
  
--- 551,558 ----
  write_ts_decl_minimal_tree_pointers (struct output_block *ob, tree expr,
  				     bool ref_p)
  {
!   stream_write_tree_edge (ob, expr, DECL_NAME (expr), ref_p);
!   stream_write_tree_edge (ob, expr, DECL_CONTEXT (expr), ref_p);
  }
  
  
*************** static void
*** 550,577 ****
  write_ts_decl_common_tree_pointers (struct output_block *ob, tree expr,
  				    bool ref_p)
  {
!   stream_write_tree (ob, DECL_SIZE (expr), ref_p);
!   stream_write_tree (ob, DECL_SIZE_UNIT (expr), ref_p);
  
    /* Note, DECL_INITIAL is not handled here.  Since DECL_INITIAL needs
       special handling in LTO, it must be handled by streamer hooks.  */
  
!   stream_write_tree (ob, DECL_ATTRIBUTES (expr), ref_p);
  
    /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
       for early inlining so drop it on the floor instead of ICEing in
       dwarf2out.c.  */
  
    if (TREE_CODE (expr) == PARM_DECL)
!     streamer_write_chain (ob, TREE_CHAIN (expr), ref_p);
  
    if ((TREE_CODE (expr) == VAR_DECL
         || TREE_CODE (expr) == PARM_DECL)
        && DECL_HAS_VALUE_EXPR_P (expr))
!     stream_write_tree (ob, DECL_VALUE_EXPR (expr), ref_p);
  
    if (TREE_CODE (expr) == VAR_DECL)
!     stream_write_tree (ob, DECL_DEBUG_EXPR (expr), ref_p);
  }
  
  
--- 564,591 ----
  write_ts_decl_common_tree_pointers (struct output_block *ob, tree expr,
  				    bool ref_p)
  {
!   stream_write_tree_edge (ob, expr, DECL_SIZE (expr), ref_p);
!   stream_write_tree_edge (ob, expr, 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.  */
  
!   stream_write_tree_edge (ob, expr, 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)
!     streamer_write_chain (ob, expr, TREE_CHAIN (expr), ref_p);
  
    if ((TREE_CODE (expr) == VAR_DECL
         || TREE_CODE (expr) == PARM_DECL)
        && DECL_HAS_VALUE_EXPR_P (expr))
!     stream_write_tree_edge (ob, expr, DECL_VALUE_EXPR (expr), ref_p);
  
    if (TREE_CODE (expr) == VAR_DECL)
!     stream_write_tree_edge (ob, expr, DECL_DEBUG_EXPR (expr), ref_p);
  }
  
  
*************** write_ts_decl_non_common_tree_pointers (
*** 585,596 ****
  {
    if (TREE_CODE (expr) == FUNCTION_DECL)
      {
!       stream_write_tree (ob, DECL_ARGUMENTS (expr), ref_p);
!       stream_write_tree (ob, DECL_RESULT (expr), ref_p);
      }
    else if (TREE_CODE (expr) == TYPE_DECL)
!     stream_write_tree (ob, DECL_ORIGINAL_TYPE (expr), ref_p);
!   stream_write_tree (ob, DECL_VINDEX (expr), ref_p);
  }
  
  
--- 599,610 ----
  {
    if (TREE_CODE (expr) == FUNCTION_DECL)
      {
!       stream_write_tree_edge (ob, expr, DECL_ARGUMENTS (expr), ref_p);
!       stream_write_tree_edge (ob, expr, DECL_RESULT (expr), ref_p);
      }
    else if (TREE_CODE (expr) == TYPE_DECL)
!     stream_write_tree_edge (ob, expr, DECL_ORIGINAL_TYPE (expr), ref_p);
!   stream_write_tree_edge (ob, expr, DECL_VINDEX (expr), ref_p);
  }
  
  
*************** write_ts_decl_with_vis_tree_pointers (st
*** 604,615 ****
  {
    /* Make sure we don't inadvertently set the assembler name.  */
    if (DECL_ASSEMBLER_NAME_SET_P (expr))
!     stream_write_tree (ob, DECL_ASSEMBLER_NAME (expr), ref_p);
    else
      stream_write_tree (ob, NULL_TREE, false);
  
!   stream_write_tree (ob, DECL_SECTION_NAME (expr), ref_p);
!   stream_write_tree (ob, DECL_COMDAT_GROUP (expr), ref_p);
  }
  
  
--- 618,629 ----
  {
    /* Make sure we don't inadvertently set the assembler name.  */
    if (DECL_ASSEMBLER_NAME_SET_P (expr))
!     stream_write_tree_edge (ob, expr, DECL_ASSEMBLER_NAME (expr), ref_p);
    else
      stream_write_tree (ob, NULL_TREE, false);
  
!   stream_write_tree_edge (ob, expr, DECL_SECTION_NAME (expr), ref_p);
!   stream_write_tree_edge (ob, expr, DECL_COMDAT_GROUP (expr), ref_p);
  }
  
  
*************** static void
*** 621,631 ****
  write_ts_field_decl_tree_pointers (struct output_block *ob, tree expr,
  				   bool ref_p)
  {
!   stream_write_tree (ob, DECL_FIELD_OFFSET (expr), ref_p);
!   stream_write_tree (ob, DECL_BIT_FIELD_TYPE (expr), ref_p);
!   stream_write_tree (ob, DECL_BIT_FIELD_REPRESENTATIVE (expr), ref_p);
!   stream_write_tree (ob, DECL_FIELD_BIT_OFFSET (expr), ref_p);
!   stream_write_tree (ob, DECL_FCONTEXT (expr), ref_p);
  }
  
  
--- 635,645 ----
  write_ts_field_decl_tree_pointers (struct output_block *ob, tree expr,
  				   bool ref_p)
  {
!   stream_write_tree_edge (ob, expr, DECL_FIELD_OFFSET (expr), ref_p);
!   stream_write_tree_edge (ob, expr, DECL_BIT_FIELD_TYPE (expr), ref_p);
!   stream_write_tree_edge (ob, expr, DECL_BIT_FIELD_REPRESENTATIVE (expr), ref_p);
!   stream_write_tree_edge (ob, expr, DECL_FIELD_BIT_OFFSET (expr), ref_p);
!   stream_write_tree_edge (ob, expr, DECL_FCONTEXT (expr), ref_p);
  }
  
  
*************** write_ts_function_decl_tree_pointers (st
*** 639,647 ****
  {
    /* DECL_STRUCT_FUNCTION is handled by lto_output_function.  FIXME lto,
       maybe it should be handled here?  */
!   stream_write_tree (ob, DECL_FUNCTION_PERSONALITY (expr), ref_p);
!   stream_write_tree (ob, DECL_FUNCTION_SPECIFIC_TARGET (expr), ref_p);
!   stream_write_tree (ob, DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr), ref_p);
  }
  
  
--- 653,664 ----
  {
    /* DECL_STRUCT_FUNCTION is handled by lto_output_function.  FIXME lto,
       maybe it should be handled here?  */
!   stream_write_tree_edge (ob, expr,
! 			  DECL_FUNCTION_PERSONALITY (expr), ref_p);
!   stream_write_tree_edge (ob, expr,
! 			  DECL_FUNCTION_SPECIFIC_TARGET (expr), ref_p);
!   stream_write_tree_edge (ob, expr,
! 			  DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr), ref_p);
  }
  
  
*************** static void
*** 653,671 ****
  write_ts_type_common_tree_pointers (struct output_block *ob, tree expr,
  				    bool ref_p)
  {
!   stream_write_tree (ob, TYPE_SIZE (expr), ref_p);
!   stream_write_tree (ob, TYPE_SIZE_UNIT (expr), ref_p);
!   stream_write_tree (ob, TYPE_ATTRIBUTES (expr), ref_p);
!   stream_write_tree (ob, TYPE_NAME (expr), ref_p);
    /* Do not stream TYPE_POINTER_TO or TYPE_REFERENCE_TO.  They will be
       reconstructed during fixup.  */
    /* Do not stream TYPE_NEXT_VARIANT, we reconstruct the variant lists
       during fixup.  */
!   stream_write_tree (ob, TYPE_MAIN_VARIANT (expr), ref_p);
!   stream_write_tree (ob, TYPE_CONTEXT (expr), ref_p);
    /* TYPE_CANONICAL is re-computed during type merging, so no need
       to stream it here.  */
!   stream_write_tree (ob, TYPE_STUB_DECL (expr), ref_p);
  }
  
  /* Write all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
--- 670,688 ----
  write_ts_type_common_tree_pointers (struct output_block *ob, tree expr,
  				    bool ref_p)
  {
!   stream_write_tree_edge (ob, expr, TYPE_SIZE (expr), ref_p);
!   stream_write_tree_edge (ob, expr, TYPE_SIZE_UNIT (expr), ref_p);
!   stream_write_tree_edge (ob, expr, TYPE_ATTRIBUTES (expr), ref_p);
!   stream_write_tree_edge (ob, expr, 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.  */
!   stream_write_tree_edge (ob, expr, TYPE_MAIN_VARIANT (expr), ref_p);
!   stream_write_tree_edge (ob, expr, TYPE_CONTEXT (expr), ref_p);
    /* TYPE_CANONICAL is re-computed during type merging, so no need
       to stream it here.  */
!   stream_write_tree_edge (ob, expr, TYPE_STUB_DECL (expr), ref_p);
  }
  
  /* Write all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
*************** write_ts_type_non_common_tree_pointers (
*** 677,696 ****
  					bool ref_p)
  {
    if (TREE_CODE (expr) == ENUMERAL_TYPE)
!     stream_write_tree (ob, TYPE_VALUES (expr), ref_p);
    else if (TREE_CODE (expr) == ARRAY_TYPE)
!     stream_write_tree (ob, TYPE_DOMAIN (expr), ref_p);
    else if (RECORD_OR_UNION_TYPE_P (expr))
!     streamer_write_chain (ob, TYPE_FIELDS (expr), ref_p);
    else if (TREE_CODE (expr) == FUNCTION_TYPE
  	   || TREE_CODE (expr) == METHOD_TYPE)
!     stream_write_tree (ob, TYPE_ARG_TYPES (expr), ref_p);
  
    if (!POINTER_TYPE_P (expr))
!     stream_write_tree (ob, TYPE_MINVAL (expr), ref_p);
!   stream_write_tree (ob, TYPE_MAXVAL (expr), ref_p);
    if (RECORD_OR_UNION_TYPE_P (expr))
!     stream_write_tree (ob, TYPE_BINFO (expr), ref_p);
  }
  
  
--- 694,713 ----
  					bool ref_p)
  {
    if (TREE_CODE (expr) == ENUMERAL_TYPE)
!     stream_write_tree_edge (ob, expr, TYPE_VALUES (expr), ref_p);
    else if (TREE_CODE (expr) == ARRAY_TYPE)
!     stream_write_tree_edge (ob, expr, TYPE_DOMAIN (expr), ref_p);
    else if (RECORD_OR_UNION_TYPE_P (expr))
!     streamer_write_chain (ob, expr, TYPE_FIELDS (expr), ref_p);
    else if (TREE_CODE (expr) == FUNCTION_TYPE
  	   || TREE_CODE (expr) == METHOD_TYPE)
!     stream_write_tree_edge (ob, expr, TYPE_ARG_TYPES (expr), ref_p);
  
    if (!POINTER_TYPE_P (expr))
!     stream_write_tree_edge (ob, expr, TYPE_MINVAL (expr), ref_p);
!   stream_write_tree_edge (ob, expr, TYPE_MAXVAL (expr), ref_p);
    if (RECORD_OR_UNION_TYPE_P (expr))
!     stream_write_tree_edge (ob, expr, TYPE_BINFO (expr), ref_p);
  }
  
  
*************** write_ts_type_non_common_tree_pointers (
*** 701,709 ****
  static void
  write_ts_list_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
  {
!   stream_write_tree (ob, TREE_PURPOSE (expr), ref_p);
!   stream_write_tree (ob, TREE_VALUE (expr), ref_p);
!   streamer_write_chain (ob, TREE_CHAIN (expr), ref_p);
  }
  
  
--- 718,726 ----
  static void
  write_ts_list_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
  {
!   stream_write_tree_edge (ob, expr, TREE_PURPOSE (expr), ref_p);
!   stream_write_tree_edge (ob, expr, TREE_VALUE (expr), ref_p);
!   streamer_write_chain (ob, expr, TREE_CHAIN (expr), ref_p);
  }
  
  
*************** write_ts_vec_tree_pointers (struct outpu
*** 719,725 ****
    /* Note that the number of slots for EXPR has already been emitted
       in EXPR's header (see streamer_write_tree_header).  */
    for (i = 0; i < TREE_VEC_LENGTH (expr); i++)
!     stream_write_tree (ob, TREE_VEC_ELT (expr, i), ref_p);
  }
  
  
--- 736,742 ----
    /* Note that the number of slots for EXPR has already been emitted
       in EXPR's header (see streamer_write_tree_header).  */
    for (i = 0; i < TREE_VEC_LENGTH (expr); i++)
!     stream_write_tree_edge (ob, expr, TREE_VEC_ELT (expr, i), ref_p);
  }
  
  
*************** write_ts_exp_tree_pointers (struct outpu
*** 733,740 ****
    int i;
  
    for (i = 0; i < TREE_OPERAND_LENGTH (expr); i++)
!     stream_write_tree (ob, TREE_OPERAND (expr, i), ref_p);
!   stream_write_tree (ob, TREE_BLOCK (expr), ref_p);
  }
  
  
--- 750,757 ----
    int i;
  
    for (i = 0; i < TREE_OPERAND_LENGTH (expr); i++)
!     stream_write_tree_edge (ob, expr, TREE_OPERAND (expr, i), ref_p);
!   stream_write_tree_edge (ob, expr, TREE_BLOCK (expr), ref_p);
  }
  
  
*************** write_ts_exp_tree_pointers (struct outpu
*** 745,753 ****
  static void
  write_ts_block_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
  {
!   streamer_write_chain (ob, BLOCK_VARS (expr), ref_p);
  
!   stream_write_tree (ob, BLOCK_SUPERCONTEXT (expr), ref_p);
  
    /* Stream BLOCK_ABSTRACT_ORIGIN for the limited cases we can handle - those
       that represent inlined function scopes.
--- 762,770 ----
  static void
  write_ts_block_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
  {
!   streamer_write_chain (ob, expr, BLOCK_VARS (expr), ref_p);
  
!   stream_write_tree_edge (ob, expr, BLOCK_SUPERCONTEXT (expr), ref_p);
  
    /* Stream BLOCK_ABSTRACT_ORIGIN for the limited cases we can handle - those
       that represent inlined function scopes.
*************** write_ts_block_tree_pointers (struct out
*** 755,761 ****
    if (inlined_function_outer_scope_p (expr))
      {
        tree ultimate_origin = block_ultimate_origin (expr);
!       stream_write_tree (ob, ultimate_origin, ref_p);
      }
    else
      stream_write_tree (ob, NULL_TREE, ref_p);
--- 772,778 ----
    if (inlined_function_outer_scope_p (expr))
      {
        tree ultimate_origin = block_ultimate_origin (expr);
!       stream_write_tree_edge (ob, expr, ultimate_origin, ref_p);
      }
    else
      stream_write_tree (ob, NULL_TREE, ref_p);
*************** write_ts_binfo_tree_pointers (struct out
*** 785,805 ****
       EXPR's header (see streamer_write_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)
!     stream_write_tree (ob, t, ref_p);
    stream_write_tree (ob, NULL_TREE, false);
  
!   stream_write_tree (ob, BINFO_OFFSET (expr), ref_p);
!   stream_write_tree (ob, BINFO_VTABLE (expr), ref_p);
!   stream_write_tree (ob, BINFO_VPTR_FIELD (expr), ref_p);
  
    /* The number of BINFO_BASE_ACCESSES has already been emitted in
       EXPR's bitfield section.  */
    FOR_EACH_VEC_ELT (tree, BINFO_BASE_ACCESSES (expr), i, t)
!     stream_write_tree (ob, t, ref_p);
  
!   stream_write_tree (ob, BINFO_INHERITANCE_CHAIN (expr), ref_p);
!   stream_write_tree (ob, BINFO_SUBVTT_INDEX (expr), ref_p);
!   stream_write_tree (ob, BINFO_VPTR_INDEX (expr), ref_p);
  }
  
  
--- 802,822 ----
       EXPR's header (see streamer_write_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)
!     stream_write_tree_edge (ob, expr, t, ref_p);
    stream_write_tree (ob, NULL_TREE, false);
  
!   stream_write_tree_edge (ob, expr, BINFO_OFFSET (expr), ref_p);
!   stream_write_tree_edge (ob, expr, BINFO_VTABLE (expr), ref_p);
!   stream_write_tree_edge (ob, expr, BINFO_VPTR_FIELD (expr), ref_p);
  
    /* The number of BINFO_BASE_ACCESSES has already been emitted in
       EXPR's bitfield section.  */
    FOR_EACH_VEC_ELT (tree, BINFO_BASE_ACCESSES (expr), i, t)
!     stream_write_tree_edge (ob, expr, t, ref_p);
  
!   stream_write_tree_edge (ob, expr, BINFO_INHERITANCE_CHAIN (expr), ref_p);
!   stream_write_tree_edge (ob, expr, BINFO_SUBVTT_INDEX (expr), ref_p);
!   stream_write_tree_edge (ob, expr, BINFO_VPTR_INDEX (expr), ref_p);
  }
  
  
*************** write_ts_constructor_tree_pointers (stru
*** 816,823 ****
  
    FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (expr), i, index, value)
      {
!       stream_write_tree (ob, index, ref_p);
!       stream_write_tree (ob, value, ref_p);
      }
  }
  
--- 833,840 ----
  
    FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (expr), i, index, value)
      {
!       stream_write_tree_edge (ob, expr, index, ref_p);
!       stream_write_tree_edge (ob, expr, value, ref_p);
      }
  }
  
Index: trunk/gcc/lto-streamer-out.c
===================================================================
*** trunk.orig/gcc/lto-streamer-out.c	2012-10-15 16:17:56.000000000 +0200
--- trunk/gcc/lto-streamer-out.c	2012-10-16 15:45:32.743237874 +0200
*************** lto_is_streamable (tree expr)
*** 298,318 ****
     where EXPR is stored.  */
  
  static void
! lto_write_tree (struct output_block *ob, tree expr, bool ref_p)
  {
-   struct bitpack_d bp;
- 
-   if (!lto_is_streamable (expr))
-     internal_error ("tree code %qs is not supported in LTO streams",
- 	            tree_code_name[TREE_CODE (expr)]);
- 
-   /* Write the header, containing everything needed to materialize
-      EXPR on the reading side.  */
-   streamer_write_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);
    streamer_pack_tree_bitfields (ob, &bp, expr);
    streamer_write_bitpack (&bp);
  
--- 298,308 ----
     where EXPR is stored.  */
  
  static void
! lto_write_tree_1 (struct output_block *ob, tree expr, bool ref_p)
  {
    /* Pack all the non-pointer fields in EXPR into a bitpack and write
       the resulting bitpack.  */
!   bitpack_d bp = bitpack_create (ob->main_stream);
    streamer_pack_tree_bitfields (ob, &bp, expr);
    streamer_write_bitpack (&bp);
  
*************** lto_write_tree (struct output_block *ob,
*** 343,361 ****
  
        stream_write_tree (ob, initial, ref_p);
      }
  
    /* Mark the end of EXPR.  */
    streamer_write_zero (ob);
  }
  
  
  /* Emit the physical representation of tree node EXPR to output block
     OB.  If THIS_REF_P is true, the leaves of EXPR are emitted as references
     via lto_output_tree_ref.  REF_P is used for streaming siblings of EXPR.  */
  
! void
! lto_output_tree (struct output_block *ob, tree expr,
! 		 bool ref_p, bool this_ref_p)
  {
    unsigned ix;
    bool existed_p;
--- 333,374 ----
  
        stream_write_tree (ob, initial, ref_p);
      }
+ }
+ 
+ /* 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)
+ {
+   if (!lto_is_streamable (expr))
+     internal_error ("tree code %qs is not supported in LTO streams",
+ 	            tree_code_name[TREE_CODE (expr)]);
+ 
+   /* Write the header, containing everything needed to materialize
+      EXPR on the reading side.  */
+   streamer_write_tree_header (ob, expr);
+ 
+   lto_write_tree_1 (ob, expr, ref_p);
  
    /* Mark the end of EXPR.  */
    streamer_write_zero (ob);
  }
  
+ static void
+ null_output_location (struct output_block *, struct bitpack_d *, location_t)
+ {
+ }
  
  /* Emit the physical representation of tree node EXPR to output block
     OB.  If THIS_REF_P is true, the leaves of EXPR are emitted as references
     via lto_output_tree_ref.  REF_P is used for streaming siblings of EXPR.  */
  
! static void
! lto_output_tree_1 (struct output_block *ob, tree, tree expr,
! 		   bool ref_p, bool this_ref_p)
  {
    unsigned ix;
    bool existed_p;
*************** lto_output_tree (struct output_block *ob
*** 408,413 ****
--- 421,633 ----
      }
  }
  
+ struct sccs
+ {
+   unsigned int dfsnum;
+   unsigned int low;
+   bool on_sccstack;
+ };
+ 
+ static unsigned int next_dfs_num;
+ static VEC (tree, heap) *sccstack;
+ static struct pointer_map_t *sccstate;
+ static struct obstack sccstate_obstack;
+ 
+ static void
+ DFS_write_tree (struct output_block *ob, tree from, tree expr,
+ 		bool ref_p, bool this_ref_p)
+ {
+   sccs *state = NULL;
+   unsigned ix;
+   sccs **slot;
+ 
+   /* Handle special cases.  */
+   if (expr == NULL_TREE)
+     return;
+ 
+   /* Do not DFS walk into indexable trees.  */
+   if (this_ref_p && tree_is_indexable (expr))
+     return;
+ 
+   /* Check if we already streamed EXPR.  */
+   if (streamer_tree_cache_lookup (ob->writer_cache, expr, &ix))
+     return;
+ 
+   if (from)
+     state = (sccs *)*pointer_map_contains (sccstate, from);
+ 
+   slot = (sccs **)pointer_map_insert (sccstate, expr);
+   sccs *cstate = *slot;
+   if (!cstate)
+     {
+       /* Not yet visited.  DFS recurse and push it onto the stack.  */
+       *slot = cstate = XOBNEW (&sccstate_obstack, struct sccs);
+       VEC_safe_push (tree, heap, sccstack, expr);
+       cstate->dfsnum = next_dfs_num++;
+       cstate->low = cstate->dfsnum;
+       cstate->on_sccstack = true;
+ 
+       if (streamer_handle_as_builtin_p (expr))
+ 	;
+       else if (TREE_CODE (expr) == INTEGER_CST)
+ 	stream_write_tree_edge (ob, expr, TREE_TYPE (expr), ref_p);
+       else
+ 	streamer_write_tree_body (ob, expr, ref_p);
+ 
+       /* See if we found an SCC.  */
+       if (cstate->low == cstate->dfsnum)
+ 	{
+ 	  unsigned first, size;
+ 	  tree x;
+ 
+ 	  /* Pop the SCC and compute its size.  */
+ 	  first = VEC_length (tree, sccstack);
+ 	  do
+ 	    {
+ 	      x = VEC_index (tree, sccstack, --first);
+ 	      sccs *s = (sccs *)*pointer_map_contains (sccstate, x);
+ 	      s->on_sccstack = false;
+ 	    }
+ 	  while (x != expr);
+ 	  size = VEC_length (tree, sccstack) - first;
+ 
+ 	  streamer_hooks.output_location = lto_output_location;
+ 	  streamer_hooks.write_tree = lto_output_tree_1;
+ 
+ 
+ 	  /* Write LTO_tree_scc.  */
+ 	  streamer_write_record_start (ob, LTO_tree_scc);
+ 	  streamer_write_uhwi (ob, size);
+ 
+ 	  /* Write size-1 SCCs without wrapping them inside SCC bundles.
+ 	     All INTEGER_CSTs need to be handled this way as we need
+ 	     their type to materialize them.  Also builtins are handled
+ 	     this way.
+ 	     ???  We still wrap these in LTO_tree_scc so at the
+ 	     input side we can properly identify the tree we want
+ 	     to ultimatively return.  */
+ 	  if (size == 1)
+ 	    lto_output_tree_1 (ob, NULL_TREE, expr, ref_p, this_ref_p);
+ 	  else
+ 	    {
+ 	      /* Write all headers and populate the streamer cache.  */
+ 	      for (unsigned i = 0; i < size; ++i)
+ 		{
+ 		  x = VEC_index (tree, sccstack, first + i);
+ 		  bool exists_p = streamer_tree_cache_insert (ob->writer_cache, x, &ix);
+ 		  gcc_assert (!exists_p);
+ 
+ 		  if (!lto_is_streamable (x))
+ 		    internal_error ("tree code %qs is not supported in LTO streams",
+ 				    tree_code_name[TREE_CODE (x)]);
+ 
+ 		  if (streamer_handle_as_builtin_p (x))
+ 		    gcc_unreachable ();
+ 
+ 		  /* Write the header, containing everything needed to materialize
+ 		     EXPR on the reading side.  */
+ 		  streamer_write_tree_header (ob, x);
+ 		}
+ 
+ 	      /* Write the bitpacks and tree references.  */
+ 	      for (unsigned i = 0; i < size; ++i)
+ 		{
+ 		  x = VEC_index (tree, sccstack, first + i);
+ 		  lto_write_tree_1 (ob, x, ref_p);
+ 
+ 		  /* Mark the end of X.  */
+ 		  streamer_write_zero (ob);
+ 		}
+ 	    }
+ 
+ 	  streamer_hooks.output_location = null_output_location;
+ 	  streamer_hooks.write_tree = DFS_write_tree;
+ 
+ 	  /* Finally truncate the vector.  */
+ 	  VEC_truncate (tree, sccstack, first);
+ 	}
+ 
+       if (state)
+ 	state->low = MIN (state->low, cstate->low);
+       if (!cstate->on_sccstack)
+ 	return;
+     }
+   gcc_assert (from && state);
+   if (cstate->dfsnum < state->dfsnum
+       && cstate->on_sccstack)
+     state->low = MIN (cstate->dfsnum, state->low);
+ }
+ 
+ /* Emit the physical representation of tree node EXPR to output block
+    OB.  If THIS_REF_P is true, the leaves of EXPR are emitted as references
+    via lto_output_tree_ref.  REF_P is used for streaming siblings of EXPR.  */
+ 
+ void
+ lto_output_tree (struct output_block *ob, tree, tree expr,
+ 		 bool ref_p, bool this_ref_p)
+ {
+   unsigned ix;
+   bool existed_p;
+ 
+   if (expr == NULL_TREE)
+     {
+       streamer_write_record_start (ob, LTO_null);
+       return;
+     }
+ 
+   if (this_ref_p && tree_is_indexable (expr))
+     {
+       lto_output_tree_ref (ob, expr);
+       return;
+     }
+ 
+   /* INTEGER_CST nodes are special because they need their original type
+      to be materialized by the reader (to implement TYPE_CACHED_VALUES).  */
+   if (TREE_CODE (expr) == INTEGER_CST)
+     {
+       streamer_write_integer_cst (ob, expr, ref_p);
+       return;
+     }
+ 
+   existed_p = streamer_tree_cache_lookup (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.  */
+       streamer_write_record_start (ob, LTO_tree_pickle_reference);
+       streamer_write_uhwi (ob, ix);
+       streamer_write_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS,
+ 			   lto_tree_code_to_tag (TREE_CODE (expr)));
+     }
+   else
+     {
+       /* This is the first time we see EXPR, write all reachable
+ 	 trees to OB.  */
+ 
+       streamer_hooks.output_location = null_output_location;
+       streamer_hooks.write_tree = DFS_write_tree;
+       /* Start the DFS walk.  */
+       /* Save ob state ... */
+       /* let's see ... */
+       sccstate = pointer_map_create ();
+       gcc_obstack_init (&sccstate_obstack);
+       sccstack = NULL;
+       next_dfs_num = 1;
+       DFS_write_tree (ob, NULL_TREE, expr, ref_p, this_ref_p);
+       VEC_free (tree, heap, sccstack);
+       pointer_map_destroy (sccstate);
+       obstack_free (&sccstate_obstack, NULL);
+       streamer_hooks.output_location = lto_output_location;
+       streamer_hooks.write_tree = lto_output_tree;
+ 
+       /* Finally append a reference to the tree we were writing.
+ 	 ???  If expr ended up as a singleton we could have
+ 	 inlined it here and avoid outputting a reference.  */
+       lto_output_tree (ob, NULL_TREE, expr, ref_p, this_ref_p);
+     }
+ }
+ 
  
  /* Output to OB a list of try/catch handlers starting with FIRST.  */
  
Index: trunk/gcc/lto-streamer.h
===================================================================
*** trunk.orig/gcc/lto-streamer.h	2012-10-15 16:17:56.000000000 +0200
--- trunk/gcc/lto-streamer.h	2012-10-15 17:49:26.909952828 +0200
*************** enum LTO_tags
*** 193,201 ****
    /* EH try/catch node.  */
    LTO_eh_catch,
  
!   /* Special for global streamer. Reference to previously-streamed node.  */
    LTO_tree_pickle_reference,
  
    /* References to indexable tree nodes.  These objects are stored in
       tables that are written separately from the function bodies that
       reference them.  This way they can be instantiated even when the
--- 193,204 ----
    /* EH try/catch node.  */
    LTO_eh_catch,
  
!   /* Special for global streamer.  Reference to previously-streamed node.  */
    LTO_tree_pickle_reference,
  
+   /* Special for global streamer.  A blob of unnamed tree nodes.  */
+   LTO_tree_scc,
+ 
    /* References to indexable tree nodes.  These objects are stored in
       tables that are written separately from the function bodies that
       reference them.  This way they can be instantiated even when the
*************** tree lto_input_tree (struct lto_input_bl
*** 821,827 ****
  extern void lto_register_decl_definition (tree, struct lto_file_decl_data *);
  extern struct output_block *create_output_block (enum lto_section_type);
  extern void destroy_output_block (struct output_block *);
! extern void lto_output_tree (struct output_block *, tree, bool, bool);
  extern void lto_output_toplevel_asms (void);
  extern void produce_asm (struct output_block *ob, tree fn);
  void lto_output_decl_state_streams (struct output_block *,
--- 824,830 ----
  extern void lto_register_decl_definition (tree, struct lto_file_decl_data *);
  extern struct output_block *create_output_block (enum lto_section_type);
  extern void destroy_output_block (struct output_block *);
! extern void lto_output_tree (struct output_block *, tree, tree, bool, bool);
  extern void lto_output_toplevel_asms (void);
  extern void produce_asm (struct output_block *ob, tree fn);
  void lto_output_decl_state_streams (struct output_block *,
Index: trunk/gcc/lto-streamer-in.c
===================================================================
*** trunk.orig/gcc/lto-streamer-in.c	2012-10-10 16:27:40.000000000 +0200
--- trunk/gcc/lto-streamer-in.c	2012-10-16 15:41:04.930253750 +0200
*************** lto_input_function_body (struct lto_file
*** 1007,1012 ****
--- 1007,1043 ----
  }
  
  
+ /* Read the physical representation of a tree node EXPR from
+    input block IB using the per-file context in DATA_IN.  */
+ 
+ static void
+ lto_read_tree_1 (struct lto_input_block *ib, struct data_in *data_in, tree expr)
+ {
+   /* Read all the bitfield values in EXPR.  Note that for LTO, we
+      only write language-independent bitfields, so no more unpacking is
+      needed.  */
+   streamer_read_tree_bitfields (ib, data_in, expr);
+ 
+   /* Read all the pointer fields in EXPR.  */
+   streamer_read_tree_body (ib, data_in, expr);
+ 
+   /* Read any LTO-specific data not read by the tree streamer.  */
+   if (DECL_P (expr)
+       && TREE_CODE (expr) != FUNCTION_DECL
+       && TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
+     DECL_INITIAL (expr) = stream_read_tree (ib, data_in);
+ 
+   /* We should never try to instantiate an MD or NORMAL builtin here.  */
+   if (TREE_CODE (expr) == FUNCTION_DECL)
+     gcc_assert (!streamer_handle_as_builtin_p (expr));
+ 
+ #ifdef LTO_STREAMER_DEBUG
+   /* Remove the mapping to RESULT's original address set by
+      streamer_alloc_tree.  */
+   lto_orig_address_remove (expr);
+ #endif
+ }
+ 
  /* Read the physical representation of a tree node with tag TAG from
     input block IB using the per-file context in DATA_IN.  */
  
*************** lto_read_tree (struct lto_input_block *i
*** 1022,1053 ****
       structure can be resolved in subsequent calls to stream_read_tree.  */
    streamer_tree_cache_append (data_in->reader_cache, result);
  
!   /* Read all the bitfield values in RESULT.  Note that for LTO, we
!      only write language-independent bitfields, so no more unpacking is
!      needed.  */
!   streamer_read_tree_bitfields (ib, data_in, result);
! 
!   /* Read all the pointer fields in RESULT.  */
!   streamer_read_tree_body (ib, data_in, result);
! 
!   /* Read any LTO-specific data not read by the tree streamer.  */
!   if (DECL_P (result)
!       && TREE_CODE (result) != FUNCTION_DECL
!       && TREE_CODE (result) != TRANSLATION_UNIT_DECL)
!     DECL_INITIAL (result) = stream_read_tree (ib, data_in);
! 
!   /* We should never try to instantiate an MD or NORMAL builtin here.  */
!   if (TREE_CODE (result) == FUNCTION_DECL)
!     gcc_assert (!streamer_handle_as_builtin_p (result));
  
    /* end_marker = */ streamer_read_uchar (ib);
  
- #ifdef LTO_STREAMER_DEBUG
-   /* Remove the mapping to RESULT's original address set by
-      streamer_alloc_tree.  */
-   lto_orig_address_remove (result);
- #endif
- 
    return result;
  }
  
--- 1053,1062 ----
       structure can be resolved in subsequent calls to stream_read_tree.  */
    streamer_tree_cache_append (data_in->reader_cache, result);
  
!   lto_read_tree_1 (ib, data_in, result);
  
    /* end_marker = */ streamer_read_uchar (ib);
  
    return result;
  }
  
*************** lto_input_tree (struct lto_input_block *
*** 1092,1097 ****
--- 1101,1146 ----
  	 words.  */
        result = streamer_read_integer_cst (ib, data_in);
      }
+   else if (tag == LTO_tree_scc)
+     {
+       /* A blob of unnamed tree nodes, fill the cache from it and
+          recurse.  */
+       unsigned HOST_WIDE_INT size = streamer_read_uhwi (ib);
+ 
+       if (size == 1)
+ 	lto_input_tree (ib, data_in);
+       else
+ 	{
+ 	  unsigned int first = VEC_length (tree, data_in->reader_cache->nodes);
+ 	  tree result;
+ 
+ 	  /* Materialize size trees by reading their headers.  */
+ 	  for (unsigned i = 0; i < size; ++i)
+ 	    {
+ 	      tag = streamer_read_record_start (ib);
+ 	      if (tag == LTO_null
+ 		  || (tag >= LTO_field_decl_ref && tag <= LTO_global_decl_ref)
+ 		  || tag == LTO_tree_pickle_reference
+ 		  || tag == LTO_builtin_decl
+ 		  || tag == LTO_tree_scc)
+ 		gcc_unreachable ();
+ 
+ 	      result = streamer_alloc_tree (ib, data_in, tag);
+ 	      streamer_tree_cache_append (data_in->reader_cache, result);
+ 	    }
+ 
+ 	  /* Read the tree bitpacks and references.  */
+ 	  for (unsigned i = 0; i < size; ++i)
+ 	    {
+ 	      result = streamer_tree_cache_get (data_in->reader_cache, first + i);
+ 	      lto_read_tree_1 (ib, data_in, result);
+ 	      /* end_marker = */ streamer_read_uchar (ib);
+ 	    }
+ 	}
+ 
+       /* Recurse.  */
+       return lto_input_tree (ib, data_in);
+     }
    else
      {
        /* Otherwise, materialize a new node from IB.  */
Index: trunk/gcc/lto/lto.c
===================================================================
*** trunk.orig/gcc/lto/lto.c	2012-10-12 12:46:45.000000000 +0200
--- trunk/gcc/lto/lto.c	2012-10-16 15:50:04.656221556 +0200
*************** uniquify_nodes (struct data_in *data_in,
*** 1858,1863 ****
--- 1858,1869 ----
    unsigned len = VEC_length (tree, cache->nodes);
    unsigned i;
  
+   /* ???  INTEGER_CSTs materialized for types in the current chunk
+      of nodes are not yet registered in the respective caches.
+      That's both an advantage (if the type does not prevail)
+      and a disadvantage (if it does we have to duplicate the
+      registering logic).  */
+ 
    /* Go backwards because children streamed for the first time come
       as part of their parents, and hence are created after them.  */
  
Index: trunk/gcc/tree-streamer-in.c
===================================================================
*** trunk.orig/gcc/tree-streamer-in.c	2012-10-15 13:36:11.000000000 +0200
--- trunk/gcc/tree-streamer-in.c	2012-10-16 15:45:05.909239397 +0200
*************** unpack_ts_base_value_fields (struct bitp
*** 140,145 ****
--- 140,156 ----
  }
  
  
+ /* Unpack all the non-pointer fields of the TS_INT_CST structure of
+    expression EXPR from bitpack BP.  */
+ 
+ static void
+ unpack_ts_int_cst_value_fields (struct bitpack_d *bp, tree expr)
+ {
+   TREE_INT_CST_LOW (expr) = (unsigned) bp_unpack_var_len_unsigned (bp);
+   TREE_INT_CST_HIGH (expr) = (unsigned) bp_unpack_var_len_int (bp);
+ }
+ 
+ 
  /* Unpack all the non-pointer fields of the TS_REAL_CST structure of
     expression EXPR from bitpack BP.  */
  
*************** unpack_value_fields (struct data_in *dat
*** 416,421 ****
--- 427,435 ----
       the types and sizes of each of the fields being packed.  */
    unpack_ts_base_value_fields (bp, expr);
  
+   if (CODE_CONTAINS_STRUCT (code, TS_INT_CST))
+     unpack_ts_int_cst_value_fields (bp, expr);
+ 
    if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
      unpack_ts_real_cst_value_fields (bp, expr);
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]