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 ();

Reply via email to