[PATCH] LTO streamer reorg - try to reduce WPA memory use

Richard Biener rguenther@suse.de
Tue Jul 29 13:57:00 GMT 2014


On Tue, 29 Jul 2014, Richard Biener wrote:

> 
> This re-organizes the LTO streamer to do compression transparently
> in the data-streamer routines (and disables section compression
> by defaulting to -flto-compression-level=0).  This avoids
> keeping the whole uncompressed sections in memory, only retaining
> the compressed ones.
> 
> The downside is that we lose compression of at least the string
> parts (they are abusing the streaming interface quite awkwardly
> and doing random-accesses with offsets into the uncompressed
> section).  With a little bit of surgery we can get that back I
> think (but we'd have to keep the uncompressed piece in memory
> somewhere which means losing the memory use advantage).
> 
> Very lightly tested sofar (running lto.exp).  I'll try a LTO
> bootstrap now.
> 
> I wonder what the change is on WPA memory use for larger
> projects and what the effect on object file size is.

Updated patch passing LTO bootstrap (one warning fix) and
with a memory leak fixed.

I'll probably try to split out cleanups from this patch.

Richard.


Index: gcc/data-streamer-out.c
===================================================================
*** gcc/data-streamer-out.c.orig	2014-07-29 13:04:48.255073822 +0200
--- gcc/data-streamer-out.c	2014-07-29 14:35:22.908699653 +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.
*** 32,37 ****
--- 37,194 ----
  #include "gimple.h"
  #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'.
     Then put the index onto the INDEX_STREAM.  
*************** streamer_string_index (struct output_blo
*** 71,77 ****
        new_slot->slot_num = start;
        *slot = new_slot;
        streamer_write_uhwi_stream (string_stream, len);
!       lto_output_data_stream (string_stream, string, len);
        return start + 1;
      }
    else
--- 228,234 ----
        new_slot->slot_num = start;
        *slot = new_slot;
        streamer_write_uhwi_stream (string_stream, len);
!       streamer_write_data_stream (string_stream, string, len);
        return start + 1;
      }
    else
*************** streamer_write_uhwi_stream (struct lto_o
*** 195,201 ****
                              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
*** 215,221 ****
    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
*** 244,250 ****
  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
*** 270,276 ****
    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_gcov_count_stream (struct
*** 304,306 ****
--- 461,494 ----
    gcc_assert ((HOST_WIDE_INT) work == work);
    streamer_write_hwi_stream (obs, work);
  }
+ 
+ /* Write raw DATA of length LEN to the output block OB.  */
+ 
+ void
+ streamer_write_data_stream (struct lto_output_stream *obs, const void *data,
+ 			    size_t len)
+ {
+   while (len)
+     {
+       size_t copy;
+ 
+       /* 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)
+ 	copy = len;
+       else
+ 	copy = obs->left_in_block;
+ 
+       /* Copy the data and do bookkeeping.  */
+       memcpy (obs->current_pointer, data, copy);
+       obs->current_pointer += copy;
+       obs->total_size += copy;
+       obs->left_in_block -= copy;
+       data = (const char *) data + copy;
+       len -= copy;
+     }
+ }
+ 
Index: gcc/lto-section-out.c
===================================================================
*** gcc/lto-section-out.c.orig	2014-07-29 13:04:48.255073822 +0200
--- gcc/lto-section-out.c	2014-07-29 13:09:05.036056143 +0200
*************** lto_end_section (void)
*** 105,120 ****
  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
--- 105,117 ----
  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
*** 134,213 ****
  	}
        else
  	lang_hooks.lto.append_data (base, num_chars, block);
-       block_size *= 2;
-     }
- }
- 
- 
- /* 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);
- }
- 
- 
- /* Write raw DATA of length LEN to the output block OB.  */
- 
- void
- lto_output_data_stream (struct lto_output_stream *obs, const void *data,
- 			size_t len)
- {
-   while (len)
-     {
-       size_t copy;
- 
-       /* 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)
- 	copy = len;
-       else
- 	copy = obs->left_in_block;
- 
-       /* Copy the data and do bookkeeping.  */
-       memcpy (obs->current_pointer, data, copy);
-       obs->current_pointer += copy;
-       obs->total_size += copy;
-       obs->left_in_block -= copy;
-       data = (const char *) data + copy;
-       len -= copy;
      }
  }
  
--- 131,136 ----
*************** lto_create_simple_output_block (enum lto
*** 321,328 ****
  
    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;
  }
--- 244,250 ----
  
    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
*** 349,360 ****
  
    header.compressed_size = 0;
  
!   header.main_size = ob->main_stream->total_size;
  
!   header_stream = XCNEW (struct lto_output_stream);
!   lto_output_data_stream (header_stream, &header, sizeof header);
    lto_write_stream (header_stream);
!   free (header_stream);
  
    lto_write_stream (ob->main_stream);
  
--- 271,282 ----
  
    header.compressed_size = 0;
  
!   header.main_size = ob->main_stream->finish ();
  
!   header_stream = new lto_output_stream (2 * 1024 * 1024, false);
!   streamer_write_data_stream (header_stream, &header, sizeof header);
    lto_write_stream (header_stream);
!   delete header_stream;
  
    lto_write_stream (ob->main_stream);
  
*************** lto_destroy_simple_output_block (struct
*** 362,368 ****
       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-07-29 13:04:48.255073822 +0200
--- gcc/data-streamer.h	2014-07-29 13:09:05.037056143 +0200
*************** void streamer_write_uhwi_stream (struct
*** 70,75 ****
--- 70,77 ----
  				 unsigned HOST_WIDE_INT);
  void streamer_write_hwi_stream (struct lto_output_stream *, HOST_WIDE_INT);
  void streamer_write_gcov_count_stream (struct lto_output_stream *, gcov_type);
+ void streamer_write_data_stream (struct lto_output_stream *, const void *,
+ 				 size_t);
  
  /* In data-streamer-in.c  */
  const char *string_for_index (struct data_in *, unsigned int, unsigned int *);
*************** streamer_write_char_stream (struct lto_o
*** 180,186 ****
  {
    /* 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
*** 196,204 ****
  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,207 ----
  static inline unsigned char
  streamer_read_uchar (struct lto_input_block *ib)
  {
!   if (ib->left_in_block == 0)
!     ib->append_block ();
!   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-29 13:04:48.255073822 +0200
--- gcc/lto-opts.c	2014-07-29 13:09:05.037056143 +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
*************** append_to_collect_gcc_options (struct ob
*** 67,73 ****
  void
  lto_write_options (void)
  {
!   struct lto_output_stream stream;
    char *section_name;
    struct obstack temporary_obstack;
    unsigned int i, j;
--- 68,74 ----
  void
  lto_write_options (void)
  {
!   lto_output_stream *stream = new lto_output_stream (2 * 1024 * 1024, false);
    char *section_name;
    struct obstack temporary_obstack;
    unsigned int i, j;
*************** lto_write_options (void)
*** 76,82 ****
  
    section_name = lto_get_section_name (LTO_section_opts, NULL, NULL);
    lto_begin_section (section_name, false);
-   memset (&stream, 0, sizeof (stream));
  
    obstack_init (&temporary_obstack);
  
--- 77,82 ----
*************** lto_write_options (void)
*** 170,178 ****
      }
    obstack_grow (&temporary_obstack, "\0", 1);
    args = XOBFINISH (&temporary_obstack, char *);
!   lto_output_data_stream (&stream, args, strlen (args) + 1);
  
!   lto_write_stream (&stream);
    lto_end_section ();
  
    obstack_free (&temporary_obstack, NULL);
--- 170,179 ----
      }
    obstack_grow (&temporary_obstack, "\0", 1);
    args = XOBFINISH (&temporary_obstack, char *);
!   streamer_write_data_stream (stream, args, strlen (args) + 1);
  
!   lto_write_stream (stream);
!   delete stream;
    lto_end_section ();
  
    obstack_free (&temporary_obstack, NULL);
Index: gcc/lto-streamer-out.c
===================================================================
*** gcc/lto-streamer-out.c.orig	2014-07-29 13:04:48.255073822 +0200
--- gcc/lto-streamer-out.c	2014-07-29 13:09:05.038056143 +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
*** 1895,1908 ****
    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;
  
!   header_stream = XCNEW (struct lto_output_stream);
!   lto_output_data_stream (header_stream, &header, sizeof header);
    lto_write_stream (header_stream);
!   free (header_stream);
  
    /* Put all of the gimple and the string table out the asm file as a
       block of text.  */
--- 1897,1910 ----
    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 ();
  
!   header_stream = new lto_output_stream (2 * 1024 * 1024, false);
!   streamer_write_data_stream (header_stream, &header, sizeof header);
    lto_write_stream (header_stream);
!   delete header_stream;
  
    /* Put all of the gimple and the string table out the asm file as a
       block of text.  */
*************** lto_output_toplevel_asms (void)
*** 2134,2146 ****
    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;
  
!   header_stream = XCNEW (struct lto_output_stream);
!   lto_output_data_stream (header_stream, &header, sizeof (header));
    lto_write_stream (header_stream);
!   free (header_stream);
  
    /* Put all of the gimple and the string table out the asm file as a
       block of text.  */
--- 2136,2148 ----
    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 ();
  
!   header_stream = new lto_output_stream (2 * 1024 * 1024, false);
!   streamer_write_data_stream (header_stream, &header, sizeof (header));
    lto_write_stream (header_stream);
!   delete header_stream;
  
    /* Put all of the gimple and the string table out the asm file as a
       block of text.  */
*************** copy_function_or_variable (struct symtab
*** 2160,2166 ****
  {
    tree function = node->decl;
    struct lto_file_decl_data *file_data = node->lto_file_data;
!   struct lto_output_stream *output_stream = XCNEW (struct lto_output_stream);
    const char *data;
    size_t len;
    const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (function));
--- 2162,2168 ----
  {
    tree function = node->decl;
    struct lto_file_decl_data *file_data = node->lto_file_data;
!   struct lto_output_stream *output_stream = new lto_output_stream (2 * 1024 * 1024, false);
    const char *data;
    size_t len;
    const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (function));
*************** copy_function_or_variable (struct symtab
*** 2181,2187 ****
    gcc_assert (data);
  
    /* Do a bit copy of the function body.  */
!   lto_output_data_stream (output_stream, data, len);
    lto_write_stream (output_stream);
  
    /* Copy decls. */
--- 2183,2189 ----
    gcc_assert (data);
  
    /* Do a bit copy of the function body.  */
!   streamer_write_data_stream (output_stream, data, len);
    lto_write_stream (output_stream);
  
    /* Copy decls. */
*************** copy_function_or_variable (struct symtab
*** 2206,2212 ****
  
    lto_free_section_data (file_data, LTO_section_function_body, name,
  			 data, len);
!   free (output_stream);
    lto_end_section ();
  }
  
--- 2208,2214 ----
  
    lto_free_section_data (file_data, LTO_section_function_body, name,
  			 data, len);
!   delete output_stream;
    lto_end_section ();
  }
  
*************** write_global_references (struct output_b
*** 2356,2362 ****
    const uint32_t size = lto_tree_ref_encoder_size (encoder);
  
    /* Write size as 32-bit unsigned. */
!   lto_output_data_stream (ref_stream, &size, sizeof (int32_t));
  
    for (index = 0; index < size; index++)
      {
--- 2358,2364 ----
    const uint32_t size = lto_tree_ref_encoder_size (encoder);
  
    /* Write size as 32-bit unsigned. */
!   streamer_write_data_stream (ref_stream, &size, sizeof (int32_t));
  
    for (index = 0; index < size; index++)
      {
*************** write_global_references (struct output_b
*** 2365,2371 ****
        t = lto_tree_ref_encoder_get_tree (encoder, index);
        streamer_tree_cache_lookup (ob->writer_cache, t, &slot_num);
        gcc_assert (slot_num != (unsigned)-1);
!       lto_output_data_stream (ref_stream, &slot_num, sizeof slot_num);
      }
  }
  
--- 2367,2373 ----
        t = lto_tree_ref_encoder_get_tree (encoder, index);
        streamer_tree_cache_lookup (ob->writer_cache, t, &slot_num);
        gcc_assert (slot_num != (unsigned)-1);
!       streamer_write_data_stream (ref_stream, &slot_num, sizeof slot_num);
      }
  }
  
*************** lto_output_decl_state_refs (struct outpu
*** 2401,2407 ****
    decl = (state->fn_decl) ? state->fn_decl : void_type_node;
    streamer_tree_cache_lookup (ob->writer_cache, decl, &ref);
    gcc_assert (ref != (unsigned)-1);
!   lto_output_data_stream (out_stream, &ref, sizeof (uint32_t));
  
    for (i = 0;  i < LTO_N_DECL_STREAMS; i++)
      write_global_references (ob, out_stream, &state->streams[i]);
--- 2403,2409 ----
    decl = (state->fn_decl) ? state->fn_decl : void_type_node;
    streamer_tree_cache_lookup (ob->writer_cache, decl, &ref);
    gcc_assert (ref != (unsigned)-1);
!   streamer_write_data_stream (out_stream, &ref, sizeof (uint32_t));
  
    for (i = 0;  i < LTO_N_DECL_STREAMS; i++)
      write_global_references (ob, out_stream, &state->streams[i]);
*************** write_symbol (struct streamer_tree_cache
*** 2531,2544 ****
    else
      comdat = "";
  
!   lto_output_data_stream (stream, name, strlen (name) + 1);
!   lto_output_data_stream (stream, comdat, strlen (comdat) + 1);
    c = (unsigned char) kind;
!   lto_output_data_stream (stream, &c, 1);
    c = (unsigned char) visibility;
!   lto_output_data_stream (stream, &c, 1);
!   lto_output_data_stream (stream, &size, 8);
!   lto_output_data_stream (stream, &slot_num, 4);
  }
  
  /* Return true if NODE should appear in the plugin symbol table.  */
--- 2533,2546 ----
    else
      comdat = "";
  
!   streamer_write_data_stream (stream, name, strlen (name) + 1);
!   streamer_write_data_stream (stream, comdat, strlen (comdat) + 1);
    c = (unsigned char) kind;
!   streamer_write_data_stream (stream, &c, 1);
    c = (unsigned char) visibility;
!   streamer_write_data_stream (stream, &c, 1);
!   streamer_write_data_stream (stream, &size, 8);
!   streamer_write_data_stream (stream, &slot_num, 4);
  }
  
  /* Return true if NODE should appear in the plugin symbol table.  */
*************** produce_symtab (struct output_block *ob)
*** 2589,2595 ****
    struct streamer_tree_cache_d *cache = ob->writer_cache;
    char *section_name = lto_get_section_name (LTO_section_symtab, NULL, NULL);
    struct pointer_set_t *seen;
!   struct lto_output_stream stream;
    lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
    lto_symtab_encoder_iterator lsei;
  
--- 2591,2597 ----
    struct streamer_tree_cache_d *cache = ob->writer_cache;
    char *section_name = lto_get_section_name (LTO_section_symtab, NULL, NULL);
    struct pointer_set_t *seen;
!   lto_output_stream *stream = new lto_output_stream (2 * 1024 * 1024, false);
    lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
    lto_symtab_encoder_iterator lsei;
  
*************** produce_symtab (struct output_block *ob)
*** 2597,2603 ****
    free (section_name);
  
    seen = pointer_set_create ();
-   memset (&stream, 0, sizeof (stream));
  
    /* Write the symbol table.
       First write everything defined and then all declarations.
--- 2599,2604 ----
*************** produce_symtab (struct output_block *ob)
*** 2609,2615 ****
  
        if (!output_symbol_p (node) || DECL_EXTERNAL (node->decl))
  	continue;
!       write_symbol (cache, &stream, node->decl, seen, false);
      }
    for (lsei = lsei_start (encoder);
         !lsei_end_p (lsei); lsei_next (&lsei))
--- 2610,2616 ----
  
        if (!output_symbol_p (node) || DECL_EXTERNAL (node->decl))
  	continue;
!       write_symbol (cache, stream, node->decl, seen, false);
      }
    for (lsei = lsei_start (encoder);
         !lsei_end_p (lsei); lsei_next (&lsei))
*************** produce_symtab (struct output_block *ob)
*** 2618,2627 ****
  
        if (!output_symbol_p (node) || !DECL_EXTERNAL (node->decl))
  	continue;
!       write_symbol (cache, &stream, node->decl, seen, false);
      }
  
!   lto_write_stream (&stream);
    pointer_set_destroy (seen);
  
    lto_end_section ();
--- 2619,2629 ----
  
        if (!output_symbol_p (node) || !DECL_EXTERNAL (node->decl))
  	continue;
!       write_symbol (cache, stream, node->decl, seen, false);
      }
  
!   lto_write_stream (stream);
!   delete stream;
    pointer_set_destroy (seen);
  
    lto_end_section ();
*************** produce_asm_for_decls (void)
*** 2698,2717 ****
      }
    header.decl_state_size = decl_state_size;
  
!   header.main_size = ob->main_stream->total_size;
!   header.string_size = ob->string_stream->total_size;
  
!   header_stream = XCNEW (struct lto_output_stream);
!   lto_output_data_stream (header_stream, &header, sizeof header);
    lto_write_stream (header_stream);
!   free (header_stream);
  
    /* Write the main out-decl state, followed by out-decl states of
       functions. */
!   decl_state_stream = XCNEW (struct lto_output_stream);
    num_decl_states = num_fns + 1;
!   lto_output_data_stream (decl_state_stream, &num_decl_states,
! 			  sizeof (num_decl_states));
    lto_output_decl_state_refs (ob, decl_state_stream, out_state);
    for (idx = 0; idx < num_fns; idx++)
      {
--- 2700,2719 ----
      }
    header.decl_state_size = decl_state_size;
  
!   header.main_size = ob->main_stream->finish ();
!   header.string_size = ob->string_stream->finish ();
  
!   header_stream = new lto_output_stream (2 * 1024 * 1024, false);
!   streamer_write_data_stream (header_stream, &header, sizeof header);
    lto_write_stream (header_stream);
!   delete header_stream;
  
    /* Write the main out-decl state, followed by out-decl states of
       functions. */
!   decl_state_stream = new lto_output_stream (2 * 1024 * 1024, false);
    num_decl_states = num_fns + 1;
!   streamer_write_data_stream (decl_state_stream, &num_decl_states,
! 			      sizeof (num_decl_states));
    lto_output_decl_state_refs (ob, decl_state_stream, out_state);
    for (idx = 0; idx < num_fns; idx++)
      {
*************** produce_asm_for_decls (void)
*** 2720,2726 ****
        lto_output_decl_state_refs (ob, decl_state_stream, fn_out_state);
      }
    lto_write_stream (decl_state_stream);
!   free (decl_state_stream);
  
    lto_write_stream (ob->main_stream);
    lto_write_stream (ob->string_stream);
--- 2722,2728 ----
        lto_output_decl_state_refs (ob, decl_state_stream, fn_out_state);
      }
    lto_write_stream (decl_state_stream);
!   delete decl_state_stream;
  
    lto_write_stream (ob->main_stream);
    lto_write_stream (ob->string_stream);
Index: gcc/lto-streamer.h
===================================================================
*** gcc/lto-streamer.h.orig	2014-07-29 13:04:48.255073822 +0200
--- gcc/lto-streamer.h	2014-07-29 14:36:21.727695603 +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
*** 769,775 ****
  				      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;
--- 806,811 ----
*************** extern void lto_push_out_decl_state (str
*** 805,811 ****
  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.  */
--- 841,846 ----
Index: gcc/lto-section-in.c
===================================================================
*** gcc/lto-section-in.c.orig	2014-07-29 13:04:48.255073822 +0200
--- gcc/lto-section-in.c	2014-07-29 13:09:05.039056143 +0200
*************** 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_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-29 13:04:48.255073822 +0200
--- gcc/lto-cgraph.c	2014-07-29 13:09:05.040056143 +0200
*************** lto_output_node (struct lto_simple_outpu
*** 488,494 ****
      comdat = IDENTIFIER_POINTER (group);
    else
      comdat = "";
!   lto_output_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);
!   lto_output_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 = "";
!   lto_output_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 = "";
!   lto_output_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-29 13:04:48.255073822 +0200
--- gcc/data-streamer-in.c	2014-07-29 13:58:27.738852164 +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-29 13:04:48.255073822 +0200
--- gcc/ipa-inline-analysis.c	2014-07-29 13:09:05.041056143 +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-29 13:05:27.958071088 +0200
--- gcc/ipa-prop.c	2014-07-29 13:09:05.042056142 +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-29 13:04:48.255073822 +0200
--- gcc/lto-streamer-in.c	2014-07-29 13:09:05.043056142 +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-29 13:04:48.255073822 +0200
--- gcc/lto/lto.c	2014-07-29 13:09:05.044056142 +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 ();
Index: gcc/common.opt
===================================================================
*** gcc/common.opt.orig	2014-07-29 13:04:48.255073822 +0200
--- gcc/common.opt	2014-07-29 13:09:05.044056142 +0200
*************** Specify the algorithm to partition symbo
*** 1545,1551 ****
  
  ; The initial value of -1 comes from Z_DEFAULT_COMPRESSION in zlib.h.
  flto-compression-level=
! Common Joined RejectNegative UInteger Var(flag_lto_compression_level) Init(-1)
  -flto-compression-level=<number>	Use zlib compression level <number> for IL
  
  flto-report
--- 1545,1551 ----
  
  ; The initial value of -1 comes from Z_DEFAULT_COMPRESSION in zlib.h.
  flto-compression-level=
! Common Joined RejectNegative UInteger Var(flag_lto_compression_level) Init(0)
  -flto-compression-level=<number>	Use zlib compression level <number> for IL
  
  flto-report



More information about the Gcc-patches mailing list