public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH][LTO] Streamer re-org (what's left)
@ 2014-08-07 11:50 Richard Biener
  2014-08-07 13:50 ` Richard Biener
  0 siblings, 1 reply; 7+ messages in thread
From: Richard Biener @ 2014-08-07 11:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jan Hubicka


The following are the non-cleanup parts.  The patch moves us
to compress streams (what data-streamer thinks of "streams")
instead of whole sections.  This enables us to only need
a single compressed and uncompressed block of data "live"
as opposed to a whole section (well, in theory - we still
do mmap based I/O).  The disadvantage is that you really
have to go through the data-streamer interface to access
data at read-in.

As is the patch doesn't improve virtual memory usage a lot
(according to Martins tests) but it increases compile-time
(we now compress LTRANs streams - reducing their size to 1/3).

What the patch still misses is to re-do the string part
of the decl streams to make them compressed again.  It also
misses ripping out the section-compression code entirely
(lto-compress.c).

Oh, and it misses a ChangeLog.

Now the question is whether we want this or not.  It's certainly
not perfect in it's current state.

But I wouldn't want to tie the merge-SCCs-from-disk stuff to
the data-streamer internals too much (even if it seems tempting
and easy in it's current form).

Any comments appreciated.

Thanks,
Richard.


Index: gcc/data-streamer-out.c
===================================================================
*** gcc/data-streamer-out.c.orig	2014-07-31 10:49:00.079737742 +0200
--- gcc/data-streamer-out.c	2014-07-31 12:08:48.364408075 +0200
*************** along with GCC; see the file COPYING3.
*** 22,27 ****
--- 22,32 ----
  
  #include "config.h"
  #include "system.h"
+ /* zlib.h includes other system headers.  Those headers may test feature
+    test macros.  config.h may define feature test macros.  For this reason,
+    zlib.h needs to be included after, rather than before, config.h and
+    system.h.  */
+ #include <zlib.h>
  #include "coretypes.h"
  #include "tree.h"
  #include "basic-block.h"
*************** along with GCC; see the file COPYING3.
*** 33,79 ****
  #include "data-streamer.h"
  
  
  /* Adds a new block to output stream OBS.  */
  
  void
! lto_append_block (struct lto_output_stream *obs)
  {
    struct lto_char_ptr_base *new_block;
  
!   gcc_assert (obs->left_in_block == 0);
  
!   if (obs->first_block == NULL)
      {
!       /* This is the first time the stream has been written
! 	 into.  */
!       obs->block_size = 1024;
!       new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
!       obs->first_block = new_block;
      }
    else
      {
!       struct lto_char_ptr_base *tptr;
!       /* Get a new block that is twice as big as the last block
! 	 and link it into the list.  */
!       obs->block_size *= 2;
!       new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
!       /* The first bytes of the block are reserved as a pointer to
! 	 the next block.  Set the chain of the full block to the
! 	 pointer to the new block.  */
!       tptr = obs->current_block;
!       tptr->ptr = (char *) new_block;
      }
  
    /* Set the place for the next char at the first position after the
       chain to the next block.  */
!   obs->current_pointer
      = ((char *) new_block) + sizeof (struct lto_char_ptr_base);
!   obs->current_block = new_block;
    /* Null out the newly allocated block's pointer to the next block.  */
    new_block->ptr = NULL;
!   obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base);
  }
  
  
  /* 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'.
--- 38,193 ----
  #include "data-streamer.h"
  
  
+ /* Finishes the last block, eventually compressing it, and returns the
+    total size of the stream.  */
+ 
+ unsigned int
+ lto_output_stream::finish ()
+ {
+   if (compress
+       && current_pointer)
+     {
+       /* Compress the last (partial) block.  */
+       compress_current_block (true);
+       left_in_block = zlib_stream->avail_out;
+       free (current_block);
+       current_block = NULL;
+       int status = deflateEnd (zlib_stream);
+       if (status != Z_OK)
+ 	internal_error ("compressed stream: %s", zError (status));
+       free (zlib_stream);
+     }
+   current_pointer = NULL;
+ 
+   unsigned int size = 0;
+   for (lto_char_ptr_base *b = first_block; b; b = (lto_char_ptr_base *)b->ptr)
+     size += block_size - sizeof (lto_char_ptr_base);
+   size -= left_in_block;
+   return size;
+ }
+ 
+ /* Returns a pointer to the first block of the chain of blocks to output.  */
+ 
+ lto_char_ptr_base *
+ lto_output_stream::get_blocks ()
+ {
+   finish ();
+   return first_block;
+ }
+ 
  /* Adds a new block to output stream OBS.  */
  
  void
! lto_output_stream::append_block ()
  {
    struct lto_char_ptr_base *new_block;
  
!   gcc_assert (left_in_block == 0 && block_size > sizeof (lto_char_ptr_base));
  
!   if (first_block == NULL)
      {
!       /* This is the first time the stream has been written into.  */
!       new_block = (struct lto_char_ptr_base*) xmalloc (block_size);
!       first_block = new_block;
      }
    else
      {
!       if (compress)
! 	{
! 	  /* Compress the current block and link it into the list.  */
! 	  compress_current_block (false);
! 	  /* Re-use the uncompressed buffer.  */
! 	  new_block = current_block;
! 	}
!       else
! 	{
! 	  /* Get a new block and link it into the list.  */
! 	  new_block = (struct lto_char_ptr_base*) xmalloc (block_size);
! 	  /* The first bytes of the block are reserved as a pointer to
! 	     the next block.  Set the chain of the full block to the
! 	     pointer to the new block.  */
! 	  lto_char_ptr_base *tptr = current_block;
! 	  tptr->ptr = (char *) new_block;
! 	}
      }
  
    /* Set the place for the next char at the first position after the
       chain to the next block.  */
!   current_pointer
      = ((char *) new_block) + sizeof (struct lto_char_ptr_base);
!   current_block = new_block;
    /* Null out the newly allocated block's pointer to the next block.  */
    new_block->ptr = NULL;
!   left_in_block = block_size - sizeof (struct lto_char_ptr_base);
! }
! 
! /* Return a zlib compression level that zlib will not reject.  Normalizes
!    the compression level from the command line flag, clamping non-default
!    values to the appropriate end of their valid range.  */
! 
! static int
! lto_normalized_zlib_level (void)
! {
!   int level = flag_lto_compression_level;
! 
!   if (level != Z_DEFAULT_COMPRESSION)
!     {
!       if (level < Z_NO_COMPRESSION)
! 	level = Z_NO_COMPRESSION;
!       else if (level > Z_BEST_COMPRESSION)
! 	level = Z_BEST_COMPRESSION;
!     }
! 
!   return level;
  }
  
+ void
+ lto_output_stream::compress_current_block (bool last)
+ {
+   int status;
+ 
+   /* If this is the first block we compress, initialize compression.  */
+   if (first_block == current_block)
+     {
+       zlib_stream = XCNEW (z_stream);
+       zlib_stream->zalloc = NULL;
+       zlib_stream->zfree = NULL;
+       zlib_stream->opaque = NULL;
+       status = deflateInit (zlib_stream, lto_normalized_zlib_level ());
+       if (status != Z_OK)
+ 	internal_error ("compressed stream: %s", zError (status));
+ 
+       current_z_block = first_block
+ 	= (lto_char_ptr_base *) xmalloc (block_size);
+       first_block->ptr = NULL;
+       zlib_stream->next_out = (unsigned char *)first_block + sizeof (lto_char_ptr_base);
+       zlib_stream->avail_out = block_size - sizeof (lto_char_ptr_base);
+     }
+ 
+   zlib_stream->next_in = (unsigned char *)current_block + sizeof (lto_char_ptr_base);
+   zlib_stream->avail_in
+     = block_size - sizeof (lto_char_ptr_base) - left_in_block;
+   do
+     {
+       status = deflate (zlib_stream, last ? Z_FINISH : Z_NO_FLUSH);
+       if (status != Z_OK && status != Z_STREAM_END && status != Z_BUF_ERROR)
+ 	internal_error ("compressed stream: %s", zError (status));
+ 
+       if (status == Z_OK
+ 	  && zlib_stream->avail_out == 0)
+ 	{
+ 	  lto_char_ptr_base *new_block
+ 	      = (lto_char_ptr_base *) xmalloc (block_size);
+ 	  current_z_block->ptr = (char *)new_block;
+ 	  current_z_block = new_block;
+ 	  current_z_block->ptr = NULL;
+ 	  zlib_stream->next_out = (unsigned char *)new_block + sizeof (lto_char_ptr_base);
+ 	  zlib_stream->avail_out = block_size - sizeof (lto_char_ptr_base);
+ 	}
+     }
+   while (zlib_stream->avail_in > 0);
+   gcc_assert (zlib_stream->avail_in == 0);
+ }
  
  /* 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'.
*************** streamer_write_uhwi_stream (struct lto_o
*** 238,244 ****
                              unsigned HOST_WIDE_INT work)
  {
    if (obs->left_in_block == 0)
!     lto_append_block (obs);
    char *current_pointer = obs->current_pointer;
    unsigned int left_in_block = obs->left_in_block;
    unsigned int size = 0;
--- 352,358 ----
                              unsigned HOST_WIDE_INT work)
  {
    if (obs->left_in_block == 0)
!     obs->append_block ();
    char *current_pointer = obs->current_pointer;
    unsigned int left_in_block = obs->left_in_block;
    unsigned int size = 0;
*************** streamer_write_uhwi_stream (struct lto_o
*** 258,264 ****
    if (work != 0)
      {
        obs->left_in_block = 0;
!       lto_append_block (obs);
        current_pointer = obs->current_pointer;
        left_in_block = obs->left_in_block;
        do
--- 372,378 ----
    if (work != 0)
      {
        obs->left_in_block = 0;
!       obs->append_block ();
        current_pointer = obs->current_pointer;
        left_in_block = obs->left_in_block;
        do
*************** void
*** 287,293 ****
  streamer_write_hwi_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
  {
    if (obs->left_in_block == 0)
!     lto_append_block (obs);
    char *current_pointer = obs->current_pointer;
    unsigned int left_in_block = obs->left_in_block;
    unsigned int size = 0;
--- 401,407 ----
  streamer_write_hwi_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
  {
    if (obs->left_in_block == 0)
!     obs->append_block ();
    char *current_pointer = obs->current_pointer;
    unsigned int left_in_block = obs->left_in_block;
    unsigned int size = 0;
*************** streamer_write_hwi_stream (struct lto_ou
*** 313,319 ****
    if (more)
      {
        obs->left_in_block = 0;
!       lto_append_block (obs);
        current_pointer = obs->current_pointer;
        left_in_block = obs->left_in_block;
        do
--- 427,433 ----
    if (more)
      {
        obs->left_in_block = 0;
!       obs->append_block ();
        current_pointer = obs->current_pointer;
        left_in_block = obs->left_in_block;
        do
*************** streamer_write_data_stream (struct lto_o
*** 360,366 ****
  
        /* No space left.  */
        if (obs->left_in_block == 0)
! 	lto_append_block (obs);
  
        /* Determine how many bytes to copy in this loop.  */
        if (len <= obs->left_in_block)
--- 474,480 ----
  
        /* No space left.  */
        if (obs->left_in_block == 0)
! 	obs->append_block ();
  
        /* Determine how many bytes to copy in this loop.  */
        if (len <= obs->left_in_block)
Index: gcc/lto-section-out.c
===================================================================
*** gcc/lto-section-out.c.orig	2014-07-31 10:49:00.079737742 +0200
--- gcc/lto-section-out.c	2014-07-31 12:08:48.364408075 +0200
*************** lto_begin_section (const char *name, boo
*** 80,86 ****
       data is anything other than assembler output.  The effect here is that
       we get compression of IL only in non-ltrans object files.  */
    gcc_assert (compression_stream == NULL);
!   if (compress)
      compression_stream = lto_start_compression (lto_append_data, NULL);
  }
  
--- 80,86 ----
       data is anything other than assembler output.  The effect here is that
       we get compression of IL only in non-ltrans object files.  */
    gcc_assert (compression_stream == NULL);
!   if (compress && 0)
      compression_stream = lto_start_compression (lto_append_data, NULL);
  }
  
*************** lto_write_data (const void *data, unsign
*** 115,130 ****
  void
  lto_write_stream (struct lto_output_stream *obs)
  {
-   unsigned int block_size = 1024;
    struct lto_char_ptr_base *block;
    struct lto_char_ptr_base *next_block;
-   if (!obs->first_block)
-     return;
  
!   for (block = obs->first_block; block; block = next_block)
      {
        const char *base = ((char *)block) + sizeof (struct lto_char_ptr_base);
!       unsigned int num_chars = block_size - sizeof (struct lto_char_ptr_base);
  
        /* If this is not the last block, it is full.  If it is the last
  	 block, left_in_block indicates how many chars are unoccupied in
--- 115,127 ----
  void
  lto_write_stream (struct lto_output_stream *obs)
  {
    struct lto_char_ptr_base *block;
    struct lto_char_ptr_base *next_block;
  
!   for (block = obs->get_blocks (); block; block = next_block)
      {
        const char *base = ((char *)block) + sizeof (struct lto_char_ptr_base);
!       size_t num_chars = obs->block_size - sizeof (struct lto_char_ptr_base);
  
        /* If this is not the last block, it is full.  If it is the last
  	 block, left_in_block indicates how many chars are unoccupied in
*************** lto_write_stream (struct lto_output_stre
*** 142,148 ****
        else
  	lang_hooks.lto.append_data (base, num_chars, block);
        free (block);
-       block_size *= 2;
      }
  }
  
--- 139,144 ----
*************** lto_create_simple_output_block (enum lto
*** 256,263 ****
  
    ob->section_type = section_type;
    ob->decl_state = lto_get_out_decl_state ();
!   ob->main_stream = ((struct lto_output_stream *)
! 		     xcalloc (1, sizeof (struct lto_output_stream)));
  
    return ob;
  }
--- 252,258 ----
  
    ob->section_type = section_type;
    ob->decl_state = lto_get_out_decl_state ();
!   ob->main_stream = new lto_output_stream;
  
    return ob;
  }
*************** lto_destroy_simple_output_block (struct
*** 281,287 ****
    header.lto_header.major_version = LTO_major_version;
    header.lto_header.minor_version = LTO_minor_version;
    header.compressed_size = 0;
!   header.main_size = ob->main_stream->total_size;
    lto_write_data (&header, sizeof header);
  
    lto_write_stream (ob->main_stream);
--- 276,282 ----
    header.lto_header.major_version = LTO_major_version;
    header.lto_header.minor_version = LTO_minor_version;
    header.compressed_size = 0;
!   header.main_size = ob->main_stream->finish ();
    lto_write_data (&header, sizeof header);
  
    lto_write_stream (ob->main_stream);
*************** lto_destroy_simple_output_block (struct
*** 290,296 ****
       writing lto info.  */
    lto_end_section ();
  
!   free (ob->main_stream);
    free (ob);
  }
  
--- 285,291 ----
       writing lto info.  */
    lto_end_section ();
  
!   delete ob->main_stream;
    free (ob);
  }
  
Index: gcc/data-streamer.h
===================================================================
*** gcc/data-streamer.h.orig	2014-07-31 10:49:00.079737742 +0200
--- gcc/data-streamer.h	2014-07-31 12:08:48.386408073 +0200
*************** streamer_write_char_stream (struct lto_o
*** 182,188 ****
  {
    /* No space left.  */
    if (obs->left_in_block == 0)
!     lto_append_block (obs);
  
    /* Write the actual character.  */
    char *current_pointer = obs->current_pointer;
--- 182,188 ----
  {
    /* No space left.  */
    if (obs->left_in_block == 0)
!     obs->append_block ();
  
    /* Write the actual character.  */
    char *current_pointer = obs->current_pointer;
*************** streamer_write_char_stream (struct lto_o
*** 198,206 ****
  static inline unsigned char
  streamer_read_uchar (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
--- 198,210 ----
  static inline unsigned char
  streamer_read_uchar (struct lto_input_block *ib)
  {
!   /* No data left.  */
!   if (ib->left_in_block == 0)
!     ib->append_block ();
! 
!   /* Read a character.  */
!   ib->left_in_block--;
!   return *(ib->current_pointer++);
  }
  
  /* Output VAL into OBS and verify it is in range MIN...MAX that is supposed
Index: gcc/lto-opts.c
===================================================================
*** gcc/lto-opts.c.orig	2014-07-31 10:49:00.079737742 +0200
--- gcc/lto-opts.c	2014-07-31 12:08:48.386408073 +0200
*************** along with GCC; see the file COPYING3.
*** 37,42 ****
--- 37,43 ----
  #include "common/common-target.h"
  #include "diagnostic.h"
  #include "lto-streamer.h"
+ #include "data-streamer.h"
  #include "toplev.h"
  
  /* Append the option piece OPT to the COLLECT_GCC_OPTIONS string
Index: gcc/lto-streamer-out.c
===================================================================
*** gcc/lto-streamer-out.c.orig	2014-07-31 11:18:45.208614838 +0200
--- gcc/lto-streamer-out.c	2014-07-31 12:08:48.388408073 +0200
*************** create_output_block (enum lto_section_ty
*** 79,90 ****
  
    ob->section_type = section_type;
    ob->decl_state = lto_get_out_decl_state ();
!   ob->main_stream = XCNEW (struct lto_output_stream);
!   ob->string_stream = XCNEW (struct lto_output_stream);
    ob->writer_cache = streamer_tree_cache_create (!flag_wpa, true, false);
  
    if (section_type == LTO_section_function_body)
!     ob->cfg_stream = XCNEW (struct lto_output_stream);
  
    clear_line_info (ob);
  
--- 79,92 ----
  
    ob->section_type = section_type;
    ob->decl_state = lto_get_out_decl_state ();
!   ob->main_stream = new lto_output_stream;
!   // The way we use this stream prevents its compression as we basically
!   // perform random access
!   ob->string_stream = new lto_output_stream (2 * 1024 * 1024, false);
    ob->writer_cache = streamer_tree_cache_create (!flag_wpa, true, false);
  
    if (section_type == LTO_section_function_body)
!     ob->cfg_stream = new lto_output_stream;
  
    clear_line_info (ob);
  
*************** destroy_output_block (struct output_bloc
*** 105,114 ****
    delete ob->string_hash_table;
    ob->string_hash_table = NULL;
  
!   free (ob->main_stream);
!   free (ob->string_stream);
    if (section_type == LTO_section_function_body)
!     free (ob->cfg_stream);
  
    streamer_tree_cache_delete (ob->writer_cache);
    obstack_free (&ob->obstack, NULL);
--- 107,116 ----
    delete ob->string_hash_table;
    ob->string_hash_table = NULL;
  
!   delete ob->main_stream;
!   delete ob->string_stream;
    if (section_type == LTO_section_function_body)
!     delete ob->cfg_stream;
  
    streamer_tree_cache_delete (ob->writer_cache);
    obstack_free (&ob->obstack, NULL);
*************** produce_asm (struct output_block *ob, tr
*** 1894,1902 ****
    header.compressed_size = 0;
  
    if (section_type == LTO_section_function_body)
!     header.cfg_size = ob->cfg_stream->total_size;
!   header.main_size = ob->main_stream->total_size;
!   header.string_size = ob->string_stream->total_size;
    lto_write_data (&header, sizeof header);
  
    /* Put all of the gimple and the string table out the asm file as a
--- 1896,1904 ----
    header.compressed_size = 0;
  
    if (section_type == LTO_section_function_body)
!     header.cfg_size = ob->cfg_stream->finish ();
!   header.main_size = ob->main_stream->finish ();
!   header.string_size = ob->string_stream->finish ();
    lto_write_data (&header, sizeof header);
  
    /* Put all of the gimple and the string table out the asm file as a
*************** lto_output_toplevel_asms (void)
*** 2128,2135 ****
    header.lto_header.major_version = LTO_major_version;
    header.lto_header.minor_version = LTO_minor_version;
  
!   header.main_size = ob->main_stream->total_size;
!   header.string_size = ob->string_stream->total_size;
    lto_write_data (&header, sizeof header);
  
    /* Put all of the gimple and the string table out the asm file as a
--- 2130,2137 ----
    header.lto_header.major_version = LTO_major_version;
    header.lto_header.minor_version = LTO_minor_version;
  
!   header.main_size = ob->main_stream->finish ();
!   header.string_size = ob->string_stream->finish ();
    lto_write_data (&header, sizeof header);
  
    /* Put all of the gimple and the string table out the asm file as a
*************** produce_asm_for_decls (void)
*** 2681,2688 ****
      }
    header.decl_state_size = decl_state_size;
  
!   header.main_size = ob->main_stream->total_size;
!   header.string_size = ob->string_stream->total_size;
  
    lto_write_data (&header, sizeof header);
  
--- 2683,2690 ----
      }
    header.decl_state_size = decl_state_size;
  
!   header.main_size = ob->main_stream->finish ();
!   header.string_size = ob->string_stream->finish ();
  
    lto_write_data (&header, sizeof header);
  
Index: gcc/lto-streamer.h
===================================================================
*** gcc/lto-streamer.h.orig	2014-07-31 11:18:03.998617676 +0200
--- gcc/lto-streamer.h	2014-07-31 12:08:48.389408073 +0200
*************** typedef void (lto_free_section_data_f) (
*** 308,333 ****
  					size_t);
  
  /* Structure used as buffer for reading an LTO file.  */
! struct lto_input_block
  {
    const char *data;
    unsigned int p;
    unsigned int len;
  };
  
! #define LTO_INIT_INPUT_BLOCK(BASE,D,P,L)   \
!   do {                                     \
!     BASE.data = D;                         \
!     BASE.p = P;                            \
!     BASE.len = L;                          \
!   } while (0)
! 
! #define LTO_INIT_INPUT_BLOCK_PTR(BASE,D,P,L) \
!   do {                                       \
!     BASE->data = D;                          \
!     BASE->p = P;                             \
!     BASE->len = L;                           \
!   } while (0)
  
  
  /* The is the first part of the record for a function or constructor
--- 308,344 ----
  					size_t);
  
  /* Structure used as buffer for reading an LTO file.  */
! class lto_input_block
  {
+ public:
+   /* Special constructor for the string table, it abuses this to
+      do random access but use the uhwi decoder.  */
+   lto_input_block (const char *data_, unsigned int p_, unsigned int len_)
+       : current_pointer (data_ + p_), left_in_block (len_), compress (false),
+         data (NULL), p (0), len (0) {};
+   lto_input_block (const char *data_, unsigned int len_, bool compress_ = true)
+       : current_pointer (NULL), left_in_block (0), compress (compress_),
+         data (data_), p (0), len (len_), zbuf (NULL), zlib_stream (NULL) {};
+   ~lto_input_block ();
+   void append_block ();
+   inline bool eof ();
+   const char *current_pointer;
+   unsigned int left_in_block;
+ 
+ private:
+   const bool compress;
    const char *data;
    unsigned int p;
    unsigned int len;
+   char *zbuf;
+   struct z_stream_s *zlib_stream;
  };
  
! inline bool
! lto_input_block::eof ()
! {
!   return left_in_block == 0 && len == p;
! }
  
  
  /* The is the first part of the record for a function or constructor
*************** struct lto_char_ptr_base
*** 575,584 ****
     The entire structure should be zeroed when created.  The record
     consists of a set of blocks.  The first sizeof (ptr) bytes are used
     as a chain, and the rest store the bytes to be written.  */
! struct lto_output_stream
  {
!   /* The pointer to the first block in the stream.  */
!   struct lto_char_ptr_base * first_block;
  
    /* The pointer to the last and current block in the stream.  */
    struct lto_char_ptr_base * current_block;
--- 586,608 ----
     The entire structure should be zeroed when created.  The record
     consists of a set of blocks.  The first sizeof (ptr) bytes are used
     as a chain, and the rest store the bytes to be written.  */
! class lto_output_stream
  {
! public:
!   lto_output_stream (size_t block_size_ = 2 * 1024 * 1024,
! 		     bool compress_ = true)
!       : current_block (NULL), current_pointer (NULL),
!         left_in_block (0), block_size (block_size_), total_size (0),
!         first_block (NULL), current_z_block (NULL), compress (compress_),
! 	zlib_stream (NULL)
!   {
!     gcc_assert (block_size > sizeof (lto_char_ptr_base));
!   }
! 
!   unsigned int finish();
!   lto_char_ptr_base *get_blocks ();
! 
!   void append_block ();
  
    /* The pointer to the last and current block in the stream.  */
    struct lto_char_ptr_base * current_block;
*************** struct lto_output_stream
*** 589,599 ****
    /* The number of characters left in the current block.  */
    unsigned int left_in_block;
  
!   /* The block size of the last block allocated.  */
!   unsigned int block_size;
  
!   /* The total number of characters written.  */
    unsigned int total_size;
  };
  
  /* The is the first part of the record in an LTO file for many of the
--- 613,636 ----
    /* The number of characters left in the current block.  */
    unsigned int left_in_block;
  
!   /* The block size to use.  */
!   const unsigned int block_size;
  
!   /* The total number of uncompressed characters written.  */
    unsigned int total_size;
+ 
+ private:
+   void compress_current_block (bool);
+ 
+   /* The pointer to the first block in the stream.  */
+   struct lto_char_ptr_base * first_block;
+ 
+   struct lto_char_ptr_base * current_z_block;
+ 
+   /* Whether to compress this stream.  */
+   const bool compress;
+ 
+   struct z_stream_s *zlib_stream;
  };
  
  /* The is the first part of the record in an LTO file for many of the
*************** extern struct lto_in_decl_state *lto_get
*** 756,762 ****
  				      struct lto_file_decl_data *, tree);
  extern void lto_free_function_in_decl_state (struct lto_in_decl_state *);
  extern void lto_free_function_in_decl_state_for_node (symtab_node *);
- 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;
--- 793,798 ----
*************** extern void lto_push_out_decl_state (str
*** 791,797 ****
  extern struct lto_out_decl_state *lto_pop_out_decl_state (void);
  extern void lto_record_function_out_decl_state (tree,
  						struct lto_out_decl_state *);
- extern void lto_append_block (struct lto_output_stream *);
  
  
  /* In lto-streamer.c.  */
--- 827,832 ----
Index: gcc/lto-section-in.c
===================================================================
*** gcc/lto-section-in.c.orig	2014-07-31 10:49:00.079737742 +0200
--- gcc/lto-section-in.c	2014-07-31 12:08:48.389408073 +0200
*************** lto_get_section_data (struct lto_file_de
*** 153,159 ****
  
    /* FIXME lto: WPA mode does not write compressed sections, so for now
       suppress uncompression if flag_ltrans.  */
!   if (!flag_ltrans)
      {
        /* Create a mapping header containing the underlying data and length,
  	 and prepend this to the uncompression buffer.  The uncompressed data
--- 153,159 ----
  
    /* FIXME lto: WPA mode does not write compressed sections, so for now
       suppress uncompression if flag_ltrans.  */
!   if (!flag_ltrans && 0)
      {
        /* Create a mapping header containing the underlying data and length,
  	 and prepend this to the uncompression buffer.  The uncompressed data
*************** lto_free_section_data (struct lto_file_d
*** 200,206 ****
  
    /* FIXME lto: WPA mode does not write compressed sections, so for now
       suppress uncompression mapping if flag_ltrans.  */
!   if (flag_ltrans)
      {
        (free_section_f) (file_data, section_type, name, data, len);
        return;
--- 200,206 ----
  
    /* FIXME lto: WPA mode does not write compressed sections, so for now
       suppress uncompression mapping if flag_ltrans.  */
!   if (flag_ltrans || 1)
      {
        (free_section_f) (file_data, section_type, name, data, len);
        return;
*************** lto_create_simple_input_block (struct lt
*** 227,245 ****
    const struct lto_simple_header * header
      = (const struct lto_simple_header *) data;
  
-   struct lto_input_block* ib_main;
    int main_offset = sizeof (struct lto_simple_header);
  
    if (!data)
      return NULL;
  
-   ib_main = XNEW (struct lto_input_block);
- 
    *datar = data;
!   LTO_INIT_INPUT_BLOCK_PTR (ib_main, data + main_offset,
! 			    0, header->main_size);
! 
!   return ib_main;
  }
  
  
--- 227,239 ----
    const struct lto_simple_header * header
      = (const struct lto_simple_header *) data;
  
    int main_offset = sizeof (struct lto_simple_header);
  
    if (!data)
      return NULL;
  
    *datar = data;
!   return new lto_input_block (data + main_offset, header->main_size);
  }
  
  
*************** lto_destroy_simple_input_block (struct l
*** 255,261 ****
  				struct lto_input_block *ib,
  				const char *data, size_t len)
  {
!   free (ib);
    lto_free_section_data (file_data, section_type, NULL, data, len);
  }
  
--- 249,255 ----
  				struct lto_input_block *ib,
  				const char *data, size_t len)
  {
!   delete ib;
    lto_free_section_data (file_data, section_type, NULL, data, len);
  }
  
*************** lto_free_function_in_decl_state_for_node
*** 454,468 ****
  }
  
  
- /* Report read pass end of the section.  */
- 
- void
- lto_section_overrun (struct lto_input_block *ib)
- {
-   fatal_error ("bytecode stream: trying to read %d bytes "
- 	       "after the end of the input buffer", ib->p - ib->len);
- }
- 
  /* Report out of range value.  */
  
  void
--- 448,453 ----
Index: gcc/lto-cgraph.c
===================================================================
*** gcc/lto-cgraph.c.orig	2014-07-31 10:49:00.079737742 +0200
--- gcc/lto-cgraph.c	2014-07-31 12:08:48.390408073 +0200
*************** lto_output_node (struct lto_simple_outpu
*** 488,494 ****
      comdat = IDENTIFIER_POINTER (group);
    else
      comdat = "";
!   streamer_write_data_stream (ob->main_stream, comdat, strlen (comdat) + 1);
  
    if (group)
      {
--- 488,495 ----
      comdat = IDENTIFIER_POINTER (group);
    else
      comdat = "";
!   streamer_write_uhwi_stream (ob->main_stream, strlen (comdat));
!   streamer_write_data_stream (ob->main_stream, comdat, strlen (comdat));
  
    if (group)
      {
*************** lto_output_node (struct lto_simple_outpu
*** 546,552 ****
    bp_pack_enum (&bp, ld_plugin_symbol_resolution,
  	        LDPR_NUM_KNOWN, node->resolution);
    streamer_write_bitpack (&bp);
!   streamer_write_data_stream (ob->main_stream, section, strlen (section) + 1);
  
    if (node->thunk.thunk_p && !boundary_p)
      {
--- 547,554 ----
    bp_pack_enum (&bp, ld_plugin_symbol_resolution,
  	        LDPR_NUM_KNOWN, node->resolution);
    streamer_write_bitpack (&bp);
!   streamer_write_uhwi_stream (ob->main_stream, strlen (section));
!   streamer_write_data_stream (ob->main_stream, section, strlen (section));
  
    if (node->thunk.thunk_p && !boundary_p)
      {
*************** lto_output_varpool_node (struct lto_simp
*** 622,628 ****
      comdat = IDENTIFIER_POINTER (group);
    else
      comdat = "";
!   streamer_write_data_stream (ob->main_stream, comdat, strlen (comdat) + 1);
  
    if (group)
      {
--- 624,631 ----
      comdat = IDENTIFIER_POINTER (group);
    else
      comdat = "";
!   streamer_write_uhwi_stream (ob->main_stream, strlen (comdat));
!   streamer_write_data_stream (ob->main_stream, comdat, strlen (comdat));
  
    if (group)
      {
*************** lto_output_varpool_node (struct lto_simp
*** 640,646 ****
    section = node->get_section ();
    if (!section)
      section = "";
!   streamer_write_data_stream (ob->main_stream, section, strlen (section) + 1);
  
    streamer_write_enum (ob->main_stream, ld_plugin_symbol_resolution,
  		       LDPR_NUM_KNOWN, node->resolution);
--- 643,650 ----
    section = node->get_section ();
    if (!section)
      section = "";
!   streamer_write_uhwi_stream (ob->main_stream, strlen (section));
!   streamer_write_data_stream (ob->main_stream, section, strlen (section));
  
    streamer_write_enum (ob->main_stream, ld_plugin_symbol_resolution,
  		       LDPR_NUM_KNOWN, node->resolution);
*************** output_symtab (void)
*** 994,1012 ****
  static tree
  read_identifier (struct lto_input_block *ib)
  {
!   unsigned int len = strnlen (ib->data + ib->p, ib->len - ib->p - 1);
!   tree id;
! 
!   if (ib->data[ib->p + len])
!     lto_section_overrun (ib);
    if (!len)
!     {
!       ib->p++;
!       return NULL;
!     }
!   id = get_identifier (ib->data + ib->p);
!   ib->p += len + 1;
!   return id;
  }
  
  /* Return string encoded in IB, NULL if string is empty.  */
--- 998,1011 ----
  static tree
  read_identifier (struct lto_input_block *ib)
  {
!   unsigned int len = streamer_read_uhwi (ib);
    if (!len)
!     return NULL;
!   char *str = XALLOCAVEC (char, len + 1);
!   for (unsigned i = 0; i < len; ++i)
!     str[i] = streamer_read_uchar (ib);
!   str[len] = '\0';
!   return get_identifier (str);
  }
  
  /* Return string encoded in IB, NULL if string is empty.  */
*************** read_identifier (struct lto_input_block
*** 1014,1031 ****
  static const char *
  read_string (struct lto_input_block *ib)
  {
!   unsigned int len = strnlen (ib->data + ib->p, ib->len - ib->p - 1);
!   const char *str;
! 
!   if (ib->data[ib->p + len])
!     lto_section_overrun (ib);
    if (!len)
!     {
!       ib->p++;
!       return NULL;
!     }
!   str = ib->data + ib->p;
!   ib->p += len + 1;
    return str;
  }
  
--- 1013,1025 ----
  static const char *
  read_string (struct lto_input_block *ib)
  {
!   unsigned int len = streamer_read_uhwi (ib);
    if (!len)
!     return NULL;
!   char *str = (char *)xmalloc (len + 1);
!   for (unsigned i = 0; i < len; ++i)
!     str[i] = streamer_read_uchar (ib);
!   str[len] = '\0';
    return str;
  }
  
*************** input_cgraph_opt_section (struct lto_fil
*** 1902,1913 ****
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
-   struct lto_input_block ib_main;
    unsigned int i;
    unsigned int count;
  
!   LTO_INIT_INPUT_BLOCK (ib_main, (const char *) data + main_offset, 0,
! 			header->main_size);
  
    data_in =
      lto_data_in_create (file_data, (const char *) data + string_offset,
--- 1896,1906 ----
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
    unsigned int i;
    unsigned int count;
  
!   lto_input_block ib_main ((const char *) data + main_offset,
! 			   header->main_size);
  
    data_in =
      lto_data_in_create (file_data, (const char *) data + string_offset,
Index: gcc/data-streamer-in.c
===================================================================
*** gcc/data-streamer-in.c.orig	2014-07-31 10:49:00.079737742 +0200
--- gcc/data-streamer-in.c	2014-07-31 12:08:48.391408073 +0200
*************** along with GCC; see the file COPYING3.
*** 22,27 ****
--- 22,32 ----
  
  #include "config.h"
  #include "system.h"
+ /* zlib.h includes other system headers.  Those headers may test feature
+    test macros.  config.h may define feature test macros.  For this reason,
+    zlib.h needs to be included after, rather than before, config.h and
+    system.h.  */
+ #include <zlib.h>
  #include "coretypes.h"
  #include "diagnostic.h"
  #include "tree.h"
*************** along with GCC; see the file COPYING3.
*** 33,45 ****
  #include "gimple.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;
  
--- 38,107 ----
  #include "gimple.h"
  #include "data-streamer.h"
  
+ 
+ void
+ lto_input_block::append_block ()
+ {
+   gcc_assert (left_in_block == 0 && data);
+   if (!compress)
+     {
+       current_pointer = data + p;
+       left_in_block = MIN (4096, len - p);
+       p += left_in_block;
+     }
+   else
+     {
+       int status;
+ 
+       if (!zlib_stream)
+ 	{
+ 	  zlib_stream = XCNEW (z_stream);
+ 	  zlib_stream->zalloc = NULL;
+ 	  zlib_stream->zfree = NULL;
+ 	  zlib_stream->opaque = NULL;
+ 	  zlib_stream->avail_in = len;
+ 	  zlib_stream->next_in = (Bytef*)const_cast<char *>(data + p);
+ 	  status = inflateInit (zlib_stream);
+ 	  if (status != Z_OK)
+ 	    internal_error ("compressed stream: %s", zError (status));
+ 	  zbuf = XNEWVEC (char, 2 * 1024 * 1024);
+ 	}
+ 
+       zlib_stream->avail_out = 2 * 1024 * 1024;
+       zlib_stream->next_out = (Bytef*)zbuf;
+       status = inflate (zlib_stream, Z_NO_FLUSH);
+       if (status != Z_OK && status != Z_STREAM_END)
+ 	internal_error ("compressed stream: %s", zError (status));
+ 
+       current_pointer = zbuf;
+       left_in_block = 2 * 1024 * 1024 - zlib_stream->avail_out;
+       p = len - zlib_stream->avail_in;
+     }
+   if (left_in_block == 0)
+     fatal_error ("bytecode stream: trying to read bytes "
+ 		 "after the end of the input buffer");
+ }
+ 
+ lto_input_block::~lto_input_block ()
+ {
+   if (compress)
+     {
+       if (zlib_stream)
+ 	{
+ 	  inflateEnd (zlib_stream);
+ 	  free (zlib_stream);
+ 	}
+       if (zbuf)
+ 	free (zbuf);
+     }
+ }
+ 
  /* 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)
  {
    unsigned int len;
    const char *result;
  
*************** string_for_index (struct data_in *data_i
*** 50,64 ****
      }
  
    /* 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 = streamer_read_uhwi (&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;
  }
--- 112,126 ----
      }
  
    /* Get the string stored at location LOC in DATA_IN->STRINGS.  */
!   lto_input_block str_tab (data_in->strings, loc - 1,
! 			   data_in->strings_len - (loc - 1));
    len = streamer_read_uhwi (&str_tab);
    *rlen = len;
  
!   if (str_tab.left_in_block < len)
      internal_error ("bytecode stream: string too long for the string table");
  
!   result = str_tab.current_pointer;
  
    return result;
  }
*************** bp_unpack_string (struct data_in *data_i
*** 127,158 ****
  unsigned HOST_WIDE_INT
  streamer_read_uhwi (struct lto_input_block *ib)
  {
!   unsigned HOST_WIDE_INT result;
!   int shift;
!   unsigned HOST_WIDE_INT byte;
!   unsigned int p = ib->p;
!   unsigned int len = ib->len;
! 
!   const char *data = ib->data;
!   result = data[p++];
    if ((result & 0x80) != 0)
      {
        result &= 0x7f;
        shift = 7;
        do
  	{
! 	  byte = data[p++];
  	  result |= (byte & 0x7f) << shift;
  	  shift += 7;
  	}
        while ((byte & 0x80) != 0);
      }
  
-   /* We check for section overrun after the fact for performance reason.  */
-   if (p > len)
-     lto_section_overrun (ib);
- 
-   ib->p = p;
    return result;
  }
  
--- 189,210 ----
  unsigned HOST_WIDE_INT
  streamer_read_uhwi (struct lto_input_block *ib)
  {
!   unsigned HOST_WIDE_INT result = streamer_read_uchar (ib);
    if ((result & 0x80) != 0)
      {
+       unsigned HOST_WIDE_INT byte;
+       int shift;
        result &= 0x7f;
        shift = 7;
        do
  	{
! 	  byte = streamer_read_uchar (ib);
  	  result |= (byte & 0x7f) << shift;
  	  shift += 7;
  	}
        while ((byte & 0x80) != 0);
      }
  
    return result;
  }
  
Index: gcc/ipa-inline-analysis.c
===================================================================
*** gcc/ipa-inline-analysis.c.orig	2014-07-31 10:49:00.079737742 +0200
--- gcc/ipa-inline-analysis.c	2014-07-31 12:08:48.392408073 +0200
*************** inline_read_section (struct lto_file_dec
*** 4086,4097 ****
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
-   struct lto_input_block ib;
    unsigned int i, count2, j;
    unsigned int f_count;
  
!   LTO_INIT_INPUT_BLOCK (ib, (const char *) data + main_offset, 0,
! 			header->main_size);
  
    data_in =
      lto_data_in_create (file_data, (const char *) data + string_offset,
--- 4086,4095 ----
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
    unsigned int i, count2, j;
    unsigned int f_count;
  
!   lto_input_block ib ((const char *) data + main_offset, header->main_size);
  
    data_in =
      lto_data_in_create (file_data, (const char *) data + string_offset,
Index: gcc/ipa-prop.c
===================================================================
*** gcc/ipa-prop.c.orig	2014-07-31 10:49:00.079737742 +0200
--- gcc/ipa-prop.c	2014-07-31 12:08:48.394408073 +0200
*************** ipa_prop_read_section (struct lto_file_d
*** 4895,4906 ****
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
-   struct lto_input_block ib_main;
    unsigned int i;
    unsigned int count;
  
!   LTO_INIT_INPUT_BLOCK (ib_main, (const char *) data + main_offset, 0,
! 			header->main_size);
  
    data_in =
      lto_data_in_create (file_data, (const char *) data + string_offset,
--- 4895,4905 ----
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
    unsigned int i;
    unsigned int count;
  
!   lto_input_block ib_main ((const char *) data + main_offset,
! 			   header->main_size);
  
    data_in =
      lto_data_in_create (file_data, (const char *) data + string_offset,
*************** read_replacements_section (struct lto_fi
*** 5073,5084 ****
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
-   struct lto_input_block ib_main;
    unsigned int i;
    unsigned int count;
  
!   LTO_INIT_INPUT_BLOCK (ib_main, (const char *) data + main_offset, 0,
! 			header->main_size);
  
    data_in = lto_data_in_create (file_data, (const char *) data + string_offset,
  				header->string_size, vNULL);
--- 5072,5082 ----
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
    unsigned int i;
    unsigned int count;
  
!   lto_input_block ib_main ((const char *) data + main_offset,
! 			   header->main_size);
  
    data_in = lto_data_in_create (file_data, (const char *) data + string_offset,
  				header->string_size, vNULL);
Index: gcc/lto-streamer-in.c
===================================================================
*** gcc/lto-streamer-in.c.orig	2014-07-31 10:49:30.181735670 +0200
--- gcc/lto-streamer-in.c	2014-07-31 12:08:48.395408073 +0200
*************** lto_read_body_or_constructor (struct lto
*** 1054,1061 ****
    int cfg_offset;
    int main_offset;
    int string_offset;
-   struct lto_input_block ib_cfg;
-   struct lto_input_block ib_main;
    tree fn_decl = node->decl;
  
    header = (const struct lto_function_header *) data;
--- 1054,1059 ----
*************** lto_read_body_or_constructor (struct lto
*** 1064,1089 ****
        cfg_offset = sizeof (struct lto_function_header);
        main_offset = cfg_offset + header->cfg_size;
        string_offset = main_offset + header->main_size;
- 
-       LTO_INIT_INPUT_BLOCK (ib_cfg,
- 			    data + cfg_offset,
- 			    0,
- 			    header->cfg_size);
- 
-       LTO_INIT_INPUT_BLOCK (ib_main,
- 			    data + main_offset,
- 			    0,
- 			    header->main_size);
      }
    else
      {
        main_offset = sizeof (struct lto_function_header);
        string_offset = main_offset + header->main_size;
- 
-       LTO_INIT_INPUT_BLOCK (ib_main,
- 			    data + main_offset,
- 			    0,
- 			    header->main_size);
      }
  
    data_in = lto_data_in_create (file_data, data + string_offset,
--- 1062,1072 ----
*************** lto_read_body_or_constructor (struct lto
*** 1104,1111 ****
  
        /* Set up the struct function.  */
        from = data_in->reader_cache->nodes.length ();
        if (TREE_CODE (node->decl) == FUNCTION_DECL)
!         input_function (fn_decl, data_in, &ib_main, &ib_cfg);
        else
          input_constructor (fn_decl, data_in, &ib_main);
        /* And fixup types we streamed locally.  */
--- 1087,1098 ----
  
        /* Set up the struct function.  */
        from = data_in->reader_cache->nodes.length ();
+       lto_input_block ib_main (data + main_offset, header->main_size);
        if (TREE_CODE (node->decl) == FUNCTION_DECL)
! 	{
! 	  lto_input_block ib_cfg (data + cfg_offset, header->cfg_size);
! 	  input_function (fn_decl, data_in, &ib_main, &ib_cfg);
! 	}
        else
          input_constructor (fn_decl, data_in, &ib_main);
        /* And fixup types we streamed locally.  */
*************** lto_input_toplevel_asms (struct lto_file
*** 1360,1366 ****
    const struct lto_asm_header *header = (const struct lto_asm_header *) data;
    int string_offset;
    struct data_in *data_in;
-   struct lto_input_block ib;
    tree str;
  
    if (! data)
--- 1347,1352 ----
*************** lto_input_toplevel_asms (struct lto_file
*** 1368,1377 ****
  
    string_offset = sizeof (*header) + header->main_size;
  
!   LTO_INIT_INPUT_BLOCK (ib,
! 			data + sizeof (*header),
! 			0,
! 			header->main_size);
  
    data_in = lto_data_in_create (file_data, data + string_offset,
  			      header->string_size, vNULL);
--- 1354,1360 ----
  
    string_offset = sizeof (*header) + header->main_size;
  
!   lto_input_block ib (data + sizeof (*header), header->main_size);
  
    data_in = lto_data_in_create (file_data, data + string_offset,
  			      header->string_size, vNULL);
Index: gcc/lto/lto.c
===================================================================
*** gcc/lto/lto.c.orig	2014-07-31 10:49:00.079737742 +0200
--- gcc/lto/lto.c	2014-07-31 12:08:48.396408073 +0200
*************** lto_read_decls (struct lto_file_decl_dat
*** 1843,1856 ****
    const int decl_offset = sizeof (struct lto_decl_header);
    const int main_offset = decl_offset + header->decl_state_size;
    const int string_offset = main_offset + header->main_size;
-   struct lto_input_block ib_main;
    struct data_in *data_in;
    unsigned int i;
    const uint32_t *data_ptr, *data_end;
    uint32_t num_decl_states;
  
!   LTO_INIT_INPUT_BLOCK (ib_main, (const char *) data + main_offset, 0,
! 			header->main_size);
  
    data_in = lto_data_in_create (decl_data, (const char *) data + string_offset,
  				header->string_size, resolutions);
--- 1843,1855 ----
    const int decl_offset = sizeof (struct lto_decl_header);
    const int main_offset = decl_offset + header->decl_state_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
    unsigned int i;
    const uint32_t *data_ptr, *data_end;
    uint32_t num_decl_states;
  
!   lto_input_block ib_main ((const char *) data + main_offset,
! 			   header->main_size);
  
    data_in = lto_data_in_create (decl_data, (const char *) data + string_offset,
  				header->string_size, resolutions);
*************** lto_read_decls (struct lto_file_decl_dat
*** 1859,1865 ****
       internal types that should not be merged.  */
  
    /* Read the global declarations and types.  */
!   while (ib_main.p < ib_main.len)
      {
        tree t;
        unsigned from = data_in->reader_cache->nodes.length ();
--- 1858,1864 ----
       internal types that should not be merged.  */
  
    /* Read the global declarations and types.  */
!   while (!ib_main.eof ())
      {
        tree t;
        unsigned from = data_in->reader_cache->nodes.length ();

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

* Re: [PATCH][LTO] Streamer re-org (what's left)
  2014-08-07 11:50 [PATCH][LTO] Streamer re-org (what's left) Richard Biener
@ 2014-08-07 13:50 ` Richard Biener
  2014-08-11  9:11   ` Richard Biener
  0 siblings, 1 reply; 7+ messages in thread
From: Richard Biener @ 2014-08-07 13:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jan Hubicka

On Thu, 7 Aug 2014, Richard Biener wrote:

> 
> The following are the non-cleanup parts.  The patch moves us
> to compress streams (what data-streamer thinks of "streams")
> instead of whole sections.  This enables us to only need
> a single compressed and uncompressed block of data "live"
> as opposed to a whole section (well, in theory - we still
> do mmap based I/O).  The disadvantage is that you really
> have to go through the data-streamer interface to access
> data at read-in.
> 
> As is the patch doesn't improve virtual memory usage a lot
> (according to Martins tests) but it increases compile-time
> (we now compress LTRANs streams - reducing their size to 1/3).
> 
> What the patch still misses is to re-do the string part
> of the decl streams to make them compressed again.  It also
> misses ripping out the section-compression code entirely
> (lto-compress.c).
> 
> Oh, and it misses a ChangeLog.
> 
> Now the question is whether we want this or not.  It's certainly
> not perfect in it's current state.
> 
> But I wouldn't want to tie the merge-SCCs-from-disk stuff to
> the data-streamer internals too much (even if it seems tempting
> and easy in it's current form).
> 
> Any comments appreciated.

The following is the update I promised on IRC.  It fixes a
small memory leak from read_string () and should restore
performance of streamer_read_uhwi.

Richard.


Index: gcc/data-streamer-out.c
===================================================================
*** gcc/data-streamer-out.c.orig	2014-08-07 13:47:46.007359525 +0200
--- gcc/data-streamer-out.c	2014-08-07 15:21:50.153970932 +0200
*************** along with GCC; see the file COPYING3.
*** 22,27 ****
--- 22,32 ----
  
  #include "config.h"
  #include "system.h"
+ /* zlib.h includes other system headers.  Those headers may test feature
+    test macros.  config.h may define feature test macros.  For this reason,
+    zlib.h needs to be included after, rather than before, config.h and
+    system.h.  */
+ #include <zlib.h>
  #include "coretypes.h"
  #include "tree.h"
  #include "basic-block.h"
*************** along with GCC; see the file COPYING3.
*** 33,79 ****
  #include "data-streamer.h"
  
  
  /* Adds a new block to output stream OBS.  */
  
  void
! lto_append_block (struct lto_output_stream *obs)
  {
    struct lto_char_ptr_base *new_block;
  
!   gcc_assert (obs->left_in_block == 0);
  
!   if (obs->first_block == NULL)
      {
!       /* This is the first time the stream has been written
! 	 into.  */
!       obs->block_size = 1024;
!       new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
!       obs->first_block = new_block;
      }
    else
      {
!       struct lto_char_ptr_base *tptr;
!       /* Get a new block that is twice as big as the last block
! 	 and link it into the list.  */
!       obs->block_size *= 2;
!       new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
!       /* The first bytes of the block are reserved as a pointer to
! 	 the next block.  Set the chain of the full block to the
! 	 pointer to the new block.  */
!       tptr = obs->current_block;
!       tptr->ptr = (char *) new_block;
      }
  
    /* Set the place for the next char at the first position after the
       chain to the next block.  */
!   obs->current_pointer
      = ((char *) new_block) + sizeof (struct lto_char_ptr_base);
!   obs->current_block = new_block;
    /* Null out the newly allocated block's pointer to the next block.  */
    new_block->ptr = NULL;
!   obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base);
  }
  
  
  /* 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'.
--- 38,193 ----
  #include "data-streamer.h"
  
  
+ /* Finishes the last block, eventually compressing it, and returns the
+    total size of the stream.  */
+ 
+ unsigned int
+ lto_output_stream::finish ()
+ {
+   if (compress
+       && current_pointer)
+     {
+       /* Compress the last (partial) block.  */
+       compress_current_block (true);
+       left_in_block = zlib_stream->avail_out;
+       free (current_block);
+       current_block = NULL;
+       int status = deflateEnd (zlib_stream);
+       if (status != Z_OK)
+ 	internal_error ("compressed stream: %s", zError (status));
+       free (zlib_stream);
+     }
+   current_pointer = NULL;
+ 
+   unsigned int size = 0;
+   for (lto_char_ptr_base *b = first_block; b; b = (lto_char_ptr_base *)b->ptr)
+     size += block_size - sizeof (lto_char_ptr_base);
+   size -= left_in_block;
+   return size;
+ }
+ 
+ /* Returns a pointer to the first block of the chain of blocks to output.  */
+ 
+ lto_char_ptr_base *
+ lto_output_stream::get_blocks ()
+ {
+   finish ();
+   return first_block;
+ }
+ 
  /* Adds a new block to output stream OBS.  */
  
  void
! lto_output_stream::append_block ()
  {
    struct lto_char_ptr_base *new_block;
  
!   gcc_assert (left_in_block == 0 && block_size > sizeof (lto_char_ptr_base));
  
!   if (first_block == NULL)
      {
!       /* This is the first time the stream has been written into.  */
!       new_block = (struct lto_char_ptr_base*) xmalloc (block_size);
!       first_block = new_block;
      }
    else
      {
!       if (compress)
! 	{
! 	  /* Compress the current block and link it into the list.  */
! 	  compress_current_block (false);
! 	  /* Re-use the uncompressed buffer.  */
! 	  new_block = current_block;
! 	}
!       else
! 	{
! 	  /* Get a new block and link it into the list.  */
! 	  new_block = (struct lto_char_ptr_base*) xmalloc (block_size);
! 	  /* The first bytes of the block are reserved as a pointer to
! 	     the next block.  Set the chain of the full block to the
! 	     pointer to the new block.  */
! 	  lto_char_ptr_base *tptr = current_block;
! 	  tptr->ptr = (char *) new_block;
! 	}
      }
  
    /* Set the place for the next char at the first position after the
       chain to the next block.  */
!   current_pointer
      = ((char *) new_block) + sizeof (struct lto_char_ptr_base);
!   current_block = new_block;
    /* Null out the newly allocated block's pointer to the next block.  */
    new_block->ptr = NULL;
!   left_in_block = block_size - sizeof (struct lto_char_ptr_base);
! }
! 
! /* Return a zlib compression level that zlib will not reject.  Normalizes
!    the compression level from the command line flag, clamping non-default
!    values to the appropriate end of their valid range.  */
! 
! static int
! lto_normalized_zlib_level (void)
! {
!   int level = flag_lto_compression_level;
! 
!   if (level != Z_DEFAULT_COMPRESSION)
!     {
!       if (level < Z_NO_COMPRESSION)
! 	level = Z_NO_COMPRESSION;
!       else if (level > Z_BEST_COMPRESSION)
! 	level = Z_BEST_COMPRESSION;
!     }
! 
!   return level;
  }
  
+ void
+ lto_output_stream::compress_current_block (bool last)
+ {
+   int status;
+ 
+   /* If this is the first block we compress, initialize compression.  */
+   if (first_block == current_block)
+     {
+       zlib_stream = XCNEW (z_stream);
+       zlib_stream->zalloc = NULL;
+       zlib_stream->zfree = NULL;
+       zlib_stream->opaque = NULL;
+       status = deflateInit (zlib_stream, lto_normalized_zlib_level ());
+       if (status != Z_OK)
+ 	internal_error ("compressed stream: %s", zError (status));
+ 
+       current_z_block = first_block
+ 	= (lto_char_ptr_base *) xmalloc (block_size);
+       first_block->ptr = NULL;
+       zlib_stream->next_out = (unsigned char *)first_block + sizeof (lto_char_ptr_base);
+       zlib_stream->avail_out = block_size - sizeof (lto_char_ptr_base);
+     }
+ 
+   zlib_stream->next_in = (unsigned char *)current_block + sizeof (lto_char_ptr_base);
+   zlib_stream->avail_in
+     = block_size - sizeof (lto_char_ptr_base) - left_in_block;
+   do
+     {
+       status = deflate (zlib_stream, last ? Z_FINISH : Z_NO_FLUSH);
+       if (status != Z_OK && status != Z_STREAM_END && status != Z_BUF_ERROR)
+ 	internal_error ("compressed stream: %s", zError (status));
+ 
+       if (status == Z_OK
+ 	  && zlib_stream->avail_out == 0)
+ 	{
+ 	  lto_char_ptr_base *new_block
+ 	      = (lto_char_ptr_base *) xmalloc (block_size);
+ 	  current_z_block->ptr = (char *)new_block;
+ 	  current_z_block = new_block;
+ 	  current_z_block->ptr = NULL;
+ 	  zlib_stream->next_out = (unsigned char *)new_block + sizeof (lto_char_ptr_base);
+ 	  zlib_stream->avail_out = block_size - sizeof (lto_char_ptr_base);
+ 	}
+     }
+   while (zlib_stream->avail_in > 0);
+   gcc_assert (zlib_stream->avail_in == 0);
+ }
  
  /* 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'.
*************** streamer_write_uhwi_stream (struct lto_o
*** 238,244 ****
                              unsigned HOST_WIDE_INT work)
  {
    if (obs->left_in_block == 0)
!     lto_append_block (obs);
    char *current_pointer = obs->current_pointer;
    unsigned int left_in_block = obs->left_in_block;
    unsigned int size = 0;
--- 352,358 ----
                              unsigned HOST_WIDE_INT work)
  {
    if (obs->left_in_block == 0)
!     obs->append_block ();
    char *current_pointer = obs->current_pointer;
    unsigned int left_in_block = obs->left_in_block;
    unsigned int size = 0;
*************** streamer_write_uhwi_stream (struct lto_o
*** 258,264 ****
    if (work != 0)
      {
        obs->left_in_block = 0;
!       lto_append_block (obs);
        current_pointer = obs->current_pointer;
        left_in_block = obs->left_in_block;
        do
--- 372,378 ----
    if (work != 0)
      {
        obs->left_in_block = 0;
!       obs->append_block ();
        current_pointer = obs->current_pointer;
        left_in_block = obs->left_in_block;
        do
*************** void
*** 287,293 ****
  streamer_write_hwi_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
  {
    if (obs->left_in_block == 0)
!     lto_append_block (obs);
    char *current_pointer = obs->current_pointer;
    unsigned int left_in_block = obs->left_in_block;
    unsigned int size = 0;
--- 401,407 ----
  streamer_write_hwi_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
  {
    if (obs->left_in_block == 0)
!     obs->append_block ();
    char *current_pointer = obs->current_pointer;
    unsigned int left_in_block = obs->left_in_block;
    unsigned int size = 0;
*************** streamer_write_hwi_stream (struct lto_ou
*** 313,319 ****
    if (more)
      {
        obs->left_in_block = 0;
!       lto_append_block (obs);
        current_pointer = obs->current_pointer;
        left_in_block = obs->left_in_block;
        do
--- 427,433 ----
    if (more)
      {
        obs->left_in_block = 0;
!       obs->append_block ();
        current_pointer = obs->current_pointer;
        left_in_block = obs->left_in_block;
        do
*************** streamer_write_data_stream (struct lto_o
*** 360,366 ****
  
        /* No space left.  */
        if (obs->left_in_block == 0)
! 	lto_append_block (obs);
  
        /* Determine how many bytes to copy in this loop.  */
        if (len <= obs->left_in_block)
--- 474,480 ----
  
        /* No space left.  */
        if (obs->left_in_block == 0)
! 	obs->append_block ();
  
        /* Determine how many bytes to copy in this loop.  */
        if (len <= obs->left_in_block)
Index: gcc/lto-section-out.c
===================================================================
*** gcc/lto-section-out.c.orig	2014-08-07 13:47:46.007359525 +0200
--- gcc/lto-section-out.c	2014-08-07 15:21:50.153970932 +0200
*************** lto_begin_section (const char *name, boo
*** 80,86 ****
       data is anything other than assembler output.  The effect here is that
       we get compression of IL only in non-ltrans object files.  */
    gcc_assert (compression_stream == NULL);
!   if (compress)
      compression_stream = lto_start_compression (lto_append_data, NULL);
  }
  
--- 80,86 ----
       data is anything other than assembler output.  The effect here is that
       we get compression of IL only in non-ltrans object files.  */
    gcc_assert (compression_stream == NULL);
!   if (compress && 0)
      compression_stream = lto_start_compression (lto_append_data, NULL);
  }
  
*************** lto_write_data (const void *data, unsign
*** 115,130 ****
  void
  lto_write_stream (struct lto_output_stream *obs)
  {
-   unsigned int block_size = 1024;
    struct lto_char_ptr_base *block;
    struct lto_char_ptr_base *next_block;
-   if (!obs->first_block)
-     return;
  
!   for (block = obs->first_block; block; block = next_block)
      {
        const char *base = ((char *)block) + sizeof (struct lto_char_ptr_base);
!       unsigned int num_chars = block_size - sizeof (struct lto_char_ptr_base);
  
        /* If this is not the last block, it is full.  If it is the last
  	 block, left_in_block indicates how many chars are unoccupied in
--- 115,127 ----
  void
  lto_write_stream (struct lto_output_stream *obs)
  {
    struct lto_char_ptr_base *block;
    struct lto_char_ptr_base *next_block;
  
!   for (block = obs->get_blocks (); block; block = next_block)
      {
        const char *base = ((char *)block) + sizeof (struct lto_char_ptr_base);
!       size_t num_chars = obs->block_size - sizeof (struct lto_char_ptr_base);
  
        /* If this is not the last block, it is full.  If it is the last
  	 block, left_in_block indicates how many chars are unoccupied in
*************** lto_write_stream (struct lto_output_stre
*** 142,148 ****
        else
  	lang_hooks.lto.append_data (base, num_chars, block);
        free (block);
-       block_size *= 2;
      }
  }
  
--- 139,144 ----
*************** lto_create_simple_output_block (enum lto
*** 256,263 ****
  
    ob->section_type = section_type;
    ob->decl_state = lto_get_out_decl_state ();
!   ob->main_stream = ((struct lto_output_stream *)
! 		     xcalloc (1, sizeof (struct lto_output_stream)));
  
    return ob;
  }
--- 252,258 ----
  
    ob->section_type = section_type;
    ob->decl_state = lto_get_out_decl_state ();
!   ob->main_stream = new lto_output_stream;
  
    return ob;
  }
*************** lto_destroy_simple_output_block (struct
*** 281,287 ****
    header.lto_header.major_version = LTO_major_version;
    header.lto_header.minor_version = LTO_minor_version;
    header.compressed_size = 0;
!   header.main_size = ob->main_stream->total_size;
    lto_write_data (&header, sizeof header);
  
    lto_write_stream (ob->main_stream);
--- 276,282 ----
    header.lto_header.major_version = LTO_major_version;
    header.lto_header.minor_version = LTO_minor_version;
    header.compressed_size = 0;
!   header.main_size = ob->main_stream->finish ();
    lto_write_data (&header, sizeof header);
  
    lto_write_stream (ob->main_stream);
*************** lto_destroy_simple_output_block (struct
*** 290,296 ****
       writing lto info.  */
    lto_end_section ();
  
!   free (ob->main_stream);
    free (ob);
  }
  
--- 285,291 ----
       writing lto info.  */
    lto_end_section ();
  
!   delete ob->main_stream;
    free (ob);
  }
  
Index: gcc/data-streamer.h
===================================================================
*** gcc/data-streamer.h.orig	2014-08-07 13:47:46.007359525 +0200
--- gcc/data-streamer.h	2014-08-07 15:36:52.565908802 +0200
*************** const char *bp_unpack_string (struct dat
*** 85,90 ****
--- 85,91 ----
  unsigned HOST_WIDE_INT streamer_read_uhwi (struct lto_input_block *);
  HOST_WIDE_INT streamer_read_hwi (struct lto_input_block *);
  gcov_type streamer_read_gcov_count (struct lto_input_block *);
+ void streamer_read_data_stream (struct lto_input_block *, void *, size_t);
  
  /* Returns a new bit-packing context for bit-packing into S.  */
  static inline struct bitpack_d
*************** streamer_write_char_stream (struct lto_o
*** 182,188 ****
  {
    /* No space left.  */
    if (obs->left_in_block == 0)
!     lto_append_block (obs);
  
    /* Write the actual character.  */
    char *current_pointer = obs->current_pointer;
--- 183,189 ----
  {
    /* No space left.  */
    if (obs->left_in_block == 0)
!     obs->append_block ();
  
    /* Write the actual character.  */
    char *current_pointer = obs->current_pointer;
*************** streamer_write_char_stream (struct lto_o
*** 198,206 ****
  static inline unsigned char
  streamer_read_uchar (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
--- 199,211 ----
  static inline unsigned char
  streamer_read_uchar (struct lto_input_block *ib)
  {
!   /* No data left.  */
!   if (ib->left_in_block == 0)
!     ib->append_block ();
! 
!   /* Read a character.  */
!   ib->left_in_block--;
!   return *(ib->current_pointer++);
  }
  
  /* Output VAL into OBS and verify it is in range MIN...MAX that is supposed
Index: gcc/lto-opts.c
===================================================================
*** gcc/lto-opts.c.orig	2014-08-07 13:47:46.007359525 +0200
--- gcc/lto-opts.c	2014-08-07 15:21:50.154970932 +0200
*************** along with GCC; see the file COPYING3.
*** 37,42 ****
--- 37,43 ----
  #include "common/common-target.h"
  #include "diagnostic.h"
  #include "lto-streamer.h"
+ #include "data-streamer.h"
  #include "toplev.h"
  
  /* Append the option piece OPT to the COLLECT_GCC_OPTIONS string
Index: gcc/lto-streamer-out.c
===================================================================
*** gcc/lto-streamer-out.c.orig	2014-08-07 13:47:46.007359525 +0200
--- gcc/lto-streamer-out.c	2014-08-07 15:21:50.155970932 +0200
*************** create_output_block (enum lto_section_ty
*** 80,91 ****
  
    ob->section_type = section_type;
    ob->decl_state = lto_get_out_decl_state ();
!   ob->main_stream = XCNEW (struct lto_output_stream);
!   ob->string_stream = XCNEW (struct lto_output_stream);
    ob->writer_cache = streamer_tree_cache_create (!flag_wpa, true, false);
  
    if (section_type == LTO_section_function_body)
!     ob->cfg_stream = XCNEW (struct lto_output_stream);
  
    clear_line_info (ob);
  
--- 80,93 ----
  
    ob->section_type = section_type;
    ob->decl_state = lto_get_out_decl_state ();
!   ob->main_stream = new lto_output_stream;
!   // The way we use this stream prevents its compression as we basically
!   // perform random access
!   ob->string_stream = new lto_output_stream (2 * 1024 * 1024, false);
    ob->writer_cache = streamer_tree_cache_create (!flag_wpa, true, false);
  
    if (section_type == LTO_section_function_body)
!     ob->cfg_stream = new lto_output_stream;
  
    clear_line_info (ob);
  
*************** destroy_output_block (struct output_bloc
*** 106,115 ****
    delete ob->string_hash_table;
    ob->string_hash_table = NULL;
  
!   free (ob->main_stream);
!   free (ob->string_stream);
    if (section_type == LTO_section_function_body)
!     free (ob->cfg_stream);
  
    streamer_tree_cache_delete (ob->writer_cache);
    obstack_free (&ob->obstack, NULL);
--- 108,117 ----
    delete ob->string_hash_table;
    ob->string_hash_table = NULL;
  
!   delete ob->main_stream;
!   delete ob->string_stream;
    if (section_type == LTO_section_function_body)
!     delete ob->cfg_stream;
  
    streamer_tree_cache_delete (ob->writer_cache);
    obstack_free (&ob->obstack, NULL);
*************** produce_asm (struct output_block *ob, tr
*** 1895,1903 ****
    header.compressed_size = 0;
  
    if (section_type == LTO_section_function_body)
!     header.cfg_size = ob->cfg_stream->total_size;
!   header.main_size = ob->main_stream->total_size;
!   header.string_size = ob->string_stream->total_size;
    lto_write_data (&header, sizeof header);
  
    /* Put all of the gimple and the string table out the asm file as a
--- 1897,1905 ----
    header.compressed_size = 0;
  
    if (section_type == LTO_section_function_body)
!     header.cfg_size = ob->cfg_stream->finish ();
!   header.main_size = ob->main_stream->finish ();
!   header.string_size = ob->string_stream->finish ();
    lto_write_data (&header, sizeof header);
  
    /* Put all of the gimple and the string table out the asm file as a
*************** lto_output_toplevel_asms (void)
*** 2129,2136 ****
    header.lto_header.major_version = LTO_major_version;
    header.lto_header.minor_version = LTO_minor_version;
  
!   header.main_size = ob->main_stream->total_size;
!   header.string_size = ob->string_stream->total_size;
    lto_write_data (&header, sizeof header);
  
    /* Put all of the gimple and the string table out the asm file as a
--- 2131,2138 ----
    header.lto_header.major_version = LTO_major_version;
    header.lto_header.minor_version = LTO_minor_version;
  
!   header.main_size = ob->main_stream->finish ();
!   header.string_size = ob->string_stream->finish ();
    lto_write_data (&header, sizeof header);
  
    /* Put all of the gimple and the string table out the asm file as a
*************** produce_asm_for_decls (void)
*** 2678,2685 ****
      }
    header.decl_state_size = decl_state_size;
  
!   header.main_size = ob->main_stream->total_size;
!   header.string_size = ob->string_stream->total_size;
  
    lto_write_data (&header, sizeof header);
  
--- 2680,2687 ----
      }
    header.decl_state_size = decl_state_size;
  
!   header.main_size = ob->main_stream->finish ();
!   header.string_size = ob->string_stream->finish ();
  
    lto_write_data (&header, sizeof header);
  
Index: gcc/lto-streamer.h
===================================================================
*** gcc/lto-streamer.h.orig	2014-08-07 13:47:46.007359525 +0200
--- gcc/lto-streamer.h	2014-08-07 15:21:50.156970932 +0200
*************** typedef void (lto_free_section_data_f) (
*** 308,333 ****
  					size_t);
  
  /* Structure used as buffer for reading an LTO file.  */
! struct lto_input_block
  {
    const char *data;
    unsigned int p;
    unsigned int len;
  };
  
! #define LTO_INIT_INPUT_BLOCK(BASE,D,P,L)   \
!   do {                                     \
!     BASE.data = D;                         \
!     BASE.p = P;                            \
!     BASE.len = L;                          \
!   } while (0)
! 
! #define LTO_INIT_INPUT_BLOCK_PTR(BASE,D,P,L) \
!   do {                                       \
!     BASE->data = D;                          \
!     BASE->p = P;                             \
!     BASE->len = L;                           \
!   } while (0)
  
  
  /* The is the first part of the record for a function or constructor
--- 308,344 ----
  					size_t);
  
  /* Structure used as buffer for reading an LTO file.  */
! class lto_input_block
  {
+ public:
+   /* Special constructor for the string table, it abuses this to
+      do random access but use the uhwi decoder.  */
+   lto_input_block (const char *data_, unsigned int p_, unsigned int len_)
+       : current_pointer (data_ + p_), left_in_block (len_), compress (false),
+         data (NULL), p (0), len (0) {};
+   lto_input_block (const char *data_, unsigned int len_, bool compress_ = true)
+       : current_pointer (NULL), left_in_block (0), compress (compress_),
+         data (data_), p (0), len (len_), zbuf (NULL), zlib_stream (NULL) {};
+   ~lto_input_block ();
+   void append_block ();
+   inline bool eof ();
+   const char *current_pointer;
+   unsigned int left_in_block;
+ 
+ private:
+   const bool compress;
    const char *data;
    unsigned int p;
    unsigned int len;
+   char *zbuf;
+   struct z_stream_s *zlib_stream;
  };
  
! inline bool
! lto_input_block::eof ()
! {
!   return left_in_block == 0 && len == p;
! }
  
  
  /* The is the first part of the record for a function or constructor
*************** struct lto_char_ptr_base
*** 575,584 ****
     The entire structure should be zeroed when created.  The record
     consists of a set of blocks.  The first sizeof (ptr) bytes are used
     as a chain, and the rest store the bytes to be written.  */
! struct lto_output_stream
  {
!   /* The pointer to the first block in the stream.  */
!   struct lto_char_ptr_base * first_block;
  
    /* The pointer to the last and current block in the stream.  */
    struct lto_char_ptr_base * current_block;
--- 586,608 ----
     The entire structure should be zeroed when created.  The record
     consists of a set of blocks.  The first sizeof (ptr) bytes are used
     as a chain, and the rest store the bytes to be written.  */
! class lto_output_stream
  {
! public:
!   lto_output_stream (size_t block_size_ = 2 * 1024 * 1024,
! 		     bool compress_ = true)
!       : current_block (NULL), current_pointer (NULL),
!         left_in_block (0), block_size (block_size_), total_size (0),
!         first_block (NULL), current_z_block (NULL), compress (compress_),
! 	zlib_stream (NULL)
!   {
!     gcc_assert (block_size > sizeof (lto_char_ptr_base));
!   }
! 
!   unsigned int finish();
!   lto_char_ptr_base *get_blocks ();
! 
!   void append_block ();
  
    /* The pointer to the last and current block in the stream.  */
    struct lto_char_ptr_base * current_block;
*************** struct lto_output_stream
*** 589,599 ****
    /* The number of characters left in the current block.  */
    unsigned int left_in_block;
  
!   /* The block size of the last block allocated.  */
!   unsigned int block_size;
  
!   /* The total number of characters written.  */
    unsigned int total_size;
  };
  
  /* The is the first part of the record in an LTO file for many of the
--- 613,636 ----
    /* The number of characters left in the current block.  */
    unsigned int left_in_block;
  
!   /* The block size to use.  */
!   const unsigned int block_size;
  
!   /* The total number of uncompressed characters written.  */
    unsigned int total_size;
+ 
+ private:
+   void compress_current_block (bool);
+ 
+   /* The pointer to the first block in the stream.  */
+   struct lto_char_ptr_base * first_block;
+ 
+   struct lto_char_ptr_base * current_z_block;
+ 
+   /* Whether to compress this stream.  */
+   const bool compress;
+ 
+   struct z_stream_s *zlib_stream;
  };
  
  /* The is the first part of the record in an LTO file for many of the
*************** extern struct lto_in_decl_state *lto_get
*** 756,762 ****
  				      struct lto_file_decl_data *, tree);
  extern void lto_free_function_in_decl_state (struct lto_in_decl_state *);
  extern void lto_free_function_in_decl_state_for_node (symtab_node *);
- 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;
--- 793,798 ----
*************** extern void lto_push_out_decl_state (str
*** 791,797 ****
  extern struct lto_out_decl_state *lto_pop_out_decl_state (void);
  extern void lto_record_function_out_decl_state (tree,
  						struct lto_out_decl_state *);
- extern void lto_append_block (struct lto_output_stream *);
  
  
  /* In lto-streamer.c.  */
--- 827,832 ----
Index: gcc/lto-section-in.c
===================================================================
*** gcc/lto-section-in.c.orig	2014-08-07 13:47:46.007359525 +0200
--- gcc/lto-section-in.c	2014-08-07 15:21:50.156970932 +0200
*************** lto_get_section_data (struct lto_file_de
*** 153,159 ****
  
    /* FIXME lto: WPA mode does not write compressed sections, so for now
       suppress uncompression if flag_ltrans.  */
!   if (!flag_ltrans)
      {
        /* Create a mapping header containing the underlying data and length,
  	 and prepend this to the uncompression buffer.  The uncompressed data
--- 153,159 ----
  
    /* FIXME lto: WPA mode does not write compressed sections, so for now
       suppress uncompression if flag_ltrans.  */
!   if (!flag_ltrans && 0)
      {
        /* Create a mapping header containing the underlying data and length,
  	 and prepend this to the uncompression buffer.  The uncompressed data
*************** lto_free_section_data (struct lto_file_d
*** 200,206 ****
  
    /* FIXME lto: WPA mode does not write compressed sections, so for now
       suppress uncompression mapping if flag_ltrans.  */
!   if (flag_ltrans)
      {
        (free_section_f) (file_data, section_type, name, data, len);
        return;
--- 200,206 ----
  
    /* FIXME lto: WPA mode does not write compressed sections, so for now
       suppress uncompression mapping if flag_ltrans.  */
!   if (flag_ltrans || 1)
      {
        (free_section_f) (file_data, section_type, name, data, len);
        return;
*************** lto_create_simple_input_block (struct lt
*** 227,245 ****
    const struct lto_simple_header * header
      = (const struct lto_simple_header *) data;
  
-   struct lto_input_block* ib_main;
    int main_offset = sizeof (struct lto_simple_header);
  
    if (!data)
      return NULL;
  
-   ib_main = XNEW (struct lto_input_block);
- 
    *datar = data;
!   LTO_INIT_INPUT_BLOCK_PTR (ib_main, data + main_offset,
! 			    0, header->main_size);
! 
!   return ib_main;
  }
  
  
--- 227,239 ----
    const struct lto_simple_header * header
      = (const struct lto_simple_header *) data;
  
    int main_offset = sizeof (struct lto_simple_header);
  
    if (!data)
      return NULL;
  
    *datar = data;
!   return new lto_input_block (data + main_offset, header->main_size);
  }
  
  
*************** lto_destroy_simple_input_block (struct l
*** 255,261 ****
  				struct lto_input_block *ib,
  				const char *data, size_t len)
  {
!   free (ib);
    lto_free_section_data (file_data, section_type, NULL, data, len);
  }
  
--- 249,255 ----
  				struct lto_input_block *ib,
  				const char *data, size_t len)
  {
!   delete ib;
    lto_free_section_data (file_data, section_type, NULL, data, len);
  }
  
*************** lto_free_function_in_decl_state_for_node
*** 454,468 ****
  }
  
  
- /* Report read pass end of the section.  */
- 
- void
- lto_section_overrun (struct lto_input_block *ib)
- {
-   fatal_error ("bytecode stream: trying to read %d bytes "
- 	       "after the end of the input buffer", ib->p - ib->len);
- }
- 
  /* Report out of range value.  */
  
  void
--- 448,453 ----
Index: gcc/lto-cgraph.c
===================================================================
*** gcc/lto-cgraph.c.orig	2014-08-07 13:47:46.007359525 +0200
--- gcc/lto-cgraph.c	2014-08-07 15:39:05.967899618 +0200
*************** lto_output_node (struct lto_simple_outpu
*** 484,490 ****
      comdat = IDENTIFIER_POINTER (group);
    else
      comdat = "";
!   streamer_write_data_stream (ob->main_stream, comdat, strlen (comdat) + 1);
  
    if (group)
      {
--- 484,491 ----
      comdat = IDENTIFIER_POINTER (group);
    else
      comdat = "";
!   streamer_write_uhwi_stream (ob->main_stream, strlen (comdat));
!   streamer_write_data_stream (ob->main_stream, comdat, strlen (comdat));
  
    if (group)
      {
*************** lto_output_node (struct lto_simple_outpu
*** 542,548 ****
    bp_pack_enum (&bp, ld_plugin_symbol_resolution,
  	        LDPR_NUM_KNOWN, node->resolution);
    streamer_write_bitpack (&bp);
!   streamer_write_data_stream (ob->main_stream, section, strlen (section) + 1);
  
    if (node->thunk.thunk_p && !boundary_p)
      {
--- 543,550 ----
    bp_pack_enum (&bp, ld_plugin_symbol_resolution,
  	        LDPR_NUM_KNOWN, node->resolution);
    streamer_write_bitpack (&bp);
!   streamer_write_uhwi_stream (ob->main_stream, strlen (section));
!   streamer_write_data_stream (ob->main_stream, section, strlen (section));
  
    if (node->thunk.thunk_p && !boundary_p)
      {
*************** lto_output_varpool_node (struct lto_simp
*** 618,624 ****
      comdat = IDENTIFIER_POINTER (group);
    else
      comdat = "";
!   streamer_write_data_stream (ob->main_stream, comdat, strlen (comdat) + 1);
  
    if (group)
      {
--- 620,627 ----
      comdat = IDENTIFIER_POINTER (group);
    else
      comdat = "";
!   streamer_write_uhwi_stream (ob->main_stream, strlen (comdat));
!   streamer_write_data_stream (ob->main_stream, comdat, strlen (comdat));
  
    if (group)
      {
*************** lto_output_varpool_node (struct lto_simp
*** 636,642 ****
    section = node->get_section ();
    if (!section)
      section = "";
!   streamer_write_data_stream (ob->main_stream, section, strlen (section) + 1);
  
    streamer_write_enum (ob->main_stream, ld_plugin_symbol_resolution,
  		       LDPR_NUM_KNOWN, node->resolution);
--- 639,646 ----
    section = node->get_section ();
    if (!section)
      section = "";
!   streamer_write_uhwi_stream (ob->main_stream, strlen (section));
!   streamer_write_data_stream (ob->main_stream, section, strlen (section));
  
    streamer_write_enum (ob->main_stream, ld_plugin_symbol_resolution,
  		       LDPR_NUM_KNOWN, node->resolution);
*************** output_symtab (void)
*** 988,1025 ****
  static tree
  read_identifier (struct lto_input_block *ib)
  {
!   unsigned int len = strnlen (ib->data + ib->p, ib->len - ib->p - 1);
!   tree id;
! 
!   if (ib->data[ib->p + len])
!     lto_section_overrun (ib);
    if (!len)
!     {
!       ib->p++;
!       return NULL;
!     }
!   id = get_identifier (ib->data + ib->p);
!   ib->p += len + 1;
!   return id;
  }
  
  /* Return string encoded in IB, NULL if string is empty.  */
  
! static const char *
  read_string (struct lto_input_block *ib)
  {
!   unsigned int len = strnlen (ib->data + ib->p, ib->len - ib->p - 1);
!   const char *str;
! 
!   if (ib->data[ib->p + len])
!     lto_section_overrun (ib);
    if (!len)
!     {
!       ib->p++;
!       return NULL;
!     }
!   str = ib->data + ib->p;
!   ib->p += len + 1;
    return str;
  }
  
--- 992,1018 ----
  static tree
  read_identifier (struct lto_input_block *ib)
  {
!   unsigned int len = streamer_read_uhwi (ib);
    if (!len)
!     return NULL;
!   char *str = XALLOCAVEC (char, len + 1);
!   for (unsigned i = 0; i < len; ++i)
!     str[i] = streamer_read_uchar (ib);
!   str[len] = '\0';
!   return get_identifier (str);
  }
  
  /* Return string encoded in IB, NULL if string is empty.  */
  
! static char *
  read_string (struct lto_input_block *ib)
  {
!   unsigned int len = streamer_read_uhwi (ib);
    if (!len)
!     return NULL;
!   char *str = (char *)xmalloc (len + 1);
!   streamer_read_data_stream (ib, str, len);
!   str[len] = '\0';
    return str;
  }
  
*************** input_node (struct lto_file_decl_data *f
*** 1113,1119 ****
    int order;
    int i, count;
    tree group;
!   const char *section;
  
    order = streamer_read_hwi (ib) + order_base;
    clone_ref = streamer_read_hwi (ib);
--- 1106,1112 ----
    int order;
    int i, count;
    tree group;
!   char *section;
  
    order = streamer_read_hwi (ib) + order_base;
    clone_ref = streamer_read_hwi (ib);
*************** input_node (struct lto_file_decl_data *f
*** 1190,1196 ****
      node->same_comdat_group = (symtab_node *) (intptr_t) LCC_NOT_FOUND;
    section = read_string (ib);
    if (section)
!     node->set_section_for_node (section);
  
    if (node->thunk.thunk_p)
      {
--- 1183,1192 ----
      node->same_comdat_group = (symtab_node *) (intptr_t) LCC_NOT_FOUND;
    section = read_string (ib);
    if (section)
!     {
!       node->set_section_for_node (section);
!       free (section);
!     }
  
    if (node->thunk.thunk_p)
      {
*************** input_varpool_node (struct lto_file_decl
*** 1227,1233 ****
    int ref = LCC_NOT_FOUND;
    int order;
    tree group;
!   const char *section;
  
    order = streamer_read_hwi (ib) + order_base;
    decl_index = streamer_read_uhwi (ib);
--- 1223,1229 ----
    int ref = LCC_NOT_FOUND;
    int order;
    tree group;
!   char *section;
  
    order = streamer_read_hwi (ib) + order_base;
    decl_index = streamer_read_uhwi (ib);
*************** input_varpool_node (struct lto_file_decl
*** 1280,1286 ****
      node->same_comdat_group = (symtab_node *) (intptr_t) LCC_NOT_FOUND;
    section = read_string (ib);
    if (section)
!     node->set_section_for_node (section);
    node->resolution = streamer_read_enum (ib, ld_plugin_symbol_resolution,
  					        LDPR_NUM_KNOWN);
    gcc_assert (flag_ltrans
--- 1276,1285 ----
      node->same_comdat_group = (symtab_node *) (intptr_t) LCC_NOT_FOUND;
    section = read_string (ib);
    if (section)
!     {
!       node->set_section_for_node (section);
!       free (section);
!     }
    node->resolution = streamer_read_enum (ib, ld_plugin_symbol_resolution,
  					        LDPR_NUM_KNOWN);
    gcc_assert (flag_ltrans
*************** input_cgraph_opt_section (struct lto_fil
*** 1896,1907 ****
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
-   struct lto_input_block ib_main;
    unsigned int i;
    unsigned int count;
  
!   LTO_INIT_INPUT_BLOCK (ib_main, (const char *) data + main_offset, 0,
! 			header->main_size);
  
    data_in =
      lto_data_in_create (file_data, (const char *) data + string_offset,
--- 1895,1905 ----
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
    unsigned int i;
    unsigned int count;
  
!   lto_input_block ib_main ((const char *) data + main_offset,
! 			   header->main_size);
  
    data_in =
      lto_data_in_create (file_data, (const char *) data + string_offset,
Index: gcc/data-streamer-in.c
===================================================================
*** gcc/data-streamer-in.c.orig	2014-08-07 13:47:46.007359525 +0200
--- gcc/data-streamer-in.c	2014-08-07 15:44:12.833878490 +0200
*************** along with GCC; see the file COPYING3.
*** 22,27 ****
--- 22,32 ----
  
  #include "config.h"
  #include "system.h"
+ /* zlib.h includes other system headers.  Those headers may test feature
+    test macros.  config.h may define feature test macros.  For this reason,
+    zlib.h needs to be included after, rather than before, config.h and
+    system.h.  */
+ #include <zlib.h>
  #include "coretypes.h"
  #include "diagnostic.h"
  #include "tree.h"
*************** along with GCC; see the file COPYING3.
*** 33,45 ****
  #include "gimple.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;
  
--- 38,107 ----
  #include "gimple.h"
  #include "data-streamer.h"
  
+ 
+ void
+ lto_input_block::append_block ()
+ {
+   gcc_assert (left_in_block == 0 && data);
+   if (!compress)
+     {
+       current_pointer = data + p;
+       left_in_block = len - p;
+       p += left_in_block;
+     }
+   else
+     {
+       int status;
+ 
+       if (!zlib_stream)
+ 	{
+ 	  zlib_stream = XCNEW (z_stream);
+ 	  zlib_stream->zalloc = NULL;
+ 	  zlib_stream->zfree = NULL;
+ 	  zlib_stream->opaque = NULL;
+ 	  zlib_stream->avail_in = len;
+ 	  zlib_stream->next_in = (Bytef*)const_cast<char *>(data + p);
+ 	  status = inflateInit (zlib_stream);
+ 	  if (status != Z_OK)
+ 	    internal_error ("compressed stream: %s", zError (status));
+ 	  zbuf = XNEWVEC (char, 2 * 1024 * 1024);
+ 	}
+ 
+       zlib_stream->avail_out = 2 * 1024 * 1024;
+       zlib_stream->next_out = (Bytef*)zbuf;
+       status = inflate (zlib_stream, Z_NO_FLUSH);
+       if (status != Z_OK && status != Z_STREAM_END)
+ 	internal_error ("compressed stream: %s", zError (status));
+ 
+       current_pointer = zbuf;
+       left_in_block = 2 * 1024 * 1024 - zlib_stream->avail_out;
+       p = len - zlib_stream->avail_in;
+     }
+   if (left_in_block == 0)
+     fatal_error ("bytecode stream: trying to read bytes "
+ 		 "after the end of the input buffer");
+ }
+ 
+ lto_input_block::~lto_input_block ()
+ {
+   if (compress)
+     {
+       if (zlib_stream)
+ 	{
+ 	  inflateEnd (zlib_stream);
+ 	  free (zlib_stream);
+ 	}
+       if (zbuf)
+ 	free (zbuf);
+     }
+ }
+ 
  /* 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)
  {
    unsigned int len;
    const char *result;
  
*************** string_for_index (struct data_in *data_i
*** 50,64 ****
      }
  
    /* 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 = streamer_read_uhwi (&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;
  }
--- 112,126 ----
      }
  
    /* Get the string stored at location LOC in DATA_IN->STRINGS.  */
!   lto_input_block str_tab (data_in->strings, loc - 1,
! 			   data_in->strings_len - (loc - 1));
    len = streamer_read_uhwi (&str_tab);
    *rlen = len;
  
!   if (str_tab.left_in_block < len)
      internal_error ("bytecode stream: string too long for the string table");
  
!   result = str_tab.current_pointer;
  
    return result;
  }
*************** bp_unpack_string (struct data_in *data_i
*** 127,159 ****
  unsigned HOST_WIDE_INT
  streamer_read_uhwi (struct lto_input_block *ib)
  {
!   unsigned HOST_WIDE_INT result;
!   int shift;
!   unsigned HOST_WIDE_INT byte;
!   unsigned int p = ib->p;
!   unsigned int len = ib->len;
  
!   const char *data = ib->data;
!   result = data[p++];
!   if ((result & 0x80) != 0)
!     {
!       result &= 0x7f;
!       shift = 7;
!       do
  	{
! 	  byte = data[p++];
! 	  result |= (byte & 0x7f) << shift;
! 	  shift += 7;
  	}
!       while ((byte & 0x80) != 0);
      }
- 
-   /* We check for section overrun after the fact for performance reason.  */
-   if (p > len)
-     lto_section_overrun (ib);
- 
-   ib->p = p;
-   return result;
  }
  
  
--- 189,240 ----
  unsigned HOST_WIDE_INT
  streamer_read_uhwi (struct lto_input_block *ib)
  {
!   if (ib->left_in_block >= sizeof (unsigned HOST_WIDE_INT) + 1)
!     {
!       const char *current_pointer = ib->current_pointer;
!       int left_in_block = ib->left_in_block;
  
!       unsigned HOST_WIDE_INT result = *(current_pointer++);
!       --left_in_block;
!       if ((result & 0x80) != 0)
  	{
! 	  unsigned HOST_WIDE_INT byte;
! 	  int shift;
! 	  result &= 0x7f;
! 	  shift = 7;
! 	  do
! 	    {
! 	      byte = *(current_pointer++);
! 	      --left_in_block;
! 	      result |= (byte & 0x7f) << shift;
! 	      shift += 7;
! 	    }
! 	  while ((byte & 0x80) != 0);
  	}
!       ib->current_pointer = current_pointer;
!       ib->left_in_block = left_in_block;
!       gcc_checking_assert (left_in_block >= 0);
!       return result;
!     }
!   else
!     {
!       unsigned HOST_WIDE_INT result = streamer_read_uchar (ib);
!       if ((result & 0x80) != 0)
! 	{
! 	  unsigned HOST_WIDE_INT byte;
! 	  int shift;
! 	  result &= 0x7f;
! 	  shift = 7;
! 	  do
! 	    {
! 	      byte = streamer_read_uchar (ib);
! 	      result |= (byte & 0x7f) << shift;
! 	      shift += 7;
! 	    }
! 	  while ((byte & 0x80) != 0);
! 	}
!       return result;
      }
  }
  
  
*************** streamer_read_hwi (struct lto_input_bloc
*** 166,182 ****
    int shift = 0;
    unsigned HOST_WIDE_INT byte;
  
!   while (true)
      {
!       byte = streamer_read_uchar (ib);
!       result |= (byte & 0x7f) << shift;
!       shift += 7;
!       if ((byte & 0x80) == 0)
  	{
! 	  if ((shift < HOST_BITS_PER_WIDE_INT) && (byte & 0x40))
! 	    result |= - (HOST_WIDE_INT_1U << shift);
  
! 	  return result;
  	}
      }
  }
--- 247,288 ----
    int shift = 0;
    unsigned HOST_WIDE_INT byte;
  
!   if (ib->left_in_block >= sizeof (unsigned HOST_WIDE_INT) + 1)
      {
!       const char *current_pointer = ib->current_pointer;
!       int left_in_block = ib->left_in_block;
!       while (true)
  	{
! 	  byte = *(current_pointer++);
! 	  --left_in_block;
! 	  result |= (byte & 0x7f) << shift;
! 	  shift += 7;
! 	  if ((byte & 0x80) == 0)
! 	    {
! 	      if ((shift < HOST_BITS_PER_WIDE_INT) && (byte & 0x40))
! 		result |= - (HOST_WIDE_INT_1U << shift);
! 
! 	      ib->current_pointer = current_pointer;
! 	      ib->left_in_block = left_in_block;
! 	      gcc_checking_assert (left_in_block >= 0);
! 	      return result;
! 	    }
! 	}
!     }
!   else
!     {
!       while (true)
! 	{
! 	  byte = streamer_read_uchar (ib);
! 	  result |= (byte & 0x7f) << shift;
! 	  shift += 7;
! 	  if ((byte & 0x80) == 0)
! 	    {
! 	      if ((shift < HOST_BITS_PER_WIDE_INT) && (byte & 0x40))
! 		result |= - (HOST_WIDE_INT_1U << shift);
  
! 	      return result;
! 	    }
  	}
      }
  }
*************** streamer_read_gcov_count (struct lto_inp
*** 190,192 ****
--- 296,328 ----
    gcc_assert (ret >= 0);
    return ret;
  }
+ 
+ /* Read raw DATA of length LEN from IB.  */
+ 
+ void
+ streamer_read_data_stream (struct lto_input_block *ib, void *data,
+ 			   size_t len)
+ {
+   while (len)
+     {
+       size_t copy;
+ 
+       /* No space left.  */
+       if (ib->left_in_block == 0)
+ 	ib->append_block ();
+ 
+       /* Determine how many bytes to copy in this loop.  */
+       if (len <= ib->left_in_block)
+ 	copy = len;
+       else
+ 	copy = ib->left_in_block;
+ 
+       /* Copy the data and do bookkeeping.  */
+       memcpy (data, ib->current_pointer, copy);
+       ib->current_pointer += copy;
+       ib->left_in_block -= copy;
+       data = (char *) data + copy;
+       len -= copy;
+     }
+ }
+ 
Index: gcc/ipa-inline-analysis.c
===================================================================
*** gcc/ipa-inline-analysis.c.orig	2014-08-07 13:47:46.007359525 +0200
--- gcc/ipa-inline-analysis.c	2014-08-07 15:21:50.158970932 +0200
*************** inline_read_section (struct lto_file_dec
*** 4086,4097 ****
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
-   struct lto_input_block ib;
    unsigned int i, count2, j;
    unsigned int f_count;
  
!   LTO_INIT_INPUT_BLOCK (ib, (const char *) data + main_offset, 0,
! 			header->main_size);
  
    data_in =
      lto_data_in_create (file_data, (const char *) data + string_offset,
--- 4086,4095 ----
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
    unsigned int i, count2, j;
    unsigned int f_count;
  
!   lto_input_block ib ((const char *) data + main_offset, header->main_size);
  
    data_in =
      lto_data_in_create (file_data, (const char *) data + string_offset,
Index: gcc/ipa-prop.c
===================================================================
*** gcc/ipa-prop.c.orig	2014-08-07 13:47:46.007359525 +0200
--- gcc/ipa-prop.c	2014-08-07 15:21:50.160970932 +0200
*************** ipa_prop_read_section (struct lto_file_d
*** 4895,4906 ****
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
-   struct lto_input_block ib_main;
    unsigned int i;
    unsigned int count;
  
!   LTO_INIT_INPUT_BLOCK (ib_main, (const char *) data + main_offset, 0,
! 			header->main_size);
  
    data_in =
      lto_data_in_create (file_data, (const char *) data + string_offset,
--- 4895,4905 ----
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
    unsigned int i;
    unsigned int count;
  
!   lto_input_block ib_main ((const char *) data + main_offset,
! 			   header->main_size);
  
    data_in =
      lto_data_in_create (file_data, (const char *) data + string_offset,
*************** read_replacements_section (struct lto_fi
*** 5073,5084 ****
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
-   struct lto_input_block ib_main;
    unsigned int i;
    unsigned int count;
  
!   LTO_INIT_INPUT_BLOCK (ib_main, (const char *) data + main_offset, 0,
! 			header->main_size);
  
    data_in = lto_data_in_create (file_data, (const char *) data + string_offset,
  				header->string_size, vNULL);
--- 5072,5082 ----
    const int main_offset = cfg_offset + header->cfg_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
    unsigned int i;
    unsigned int count;
  
!   lto_input_block ib_main ((const char *) data + main_offset,
! 			   header->main_size);
  
    data_in = lto_data_in_create (file_data, (const char *) data + string_offset,
  				header->string_size, vNULL);
Index: gcc/lto-streamer-in.c
===================================================================
*** gcc/lto-streamer-in.c.orig	2014-08-07 13:47:46.007359525 +0200
--- gcc/lto-streamer-in.c	2014-08-07 15:21:50.160970932 +0200
*************** lto_read_body_or_constructor (struct lto
*** 1054,1061 ****
    int cfg_offset;
    int main_offset;
    int string_offset;
-   struct lto_input_block ib_cfg;
-   struct lto_input_block ib_main;
    tree fn_decl = node->decl;
  
    header = (const struct lto_function_header *) data;
--- 1054,1059 ----
*************** lto_read_body_or_constructor (struct lto
*** 1064,1089 ****
        cfg_offset = sizeof (struct lto_function_header);
        main_offset = cfg_offset + header->cfg_size;
        string_offset = main_offset + header->main_size;
- 
-       LTO_INIT_INPUT_BLOCK (ib_cfg,
- 			    data + cfg_offset,
- 			    0,
- 			    header->cfg_size);
- 
-       LTO_INIT_INPUT_BLOCK (ib_main,
- 			    data + main_offset,
- 			    0,
- 			    header->main_size);
      }
    else
      {
        main_offset = sizeof (struct lto_function_header);
        string_offset = main_offset + header->main_size;
- 
-       LTO_INIT_INPUT_BLOCK (ib_main,
- 			    data + main_offset,
- 			    0,
- 			    header->main_size);
      }
  
    data_in = lto_data_in_create (file_data, data + string_offset,
--- 1062,1072 ----
*************** lto_read_body_or_constructor (struct lto
*** 1104,1111 ****
  
        /* Set up the struct function.  */
        from = data_in->reader_cache->nodes.length ();
        if (TREE_CODE (node->decl) == FUNCTION_DECL)
!         input_function (fn_decl, data_in, &ib_main, &ib_cfg);
        else
          input_constructor (fn_decl, data_in, &ib_main);
        /* And fixup types we streamed locally.  */
--- 1087,1098 ----
  
        /* Set up the struct function.  */
        from = data_in->reader_cache->nodes.length ();
+       lto_input_block ib_main (data + main_offset, header->main_size);
        if (TREE_CODE (node->decl) == FUNCTION_DECL)
! 	{
! 	  lto_input_block ib_cfg (data + cfg_offset, header->cfg_size);
! 	  input_function (fn_decl, data_in, &ib_main, &ib_cfg);
! 	}
        else
          input_constructor (fn_decl, data_in, &ib_main);
        /* And fixup types we streamed locally.  */
*************** lto_input_toplevel_asms (struct lto_file
*** 1360,1366 ****
    const struct lto_asm_header *header = (const struct lto_asm_header *) data;
    int string_offset;
    struct data_in *data_in;
-   struct lto_input_block ib;
    tree str;
  
    if (! data)
--- 1347,1352 ----
*************** lto_input_toplevel_asms (struct lto_file
*** 1368,1377 ****
  
    string_offset = sizeof (*header) + header->main_size;
  
!   LTO_INIT_INPUT_BLOCK (ib,
! 			data + sizeof (*header),
! 			0,
! 			header->main_size);
  
    data_in = lto_data_in_create (file_data, data + string_offset,
  			      header->string_size, vNULL);
--- 1354,1360 ----
  
    string_offset = sizeof (*header) + header->main_size;
  
!   lto_input_block ib (data + sizeof (*header), header->main_size);
  
    data_in = lto_data_in_create (file_data, data + string_offset,
  			      header->string_size, vNULL);
Index: gcc/lto/lto.c
===================================================================
*** gcc/lto/lto.c.orig	2014-08-07 13:47:46.007359525 +0200
--- gcc/lto/lto.c	2014-08-07 15:21:50.161970932 +0200
*************** lto_read_decls (struct lto_file_decl_dat
*** 1843,1856 ****
    const int decl_offset = sizeof (struct lto_decl_header);
    const int main_offset = decl_offset + header->decl_state_size;
    const int string_offset = main_offset + header->main_size;
-   struct lto_input_block ib_main;
    struct data_in *data_in;
    unsigned int i;
    const uint32_t *data_ptr, *data_end;
    uint32_t num_decl_states;
  
!   LTO_INIT_INPUT_BLOCK (ib_main, (const char *) data + main_offset, 0,
! 			header->main_size);
  
    data_in = lto_data_in_create (decl_data, (const char *) data + string_offset,
  				header->string_size, resolutions);
--- 1843,1855 ----
    const int decl_offset = sizeof (struct lto_decl_header);
    const int main_offset = decl_offset + header->decl_state_size;
    const int string_offset = main_offset + header->main_size;
    struct data_in *data_in;
    unsigned int i;
    const uint32_t *data_ptr, *data_end;
    uint32_t num_decl_states;
  
!   lto_input_block ib_main ((const char *) data + main_offset,
! 			   header->main_size);
  
    data_in = lto_data_in_create (decl_data, (const char *) data + string_offset,
  				header->string_size, resolutions);
*************** lto_read_decls (struct lto_file_decl_dat
*** 1859,1865 ****
       internal types that should not be merged.  */
  
    /* Read the global declarations and types.  */
!   while (ib_main.p < ib_main.len)
      {
        tree t;
        unsigned from = data_in->reader_cache->nodes.length ();
--- 1858,1864 ----
       internal types that should not be merged.  */
  
    /* Read the global declarations and types.  */
!   while (!ib_main.eof ())
      {
        tree t;
        unsigned from = data_in->reader_cache->nodes.length ();

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

* Re: [PATCH][LTO] Streamer re-org (what's left)
  2014-08-07 13:50 ` Richard Biener
@ 2014-08-11  9:11   ` Richard Biener
       [not found]     ` <20140814163337.GA27831@kam.mff.cuni.cz>
  0 siblings, 1 reply; 7+ messages in thread
From: Richard Biener @ 2014-08-11  9:11 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jan Hubicka

On Thu, 7 Aug 2014, Richard Biener wrote:

> On Thu, 7 Aug 2014, Richard Biener wrote:
> 
> > 
> > The following are the non-cleanup parts.  The patch moves us
> > to compress streams (what data-streamer thinks of "streams")
> > instead of whole sections.  This enables us to only need
> > a single compressed and uncompressed block of data "live"
> > as opposed to a whole section (well, in theory - we still
> > do mmap based I/O).  The disadvantage is that you really
> > have to go through the data-streamer interface to access
> > data at read-in.
> > 
> > As is the patch doesn't improve virtual memory usage a lot
> > (according to Martins tests) but it increases compile-time
> > (we now compress LTRANs streams - reducing their size to 1/3).
> > 
> > What the patch still misses is to re-do the string part
> > of the decl streams to make them compressed again.  It also
> > misses ripping out the section-compression code entirely
> > (lto-compress.c).
> > 
> > Oh, and it misses a ChangeLog.
> > 
> > Now the question is whether we want this or not.  It's certainly
> > not perfect in it's current state.
> > 
> > But I wouldn't want to tie the merge-SCCs-from-disk stuff to
> > the data-streamer internals too much (even if it seems tempting
> > and easy in it's current form).
> > 
> > Any comments appreciated.
> 
> The following is the update I promised on IRC.  It fixes a
> small memory leak from read_string () and should restore
> performance of streamer_read_uhwi.

And this fixes the thinko in zlib use.

du  /tmp/*ltrans* | awk '{ sum += $1 } END { print sum }'
stage3 cc1 WPA ltrans file size 178740 (patched)
stage3 cc1 WPA ltrans file size 460068 (unpatched)

Index: gcc/data-streamer-out.c
===================================================================
*** gcc/data-streamer-out.c.orig	2014-08-08 14:54:20.592135967 +0200
--- gcc/data-streamer-out.c	2014-08-11 10:31:24.066376554 +0200
*************** along with GCC; see the file COPYING3.
*** 22,27 ****
--- 22,32 ----
  
  #include "config.h"
  #include "system.h"
+ /* zlib.h includes other system headers.  Those headers may test feature
+    test macros.  config.h may define feature test macros.  For this reason,
+    zlib.h needs to be included after, rather than before, config.h and
+    system.h.  */
+ #include <zlib.h>
  #include "coretypes.h"
  #include "tree.h"
  #include "basic-block.h"
*************** along with GCC; see the file COPYING3.
*** 33,79 ****
  #include "data-streamer.h"
  
  
  /* Adds a new block to output stream OBS.  */
  
  void
! lto_append_block (struct lto_output_stream *obs)
  {
    struct lto_char_ptr_base *new_block;
  
!   gcc_assert (obs->left_in_block == 0);
  
!   if (obs->first_block == NULL)
      {
!       /* This is the first time the stream has been written
! 	 into.  */
!       obs->block_size = 1024;
!       new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
!       obs->first_block = new_block;
      }
    else
      {
!       struct lto_char_ptr_base *tptr;
!       /* Get a new block that is twice as big as the last block
! 	 and link it into the list.  */
!       obs->block_size *= 2;
!       new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
!       /* The first bytes of the block are reserved as a pointer to
! 	 the next block.  Set the chain of the full block to the
! 	 pointer to the new block.  */
!       tptr = obs->current_block;
!       tptr->ptr = (char *) new_block;
      }
  
    /* Set the place for the next char at the first position after the
       chain to the next block.  */
!   obs->current_pointer
      = ((char *) new_block) + sizeof (struct lto_char_ptr_base);
!   obs->current_block = new_block;
    /* Null out the newly allocated block's pointer to the next block.  */
    new_block->ptr = NULL;
!   obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base);
  }
  
  
  /* 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'.
--- 38,193 ----
  #include "data-streamer.h"
  
  
+ /* Finishes the last block, eventually compressing it, and returns the
+    total size of the stream.  */
+ 
+ unsigned int
+ lto_output_stream::finish ()
+ {
+   if (compress
+       && current_pointer)
+     {
+       /* Compress the last (partial) block.  */
+       compress_current_block (true);
+       left_in_block = zlib_stream->avail_out;
+       free (current_block);
+       current_block = NULL;
+       int status = deflateEnd (zlib_stream);
+       if (status != Z_OK)
+ 	internal_error ("compressed stream: %s", zError (status));
+       free (zlib_stream);
+     }
+   current_pointer = NULL;
+ 
+   unsigned int size = 0;
+   for (lto_char_ptr_base *b = first_block; b; b = (lto_char_ptr_base *)b->ptr)
+     size += block_size - sizeof (lto_char_ptr_base);
+   size -= left_in_block;
+   return size;
+ }
+ 
+ /* Returns a pointer to the first block of the chain of blocks to output.  */
+ 
+ lto_char_ptr_base *
+ lto_output_stream::get_blocks ()
+ {
+   finish ();
+   return first_block;
+ }
+ 
  /* Adds a new block to output stream OBS.  */
  
  void
! lto_output_stream::append_block ()
  {
    struct lto_char_ptr_base *new_block;
  
!   gcc_assert (left_in_block == 0 && block_size > sizeof (lto_char_ptr_base));
  
!   if (first_block == NULL)
      {
!       /* This is the first time the stream has been written into.  */
!       new_block = (struct lto_char_ptr_base*) xmalloc (block_size);
!       first_block = new_block;
      }
    else
      {
!       if (compress)
! 	{
! 	  /* Compress the current block and link it into the list.  */
! 	  compress_current_block (false);
! 	  /* Re-use the uncompressed buffer.  */
! 	  new_block = current_block;
! 	}
!       else
! 	{
! 	  /* Get a new block and link it into the list.  */
! 	  new_block = (struct lto_char_ptr_base*) xmalloc (block_size);
! 	  /* The first bytes of the block are reserved as a pointer to
! 	     the next block.  Set the chain of the full block to the
! 	     pointer to the new block.  */
! 	  lto_char_ptr_base *tptr = current_block;
! 	  tptr->ptr = (char *) new_block;
! 	}
      }
  
    /* Set the place for the next char at the first position after the
       chain to the next block.  */
!   current_pointer
      = ((char *) new_block) + sizeof (struct lto_char_ptr_base);
!   current_block = new_block;
    /* Null out the newly allocated block's pointer to the next block.  */
    new_block->ptr = NULL;
!   left_in_block = block_size - sizeof (struct lto_char_ptr_base);
! }
! 
! /* Return a zlib compression level that zlib will not reject.  Normalizes
!    the compression level from the command line flag, clamping non-default
!    values to the appropriate end of their valid range.  */
! 
! static int
! lto_normalized_zlib_level (void)
! {
!   int level = flag_lto_compression_level;
! 
!   if (level != Z_DEFAULT_COMPRESSION)
!     {
!       if (level < Z_NO_COMPRESSION)
! 	level = Z_NO_COMPRESSION;
!       else if (level > Z_BEST_COMPRESSION)
! 	level = Z_BEST_COMPRESSION;
!     }
! 
!   return level;
  }
  
+ void
+ lto_output_stream::compress_current_block (bool last)
+ {
+   int status;
+ 
+   /* If this is the first block we compress, initialize compression.  */
+   if (first_block == current_block)
+     {
+       zlib_stream = XCNEW (z_stream);
+       zlib_stream->zalloc = NULL;
+       zlib_stream->zfree = NULL;
+       zlib_stream->opaque = NULL;
+       status = deflateInit (zlib_stream, lto_normalized_zlib_level ());
+       if (status != Z_OK)
+ 	internal_error ("compressed stream: %s", zError (status));
+ 
+       current_z_block = first_block
+ 	= (lto_char_ptr_base *) xmalloc (block_size);
+       first_block->ptr = NULL;
+       zlib_stream->next_out = (unsigned char *)first_block + sizeof (lto_char_ptr_base);
+       zlib_stream->avail_out = block_size - sizeof (lto_char_ptr_base);
+     }
+ 
+   zlib_stream->next_in = (unsigned char *)current_block + sizeof (lto_char_ptr_base);
+   zlib_stream->avail_in
+     = block_size - sizeof (lto_char_ptr_base) - left_in_block;
+   do
+     {
+       if (zlib_stream->avail_out == 0)
+ 	{
+ 	  lto_char_ptr_base *new_block
+ 	      = (lto_char_ptr_base *) xmalloc (block_size);
+ 	  current_z_block->ptr = (char *)new_block;
+ 	  current_z_block = new_block;
+ 	  current_z_block->ptr = NULL;
+ 	  zlib_stream->next_out = (unsigned char *)new_block + sizeof (lto_char_ptr_base);
+ 	  zlib_stream->avail_out = block_size - sizeof (lto_char_ptr_base);
+ 	}
+ 
+       status = deflate (zlib_stream, last ? Z_FINISH : Z_NO_FLUSH);
+       if (status != Z_OK && status != Z_STREAM_END && status != Z_BUF_ERROR)
+ 	internal_error ("compressed stream: %s", zError (status));
+     }
+   while (zlib_stream->avail_in > 0
+ 	 || (last && zlib_stream->avail_out == 0));
+   gcc_assert (zlib_stream->avail_in == 0);
+ }
  
  /* 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'.
*************** streamer_write_uhwi_stream (struct lto_o
*** 238,244 ****
                              unsigned HOST_WIDE_INT work)
  {
    if (obs->left_in_block == 0)
!     lto_append_block (obs);
    char *current_pointer = obs->current_pointer;
    unsigned int left_in_block = obs->left_in_block;
    unsigned int size = 0;
--- 352,358 ----
                              unsigned HOST_WIDE_INT work)
  {
    if (obs->left_in_block == 0)
!     obs->append_block ();
    char *current_pointer = obs->current_pointer;
    unsigned int left_in_block = obs->left_in_block;
    unsigned int size = 0;
*************** streamer_write_uhwi_stream (struct lto_o
*** 258,264 ****
    if (work != 0)
      {
        obs->left_in_block = 0;
!       lto_append_block (obs);
        current_pointer = obs->current_pointer;
        left_in_block = obs->left_in_block;
        do
--- 372,378 ----
    if (work != 0)
      {
        obs->left_in_block = 0;
!       obs->append_block ();
        current_pointer = obs->current_pointer;
        left_in_block = obs->left_in_block;
        do
*************** void
*** 287,293 ****
  streamer_write_hwi_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
  {
    if (obs->left_in_block == 0)
!     lto_append_block (obs);
    char *current_pointer = obs->current_pointer;
    unsigned int left_in_block = obs->left_in_block;
    unsigned int size = 0;
--- 401,407 ----
  streamer_write_hwi_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
  {
    if (obs->left_in_block == 0)
!     obs->append_block ();
    char *current_pointer = obs->current_pointer;
    unsigned int left_in_block = obs->left_in_block;
    unsigned int size = 0;
*************** streamer_write_hwi_stream (struct lto_ou
*** 313,319 ****
    if (more)
      {
        obs->left_in_block = 0;
!       lto_append_block (obs);
        current_pointer = obs->current_pointer;
        left_in_block = obs->left_in_block;
        do
--- 427,433 ----
    if (more)
      {
        obs->left_in_block = 0;
!       obs->append_block ();
        current_pointer = obs->current_pointer;
        left_in_block = obs->left_in_block;
        do
*************** streamer_write_data_stream (struct lto_o
*** 360,366 ****
  
        /* No space left.  */
        if (obs->left_in_block == 0)
! 	lto_append_block (obs);
  
        /* Determine how many bytes to copy in this loop.  */
        if (len <= obs->left_in_block)
--- 474,480 ----
  
        /* No space left.  */
        if (obs->left_in_block == 0)
! 	obs->append_block ();
  
        /* Determine how many bytes to copy in this loop.  */
        if (len <= obs->left_in_block)
Index: gcc/lto-section-out.c
===================================================================
*** gcc/lto-section-out.c.orig	2014-08-08 14:54:20.591135967 +0200
--- gcc/lto-section-out.c	2014-08-08 15:08:56.553075658 +0200
*************** lto_begin_section (const char *name, boo
*** 80,86 ****
       data is anything other than assembler output.  The effect here is that
       we get compression of IL only in non-ltrans object files.  */
    gcc_assert (compression_stream == NULL);
!   if (compress)
      compression_stream = lto_start_compression (lto_append_data, NULL);
  }
  
--- 80,86 ----
       data is anything other than assembler output.  The effect here is that
       we get compression of IL only in non-ltrans object files.  */
    gcc_assert (compression_stream == NULL);
!   if (compress && 0)
      compression_stream = lto_start_compression (lto_append_data, NULL);
  }
  
*************** lto_write_data (const void *data, unsign
*** 115,130 ****
  void
  lto_write_stream (struct lto_output_stream *obs)
  {
-   unsigned int block_size = 1024;
    struct lto_char_ptr_base *block;
    struct lto_char_ptr_base *next_block;
-   if (!obs->first_block)
-     return;
  
!   for (block = obs->first_block; block; block = next_block)
      {
        const char *base = ((char *)block) + sizeof (struct lto_char_ptr_base);
!       unsigned int num_chars = block_size - sizeof (struct lto_char_ptr_base);
  
        /* If this is not the last block, it is full.  If it is the last
  	 block, left_in_block indicates how many chars are unoccupied in
--- 115,127 ----
  void
  lto_write_stream (struct lto_output_stream *obs)
  {
    struct lto_char_ptr_base *block;
    struct lto_char_ptr_base *next_block;
  
!   for (block = obs->get_blocks (); block; block = next_block)
      {
        const char *base = ((char *)block) + sizeof (struct lto_char_ptr_base);
!       size_t num_chars = obs->block_size - sizeof (struct lto_char_ptr_base);
  
        /* If this is not the last block, it is full.  If it is the last
  	 block, left_in_block indicates how many chars are unoccupied in
*************** lto_write_stream (struct lto_output_stre
*** 142,148 ****
        else
  	lang_hooks.lto.append_data (base, num_chars, block);
        free (block);
-       block_size *= 2;
      }
  }
  
--- 139,144 ----
*************** lto_create_simple_output_block (enum lto
*** 256,263 ****
  
    ob->section_type = section_type;
    ob->decl_state = lto_get_out_decl_state ();
!   ob->main_stream = ((struct lto_output_stream *)
! 		     xcalloc (1, sizeof (struct lto_output_stream)));
  
    return ob;
  }
--- 252,258 ----
  
    ob->section_type = section_type;
    ob->decl_state = lto_get_out_decl_state ();
!   ob->main_stream = new lto_output_stream;
  
    return ob;
  }
*************** lto_destroy_simple_output_block (struct
*** 280,286 ****
    memset (&header, 0, sizeof (struct lto_simple_header));
    header.major_version = LTO_major_version;
    header.minor_version = LTO_minor_version;
!   header.main_size = ob->main_stream->total_size;
    lto_write_data (&header, sizeof header);
  
    lto_write_stream (ob->main_stream);
--- 275,281 ----
    memset (&header, 0, sizeof (struct lto_simple_header));
    header.major_version = LTO_major_version;
    header.minor_version = LTO_minor_version;
!   header.main_size = ob->main_stream->finish ();
    lto_write_data (&header, sizeof header);
  
    lto_write_stream (ob->main_stream);
*************** lto_destroy_simple_output_block (struct
*** 289,295 ****
       writing lto info.  */
    lto_end_section ();
  
!   free (ob->main_stream);
    free (ob);
  }
  
--- 284,290 ----
       writing lto info.  */
    lto_end_section ();
  
!   delete ob->main_stream;
    free (ob);
  }
  
Index: gcc/data-streamer.h
===================================================================
*** gcc/data-streamer.h.orig	2014-08-08 14:54:20.592135967 +0200
--- gcc/data-streamer.h	2014-08-08 15:08:56.553075658 +0200
*************** const char *bp_unpack_string (struct dat
*** 85,90 ****
--- 85,91 ----
  unsigned HOST_WIDE_INT streamer_read_uhwi (struct lto_input_block *);
  HOST_WIDE_INT streamer_read_hwi (struct lto_input_block *);
  gcov_type streamer_read_gcov_count (struct lto_input_block *);
+ void streamer_read_data_stream (struct lto_input_block *, void *, size_t);
  
  /* Returns a new bit-packing context for bit-packing into S.  */
  static inline struct bitpack_d
*************** streamer_write_char_stream (struct lto_o
*** 182,188 ****
  {
    /* No space left.  */
    if (obs->left_in_block == 0)
!     lto_append_block (obs);
  
    /* Write the actual character.  */
    char *current_pointer = obs->current_pointer;
--- 183,189 ----
  {
    /* No space left.  */
    if (obs->left_in_block == 0)
!     obs->append_block ();
  
    /* Write the actual character.  */
    char *current_pointer = obs->current_pointer;
*************** streamer_write_char_stream (struct lto_o
*** 198,206 ****
  static inline unsigned char
  streamer_read_uchar (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
--- 199,211 ----
  static inline unsigned char
  streamer_read_uchar (struct lto_input_block *ib)
  {
!   /* No data left.  */
!   if (ib->left_in_block == 0)
!     ib->append_block ();
! 
!   /* Read a character.  */
!   ib->left_in_block--;
!   return *(ib->current_pointer++);
  }
  
  /* Output VAL into OBS and verify it is in range MIN...MAX that is supposed
Index: gcc/lto-opts.c
===================================================================
*** gcc/lto-opts.c.orig	2014-08-08 14:54:20.591135967 +0200
--- gcc/lto-opts.c	2014-08-08 15:08:56.554075658 +0200
*************** along with GCC; see the file COPYING3.
*** 37,42 ****
--- 37,43 ----
  #include "common/common-target.h"
  #include "diagnostic.h"
  #include "lto-streamer.h"
+ #include "data-streamer.h"
  #include "toplev.h"
  
  /* Append the option piece OPT to the COLLECT_GCC_OPTIONS string
Index: gcc/lto-streamer-out.c
===================================================================
*** gcc/lto-streamer-out.c.orig	2014-08-08 14:54:20.591135967 +0200
--- gcc/lto-streamer-out.c	2014-08-11 10:12:29.021454701 +0200
*************** create_output_block (enum lto_section_ty
*** 80,91 ****
  
    ob->section_type = section_type;
    ob->decl_state = lto_get_out_decl_state ();
!   ob->main_stream = XCNEW (struct lto_output_stream);
!   ob->string_stream = XCNEW (struct lto_output_stream);
    ob->writer_cache = streamer_tree_cache_create (!flag_wpa, true, false);
  
    if (section_type == LTO_section_function_body)
!     ob->cfg_stream = XCNEW (struct lto_output_stream);
  
    clear_line_info (ob);
  
--- 80,93 ----
  
    ob->section_type = section_type;
    ob->decl_state = lto_get_out_decl_state ();
!   ob->main_stream = new lto_output_stream;
!   // The way we use this stream prevents its compression as we basically
!   // perform random access
!   ob->string_stream = new lto_output_stream (2 * 1024 * 1024, false);
    ob->writer_cache = streamer_tree_cache_create (!flag_wpa, true, false);
  
    if (section_type == LTO_section_function_body)
!     ob->cfg_stream = new lto_output_stream;
  
    clear_line_info (ob);
  
*************** destroy_output_block (struct output_bloc
*** 106,115 ****
    delete ob->string_hash_table;
    ob->string_hash_table = NULL;
  
!   free (ob->main_stream);
!   free (ob->string_stream);
    if (section_type == LTO_section_function_body)
!     free (ob->cfg_stream);
  
    streamer_tree_cache_delete (ob->writer_cache);
    obstack_free (&ob->obstack, NULL);
--- 108,117 ----
    delete ob->string_hash_table;
    ob->string_hash_table = NULL;
  
!   delete ob->main_stream;
!   delete ob->string_stream;
    if (section_type == LTO_section_function_body)
!     delete ob->cfg_stream;
  
    streamer_tree_cache_delete (ob->writer_cache);
    obstack_free (&ob->obstack, NULL);
*************** produce_asm (struct output_block *ob, tr
*** 1890,1898 ****
    header.minor_version = LTO_minor_version;
  
    if (section_type == LTO_section_function_body)
!     header.cfg_size = ob->cfg_stream->total_size;
!   header.main_size = ob->main_stream->total_size;
!   header.string_size = ob->string_stream->total_size;
    lto_write_data (&header, sizeof header);
  
    /* Put all of the gimple and the string table out the asm file as a
--- 1892,1900 ----
    header.minor_version = LTO_minor_version;
  
    if (section_type == LTO_section_function_body)
!     header.cfg_size = ob->cfg_stream->finish ();
!   header.main_size = ob->main_stream->finish ();
!   header.string_size = ob->string_stream->finish ();
    lto_write_data (&header, sizeof header);
  
    /* Put all of the gimple and the string table out the asm file as a
*************** lto_output_toplevel_asms (void)
*** 2124,2131 ****
    header.major_version = LTO_major_version;
    header.minor_version = LTO_minor_version;
  
!   header.main_size = ob->main_stream->total_size;
!   header.string_size = ob->string_stream->total_size;
    lto_write_data (&header, sizeof header);
  
    /* Put all of the gimple and the string table out the asm file as a
--- 2126,2133 ----
    header.major_version = LTO_major_version;
    header.minor_version = LTO_minor_version;
  
!   header.main_size = ob->main_stream->finish ();
!   header.string_size = ob->string_stream->finish ();
    lto_write_data (&header, sizeof header);
  
    /* Put all of the gimple and the string table out the asm file as a
*************** produce_asm_for_decls (void)
*** 2673,2680 ****
      }
    header.decl_state_size = decl_state_size;
  
!   header.main_size = ob->main_stream->total_size;
!   header.string_size = ob->string_stream->total_size;
  
    lto_write_data (&header, sizeof header);
  
--- 2675,2682 ----
      }
    header.decl_state_size = decl_state_size;
  
!   header.main_size = ob->main_stream->finish ();
!   header.string_size = ob->string_stream->finish ();
  
    lto_write_data (&header, sizeof header);
  
Index: gcc/lto-streamer.h
===================================================================
*** gcc/lto-streamer.h.orig	2014-08-08 14:54:20.592135967 +0200
--- gcc/lto-streamer.h	2014-08-11 10:33:24.762368245 +0200
*************** public:
*** 313,327 ****
    /* Special constructor for the string table, it abuses this to
       do random access but use the uhwi decoder.  */
    lto_input_block (const char *data_, unsigned int p_, unsigned int len_)
!       : data (data_), p (p_), len (len_) {}
!   lto_input_block (const char *data_, unsigned int len_)
!       : data (data_), p (0), len (len_) {}
  
    const char *data;
    unsigned int p;
    unsigned int len;
  };
  
  
  /* The is the first part of the record for a function or constructor
     in the .o file.  */
--- 313,347 ----
    /* Special constructor for the string table, it abuses this to
       do random access but use the uhwi decoder.  */
    lto_input_block (const char *data_, unsigned int p_, unsigned int len_)
!       : current_pointer (data_ + p_), left_in_block (len_),
!         buffer_size (0), compress (false),
!         data (NULL), p (0), len (0) {};
!   lto_input_block (const char *data_, unsigned int len_, bool compress_ = true)
!       : current_pointer (NULL), left_in_block (0),
!         buffer_size (2 * 1024 * 1024), compress (compress_),
!         data (data_), p (0), len (len_), zbuf (NULL), zlib_stream (NULL) {};
!   ~lto_input_block ();
!   void append_block ();
!   inline bool eof ();
!   const char *current_pointer;
!   unsigned int left_in_block;
  
+ private:
+   const size_t buffer_size;
+   const bool compress;
    const char *data;
    unsigned int p;
    unsigned int len;
+   char *zbuf;
+   struct z_stream_s *zlib_stream;
  };
  
+ inline bool
+ lto_input_block::eof ()
+ {
+   return left_in_block == 0 && len == p;
+ }
+ 
  
  /* The is the first part of the record for a function or constructor
     in the .o file.  */
*************** struct lto_char_ptr_base
*** 538,547 ****
     The entire structure should be zeroed when created.  The record
     consists of a set of blocks.  The first sizeof (ptr) bytes are used
     as a chain, and the rest store the bytes to be written.  */
! struct lto_output_stream
  {
!   /* The pointer to the first block in the stream.  */
!   struct lto_char_ptr_base * first_block;
  
    /* The pointer to the last and current block in the stream.  */
    struct lto_char_ptr_base * current_block;
--- 558,580 ----
     The entire structure should be zeroed when created.  The record
     consists of a set of blocks.  The first sizeof (ptr) bytes are used
     as a chain, and the rest store the bytes to be written.  */
! class lto_output_stream
  {
! public:
!   lto_output_stream (size_t block_size_ = 2 * 1024 * 1024,
! 		     bool compress_ = true)
!       : current_block (NULL), current_pointer (NULL),
!         left_in_block (0), block_size (block_size_), total_size (0),
!         first_block (NULL), current_z_block (NULL), compress (compress_),
! 	zlib_stream (NULL)
!   {
!     gcc_assert (block_size > sizeof (lto_char_ptr_base));
!   }
! 
!   unsigned int finish();
!   lto_char_ptr_base *get_blocks ();
! 
!   void append_block ();
  
    /* The pointer to the last and current block in the stream.  */
    struct lto_char_ptr_base * current_block;
*************** struct lto_output_stream
*** 552,562 ****
    /* The number of characters left in the current block.  */
    unsigned int left_in_block;
  
!   /* The block size of the last block allocated.  */
!   unsigned int block_size;
  
!   /* The total number of characters written.  */
    unsigned int total_size;
  };
  
  /* A simple output block.  This can be used for simple IPA passes that
--- 585,608 ----
    /* The number of characters left in the current block.  */
    unsigned int left_in_block;
  
!   /* The block size to use.  */
!   const unsigned int block_size;
  
!   /* The total number of uncompressed characters written.  */
    unsigned int total_size;
+ 
+ private:
+   void compress_current_block (bool);
+ 
+   /* The pointer to the first block in the stream.  */
+   struct lto_char_ptr_base * first_block;
+ 
+   struct lto_char_ptr_base * current_z_block;
+ 
+   /* Whether to compress this stream.  */
+   const bool compress;
+ 
+   struct z_stream_s *zlib_stream;
  };
  
  /* A simple output block.  This can be used for simple IPA passes that
*************** extern struct lto_in_decl_state *lto_get
*** 705,711 ****
  				      struct lto_file_decl_data *, tree);
  extern void lto_free_function_in_decl_state (struct lto_in_decl_state *);
  extern void lto_free_function_in_decl_state_for_node (symtab_node *);
- 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;
--- 751,756 ----
*************** extern void lto_push_out_decl_state (str
*** 740,746 ****
  extern struct lto_out_decl_state *lto_pop_out_decl_state (void);
  extern void lto_record_function_out_decl_state (tree,
  						struct lto_out_decl_state *);
- extern void lto_append_block (struct lto_output_stream *);
  
  
  /* In lto-streamer.c.  */
--- 785,790 ----
Index: gcc/lto-section-in.c
===================================================================
*** gcc/lto-section-in.c.orig	2014-08-08 14:54:20.592135967 +0200
--- gcc/lto-section-in.c	2014-08-08 15:08:56.567075657 +0200
*************** lto_get_section_data (struct lto_file_de
*** 153,159 ****
  
    /* FIXME lto: WPA mode does not write compressed sections, so for now
       suppress uncompression if flag_ltrans.  */
!   if (!flag_ltrans)
      {
        /* Create a mapping header containing the underlying data and length,
  	 and prepend this to the uncompression buffer.  The uncompressed data
--- 153,159 ----
  
    /* FIXME lto: WPA mode does not write compressed sections, so for now
       suppress uncompression if flag_ltrans.  */
!   if (!flag_ltrans && 0)
      {
        /* Create a mapping header containing the underlying data and length,
  	 and prepend this to the uncompression buffer.  The uncompressed data
*************** lto_free_section_data (struct lto_file_d
*** 200,206 ****
  
    /* FIXME lto: WPA mode does not write compressed sections, so for now
       suppress uncompression mapping if flag_ltrans.  */
!   if (flag_ltrans)
      {
        (free_section_f) (file_data, section_type, name, data, len);
        return;
--- 200,206 ----
  
    /* FIXME lto: WPA mode does not write compressed sections, so for now
       suppress uncompression mapping if flag_ltrans.  */
!   if (flag_ltrans || 1)
      {
        (free_section_f) (file_data, section_type, name, data, len);
        return;
*************** lto_free_function_in_decl_state_for_node
*** 448,462 ****
  }
  
  
- /* Report read pass end of the section.  */
- 
- void
- lto_section_overrun (struct lto_input_block *ib)
- {
-   fatal_error ("bytecode stream: trying to read %d bytes "
- 	       "after the end of the input buffer", ib->p - ib->len);
- }
- 
  /* Report out of range value.  */
  
  void
--- 448,453 ----
Index: gcc/lto-cgraph.c
===================================================================
*** gcc/lto-cgraph.c.orig	2014-08-08 14:54:20.592135967 +0200
--- gcc/lto-cgraph.c	2014-08-08 15:08:56.567075657 +0200
*************** lto_output_node (struct lto_simple_outpu
*** 484,490 ****
      comdat = IDENTIFIER_POINTER (group);
    else
      comdat = "";
!   streamer_write_data_stream (ob->main_stream, comdat, strlen (comdat) + 1);
  
    if (group)
      {
--- 484,491 ----
      comdat = IDENTIFIER_POINTER (group);
    else
      comdat = "";
!   streamer_write_uhwi_stream (ob->main_stream, strlen (comdat));
!   streamer_write_data_stream (ob->main_stream, comdat, strlen (comdat));
  
    if (group)
      {
*************** lto_output_node (struct lto_simple_outpu
*** 542,548 ****
    bp_pack_enum (&bp, ld_plugin_symbol_resolution,
  	        LDPR_NUM_KNOWN, node->resolution);
    streamer_write_bitpack (&bp);
!   streamer_write_data_stream (ob->main_stream, section, strlen (section) + 1);
  
    if (node->thunk.thunk_p && !boundary_p)
      {
--- 543,550 ----
    bp_pack_enum (&bp, ld_plugin_symbol_resolution,
  	        LDPR_NUM_KNOWN, node->resolution);
    streamer_write_bitpack (&bp);
!   streamer_write_uhwi_stream (ob->main_stream, strlen (section));
!   streamer_write_data_stream (ob->main_stream, section, strlen (section));
  
    if (node->thunk.thunk_p && !boundary_p)
      {
*************** lto_output_varpool_node (struct lto_simp
*** 618,624 ****
      comdat = IDENTIFIER_POINTER (group);
    else
      comdat = "";
!   streamer_write_data_stream (ob->main_stream, comdat, strlen (comdat) + 1);
  
    if (group)
      {
--- 620,627 ----
      comdat = IDENTIFIER_POINTER (group);
    else
      comdat = "";
!   streamer_write_uhwi_stream (ob->main_stream, strlen (comdat));
!   streamer_write_data_stream (ob->main_stream, comdat, strlen (comdat));
  
    if (group)
      {
*************** lto_output_varpool_node (struct lto_simp
*** 636,642 ****
    section = node->get_section ();
    if (!section)
      section = "";
!   streamer_write_data_stream (ob->main_stream, section, strlen (section) + 1);
  
    streamer_write_enum (ob->main_stream, ld_plugin_symbol_resolution,
  		       LDPR_NUM_KNOWN, node->resolution);
--- 639,646 ----
    section = node->get_section ();
    if (!section)
      section = "";
!   streamer_write_uhwi_stream (ob->main_stream, strlen (section));
!   streamer_write_data_stream (ob->main_stream, section, strlen (section));
  
    streamer_write_enum (ob->main_stream, ld_plugin_symbol_resolution,
  		       LDPR_NUM_KNOWN, node->resolution);
*************** output_symtab (void)
*** 988,1025 ****
  static tree
  read_identifier (struct lto_input_block *ib)
  {
!   unsigned int len = strnlen (ib->data + ib->p, ib->len - ib->p - 1);
!   tree id;
! 
!   if (ib->data[ib->p + len])
!     lto_section_overrun (ib);
    if (!len)
!     {
!       ib->p++;
!       return NULL;
!     }
!   id = get_identifier (ib->data + ib->p);
!   ib->p += len + 1;
!   return id;
  }
  
  /* Return string encoded in IB, NULL if string is empty.  */
  
! static const char *
  read_string (struct lto_input_block *ib)
  {
!   unsigned int len = strnlen (ib->data + ib->p, ib->len - ib->p - 1);
!   const char *str;
! 
!   if (ib->data[ib->p + len])
!     lto_section_overrun (ib);
    if (!len)
!     {
!       ib->p++;
!       return NULL;
!     }
!   str = ib->data + ib->p;
!   ib->p += len + 1;
    return str;
  }
  
--- 992,1018 ----
  static tree
  read_identifier (struct lto_input_block *ib)
  {
!   unsigned int len = streamer_read_uhwi (ib);
    if (!len)
!     return NULL;
!   char *str = XALLOCAVEC (char, len + 1);
!   for (unsigned i = 0; i < len; ++i)
!     str[i] = streamer_read_uchar (ib);
!   str[len] = '\0';
!   return get_identifier (str);
  }
  
  /* Return string encoded in IB, NULL if string is empty.  */
  
! static char *
  read_string (struct lto_input_block *ib)
  {
!   unsigned int len = streamer_read_uhwi (ib);
    if (!len)
!     return NULL;
!   char *str = (char *)xmalloc (len + 1);
!   streamer_read_data_stream (ib, str, len);
!   str[len] = '\0';
    return str;
  }
  
*************** input_node (struct lto_file_decl_data *f
*** 1113,1119 ****
    int order;
    int i, count;
    tree group;
!   const char *section;
  
    order = streamer_read_hwi (ib) + order_base;
    clone_ref = streamer_read_hwi (ib);
--- 1106,1112 ----
    int order;
    int i, count;
    tree group;
!   char *section;
  
    order = streamer_read_hwi (ib) + order_base;
    clone_ref = streamer_read_hwi (ib);
*************** input_node (struct lto_file_decl_data *f
*** 1190,1196 ****
      node->same_comdat_group = (symtab_node *) (intptr_t) LCC_NOT_FOUND;
    section = read_string (ib);
    if (section)
!     node->set_section_for_node (section);
  
    if (node->thunk.thunk_p)
      {
--- 1183,1192 ----
      node->same_comdat_group = (symtab_node *) (intptr_t) LCC_NOT_FOUND;
    section = read_string (ib);
    if (section)
!     {
!       node->set_section_for_node (section);
!       free (section);
!     }
  
    if (node->thunk.thunk_p)
      {
*************** input_varpool_node (struct lto_file_decl
*** 1227,1233 ****
    int ref = LCC_NOT_FOUND;
    int order;
    tree group;
!   const char *section;
  
    order = streamer_read_hwi (ib) + order_base;
    decl_index = streamer_read_uhwi (ib);
--- 1223,1229 ----
    int ref = LCC_NOT_FOUND;
    int order;
    tree group;
!   char *section;
  
    order = streamer_read_hwi (ib) + order_base;
    decl_index = streamer_read_uhwi (ib);
*************** input_varpool_node (struct lto_file_decl
*** 1280,1286 ****
      node->same_comdat_group = (symtab_node *) (intptr_t) LCC_NOT_FOUND;
    section = read_string (ib);
    if (section)
!     node->set_section_for_node (section);
    node->resolution = streamer_read_enum (ib, ld_plugin_symbol_resolution,
  					        LDPR_NUM_KNOWN);
    gcc_assert (flag_ltrans
--- 1276,1285 ----
      node->same_comdat_group = (symtab_node *) (intptr_t) LCC_NOT_FOUND;
    section = read_string (ib);
    if (section)
!     {
!       node->set_section_for_node (section);
!       free (section);
!     }
    node->resolution = streamer_read_enum (ib, ld_plugin_symbol_resolution,
  					        LDPR_NUM_KNOWN);
    gcc_assert (flag_ltrans
Index: gcc/data-streamer-in.c
===================================================================
*** gcc/data-streamer-in.c.orig	2014-08-08 14:54:20.592135967 +0200
--- gcc/data-streamer-in.c	2014-08-11 11:02:23.197248555 +0200
*************** along with GCC; see the file COPYING3.
*** 22,27 ****
--- 22,32 ----
  
  #include "config.h"
  #include "system.h"
+ /* zlib.h includes other system headers.  Those headers may test feature
+    test macros.  config.h may define feature test macros.  For this reason,
+    zlib.h needs to be included after, rather than before, config.h and
+    system.h.  */
+ #include <zlib.h>
  #include "coretypes.h"
  #include "diagnostic.h"
  #include "tree.h"
*************** along with GCC; see the file COPYING3.
*** 33,38 ****
--- 38,101 ----
  #include "gimple.h"
  #include "data-streamer.h"
  
+ 
+ void
+ lto_input_block::append_block ()
+ {
+   gcc_assert (left_in_block == 0 && data);
+   if (!compress)
+     {
+       current_pointer = data + p;
+       left_in_block = len - p;
+       p += left_in_block;
+     }
+   else
+     {
+       int status;
+ 
+       if (!zlib_stream)
+ 	{
+ 	  zlib_stream = XCNEW (z_stream);
+ 	  zlib_stream->zalloc = NULL;
+ 	  zlib_stream->zfree = NULL;
+ 	  zlib_stream->opaque = NULL;
+ 	  zlib_stream->avail_in = len;
+ 	  zlib_stream->next_in = (Bytef*)const_cast<char *>(data + p);
+ 	  status = inflateInit (zlib_stream);
+ 	  if (status != Z_OK)
+ 	    internal_error ("compressed stream: %s", zError (status));
+ 	  zbuf = XNEWVEC (char, buffer_size);
+ 	}
+ 
+       zlib_stream->avail_out = buffer_size;
+       zlib_stream->next_out = (Bytef*)zbuf;
+       status = inflate (zlib_stream, Z_NO_FLUSH);
+       if (status != Z_OK && status != Z_STREAM_END)
+ 	internal_error ("compressed stream: %s", zError (status));
+ 
+       current_pointer = zbuf;
+       left_in_block = buffer_size - zlib_stream->avail_out;
+       p = len - zlib_stream->avail_in;
+     }
+   if (left_in_block == 0)
+     fatal_error ("bytecode stream: trying to read bytes "
+ 		 "after the end of the input buffer");
+ }
+ 
+ lto_input_block::~lto_input_block ()
+ {
+   if (compress)
+     {
+       if (zlib_stream)
+ 	{
+ 	  inflateEnd (zlib_stream);
+ 	  free (zlib_stream);
+ 	}
+       if (zbuf)
+ 	free (zbuf);
+     }
+ }
+ 
  /* Read a string from the string table in DATA_IN using input block
     IB.  Write the length to RLEN.  */
  
*************** string_for_index (struct data_in *data_i
*** 49,62 ****
      }
  
    /* Get the string stored at location LOC in DATA_IN->STRINGS.  */
!   lto_input_block str_tab (data_in->strings, loc - 1, data_in->strings_len);
    len = streamer_read_uhwi (&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;
  }
--- 112,126 ----
      }
  
    /* Get the string stored at location LOC in DATA_IN->STRINGS.  */
!   lto_input_block str_tab (data_in->strings, loc - 1,
! 			   data_in->strings_len - (loc - 1));
    len = streamer_read_uhwi (&str_tab);
    *rlen = len;
  
!   if (str_tab.left_in_block < len)
      internal_error ("bytecode stream: string too long for the string table");
  
!   result = str_tab.current_pointer;
  
    return result;
  }
*************** bp_unpack_string (struct data_in *data_i
*** 125,157 ****
  unsigned HOST_WIDE_INT
  streamer_read_uhwi (struct lto_input_block *ib)
  {
!   unsigned HOST_WIDE_INT result;
!   int shift;
!   unsigned HOST_WIDE_INT byte;
!   unsigned int p = ib->p;
!   unsigned int len = ib->len;
  
!   const char *data = ib->data;
!   result = data[p++];
!   if ((result & 0x80) != 0)
!     {
!       result &= 0x7f;
!       shift = 7;
!       do
  	{
! 	  byte = data[p++];
! 	  result |= (byte & 0x7f) << shift;
! 	  shift += 7;
  	}
!       while ((byte & 0x80) != 0);
      }
- 
-   /* We check for section overrun after the fact for performance reason.  */
-   if (p > len)
-     lto_section_overrun (ib);
- 
-   ib->p = p;
-   return result;
  }
  
  
--- 189,240 ----
  unsigned HOST_WIDE_INT
  streamer_read_uhwi (struct lto_input_block *ib)
  {
!   if (ib->left_in_block >= sizeof (unsigned HOST_WIDE_INT) + 2)
!     {
!       const char *current_pointer = ib->current_pointer;
!       int left_in_block = ib->left_in_block;
  
!       unsigned HOST_WIDE_INT result = *(current_pointer++);
!       --left_in_block;
!       if ((result & 0x80) != 0)
  	{
! 	  unsigned HOST_WIDE_INT byte;
! 	  int shift;
! 	  result &= 0x7f;
! 	  shift = 7;
! 	  do
! 	    {
! 	      byte = *(current_pointer++);
! 	      --left_in_block;
! 	      result |= (byte & 0x7f) << shift;
! 	      shift += 7;
! 	    }
! 	  while ((byte & 0x80) != 0);
  	}
!       gcc_checking_assert (left_in_block >= 0);
!       ib->current_pointer = current_pointer;
!       ib->left_in_block = left_in_block;
!       return result;
!     }
!   else
!     {
!       unsigned HOST_WIDE_INT result = streamer_read_uchar (ib);
!       if ((result & 0x80) != 0)
! 	{
! 	  unsigned HOST_WIDE_INT byte;
! 	  int shift;
! 	  result &= 0x7f;
! 	  shift = 7;
! 	  do
! 	    {
! 	      byte = streamer_read_uchar (ib);
! 	      result |= (byte & 0x7f) << shift;
! 	      shift += 7;
! 	    }
! 	  while ((byte & 0x80) != 0);
! 	}
!       return result;
      }
  }
  
  
*************** streamer_read_hwi (struct lto_input_bloc
*** 164,180 ****
    int shift = 0;
    unsigned HOST_WIDE_INT byte;
  
!   while (true)
      {
!       byte = streamer_read_uchar (ib);
!       result |= (byte & 0x7f) << shift;
!       shift += 7;
!       if ((byte & 0x80) == 0)
  	{
! 	  if ((shift < HOST_BITS_PER_WIDE_INT) && (byte & 0x40))
! 	    result |= - (HOST_WIDE_INT_1U << shift);
  
! 	  return result;
  	}
      }
  }
--- 247,288 ----
    int shift = 0;
    unsigned HOST_WIDE_INT byte;
  
!   if (ib->left_in_block >= sizeof (unsigned HOST_WIDE_INT) + 3)
      {
!       const char *current_pointer = ib->current_pointer;
!       int left_in_block = ib->left_in_block;
!       while (true)
  	{
! 	  byte = *(current_pointer++);
! 	  --left_in_block;
! 	  result |= (byte & 0x7f) << shift;
! 	  shift += 7;
! 	  if ((byte & 0x80) == 0)
! 	    {
! 	      if ((shift < HOST_BITS_PER_WIDE_INT) && (byte & 0x40))
! 		result |= - (HOST_WIDE_INT_1U << shift);
! 
! 	      gcc_checking_assert (left_in_block >= 0);
! 	      ib->current_pointer = current_pointer;
! 	      ib->left_in_block = left_in_block;
! 	      return result;
! 	    }
! 	}
!     }
!   else
!     {
!       while (true)
! 	{
! 	  byte = streamer_read_uchar (ib);
! 	  result |= (byte & 0x7f) << shift;
! 	  shift += 7;
! 	  if ((byte & 0x80) == 0)
! 	    {
! 	      if ((shift < HOST_BITS_PER_WIDE_INT) && (byte & 0x40))
! 		result |= - (HOST_WIDE_INT_1U << shift);
  
! 	      return result;
! 	    }
  	}
      }
  }
*************** streamer_read_gcov_count (struct lto_inp
*** 188,190 ****
--- 296,328 ----
    gcc_assert (ret >= 0);
    return ret;
  }
+ 
+ /* Read raw DATA of length LEN from IB.  */
+ 
+ void
+ streamer_read_data_stream (struct lto_input_block *ib, void *data,
+ 			   size_t len)
+ {
+   while (len)
+     {
+       size_t copy;
+ 
+       /* No space left.  */
+       if (ib->left_in_block == 0)
+ 	ib->append_block ();
+ 
+       /* Determine how many bytes to copy in this loop.  */
+       if (len <= ib->left_in_block)
+ 	copy = len;
+       else
+ 	copy = ib->left_in_block;
+ 
+       /* Copy the data and do bookkeeping.  */
+       memcpy (data, ib->current_pointer, copy);
+       ib->current_pointer += copy;
+       ib->left_in_block -= copy;
+       data = (char *) data + copy;
+       len -= copy;
+     }
+ }
+ 
Index: gcc/lto/lto.c
===================================================================
*** gcc/lto/lto.c.orig	2014-08-08 14:54:20.592135967 +0200
--- gcc/lto/lto.c	2014-08-08 15:08:56.568075657 +0200
*************** lto_read_decls (struct lto_file_decl_dat
*** 1859,1865 ****
       internal types that should not be merged.  */
  
    /* Read the global declarations and types.  */
!   while (ib_main.p < ib_main.len)
      {
        tree t;
        unsigned from = data_in->reader_cache->nodes.length ();
--- 1859,1865 ----
       internal types that should not be merged.  */
  
    /* Read the global declarations and types.  */
!   while (!ib_main.eof ())
      {
        tree t;
        unsigned from = data_in->reader_cache->nodes.length ();

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

* Re: [PATCH][LTO] Streamer re-org (what's left)
       [not found]     ` <20140814163337.GA27831@kam.mff.cuni.cz>
@ 2014-08-15  7:44       ` Richard Biener
  2014-08-15  8:14         ` Jan Hubicka
  0 siblings, 1 reply; 7+ messages in thread
From: Richard Biener @ 2014-08-15  7:44 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches

On Thu, 14 Aug 2014, Jan Hubicka wrote:

> > 
> > And this fixes the thinko in zlib use.
> > 
> > du  /tmp/*ltrans* | awk '{ sum += $1 } END { print sum }'
> > stage3 cc1 WPA ltrans file size 178740 (patched)
> > stage3 cc1 WPA ltrans file size 460068 (unpatched)
> 
> The patch works now with Firefox.  For libxul linktime I get
> 
> Unpatched:
> real    5m59.514s
> user    47m55.468s
> sys     4m36.717s
> 
> WPA is 125s, stream in 30s, stream out 5.98s.
> Note that usually WPA is around 80-90s, it is now up because of
> devirtualization having too many contextes (it takes 40s). Will fix that next
> week.
> 
> patched:
> real    6m12.437s
> user    51m18.829s
> sys     4m30.809s
> 
> WPA is 129s, stream in 29.23s, stream out 12.16s.
> 
> Patched + fast compression
> real    6m4.383s
> user    49m15.123s
> sys     4m31.166s
> 
> WPA is 124s, stream in 29.39, stream out 7.33s.
> 
> So I guess the difference is close to noise factor now. I am sure there 
> are better compression backends than zlib for this purpose but it seems 
> to work well enough.

Yeah, we might want to pursue that lz4 thing at some point.

I'll take the above as an ok to go forward with this change
(moving compression to the "stream" level from section level).

Richard.

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

* Re: [PATCH][LTO] Streamer re-org (what's left)
  2014-08-15  7:44       ` Richard Biener
@ 2014-08-15  8:14         ` Jan Hubicka
  2014-08-15  8:47           ` Richard Biener
  0 siblings, 1 reply; 7+ messages in thread
From: Jan Hubicka @ 2014-08-15  8:14 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jan Hubicka, gcc-patches

> > patched:
> > real    6m12.437s
> > user    51m18.829s
> > sys     4m30.809s
> > 
> > WPA is 129s, stream in 29.23s, stream out 12.16s.
> > 
> > Patched + fast compression
> > real    6m4.383s
> > user    49m15.123s
> > sys     4m31.166s
> > 
> > WPA is 124s, stream in 29.39, stream out 7.33s.
> > 
> > So I guess the difference is close to noise factor now. I am sure there 
> > are better compression backends than zlib for this purpose but it seems 
> > to work well enough.
> 
> Yeah, we might want to pursue that lz4 thing at some point.
> 
> I'll take the above as an ok to go forward with this change
> (moving compression to the "stream" level from section level).

Yep, I would go with fast compression for wpa->ltrans objects. Those are going
to be consumed just once and the compression level increase is probably not
terrible (i.e. not as bad as current growth caused by not compressing strings
:)

3-fold decrease in /tmp usage is nice, but it +-10% does not matter much.  BTW
if I remember well, zlib algorithm works on 64Kb blocks independently, so
perhaps havin 2MB buffer is unnecessarily large.

Honza
> 
> Richard.

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

* Re: [PATCH][LTO] Streamer re-org (what's left)
  2014-08-15  8:14         ` Jan Hubicka
@ 2014-08-15  8:47           ` Richard Biener
  2014-08-15 18:43             ` Jan Hubicka
  0 siblings, 1 reply; 7+ messages in thread
From: Richard Biener @ 2014-08-15  8:47 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches

On Fri, 15 Aug 2014, Jan Hubicka wrote:

> > > patched:
> > > real    6m12.437s
> > > user    51m18.829s
> > > sys     4m30.809s
> > > 
> > > WPA is 129s, stream in 29.23s, stream out 12.16s.
> > > 
> > > Patched + fast compression
> > > real    6m4.383s
> > > user    49m15.123s
> > > sys     4m31.166s
> > > 
> > > WPA is 124s, stream in 29.39, stream out 7.33s.
> > > 
> > > So I guess the difference is close to noise factor now. I am sure there 
> > > are better compression backends than zlib for this purpose but it seems 
> > > to work well enough.
> > 
> > Yeah, we might want to pursue that lz4 thing at some point.
> > 
> > I'll take the above as an ok to go forward with this change
> > (moving compression to the "stream" level from section level).
> 
> Yep, I would go with fast compression for wpa->ltrans objects. Those are going
> to be consumed just once and the compression level increase is probably not
> terrible (i.e. not as bad as current growth caused by not compressing strings
> :)
> 
> 3-fold decrease in /tmp usage is nice, but it +-10% does not matter much.  BTW
> if I remember well, zlib algorithm works on 64Kb blocks independently, so
> perhaps havin 2MB buffer is unnecessarily large.

Yeah, the 2MB was just a "guess", I'll change it to 64k blocks.  Note
the original code exponentially increased block size to not have
too many blocks (for whatever reason).  A 800MB compressed decl section
would need 12800 64k blocks.  But in the end it matters only that
the block allocations are "efficient" for the memory allocator
(so don't allocate 1-byte blocks).  Our internal overhead is
one pointer (to point to the next buffer).

Of course in the end I want to implement streaming right into the
file rather than queuing up the whole compressed data (or
mmapping it).

Btw, I'll first try to get rid of the separate string section
which would also make it compressed again and be less awkwardly
abusing the data-streamer.

Richard.

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

* Re: [PATCH][LTO] Streamer re-org (what's left)
  2014-08-15  8:47           ` Richard Biener
@ 2014-08-15 18:43             ` Jan Hubicka
  0 siblings, 0 replies; 7+ messages in thread
From: Jan Hubicka @ 2014-08-15 18:43 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jan Hubicka, gcc-patches

> 
> Yeah, the 2MB was just a "guess", I'll change it to 64k blocks.  Note
> the original code exponentially increased block size to not have
> too many blocks (for whatever reason).  A 800MB compressed decl section
> would need 12800 64k blocks.  But in the end it matters only that
> the block allocations are "efficient" for the memory allocator
> (so don't allocate 1-byte blocks).  Our internal overhead is
> one pointer (to point to the next buffer).
> 
> Of course in the end I want to implement streaming right into the
> file rather than queuing up the whole compressed data (or
> mmapping it).

Yep, would be nice for WPA stream out memory usage. Also getting rid of the
gcc->gas->object file way for slim LTO files may be huge win for kernel
times...
> 
> Btw, I'll first try to get rid of the separate string section
> which would also make it compressed again and be less awkwardly
> abusing the data-streamer.

Sounds good :)

Honza
> 
> Richard.

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

end of thread, other threads:[~2014-08-15 18:43 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-07 11:50 [PATCH][LTO] Streamer re-org (what's left) Richard Biener
2014-08-07 13:50 ` Richard Biener
2014-08-11  9:11   ` Richard Biener
     [not found]     ` <20140814163337.GA27831@kam.mff.cuni.cz>
2014-08-15  7:44       ` Richard Biener
2014-08-15  8:14         ` Jan Hubicka
2014-08-15  8:47           ` Richard Biener
2014-08-15 18:43             ` Jan Hubicka

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).