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. Richard. <insert-changelog-here> 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 13:09:40.301053715 +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,199 ---- #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; + 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; + bool first_p = false; + + 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; + first_p = true; + } + 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); + + #if 0 + if (first_p) + streamer_write_hwi_stream (this, compress); + #endif + } + + /* 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 --- 233,239 ---- 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; --- 357,363 ---- 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 --- 377,383 ---- 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; --- 406,412 ---- 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 --- 432,438 ---- 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 **** --- 466,499 ---- 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 13:09:05.039056143 +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:09:33.339054194 +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,115 ---- #include "gimple.h" #include "data-streamer.h" + + void + lto_input_block::append_block () + { + gcc_assert (left_in_block == 0 && data); + #if 0 + /* Auto-detect confuses special sections like lto_opts and symtab. */ + if (!current_pointer && p == 0) + { + gcc_assert (*data == compress); + p++; + } + #endif + 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; } --- 120,134 ---- } /* 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; } --- 197,218 ---- 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