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