format of these sections is entirely up to each individual pass. The
only requirement is that the writer and reader hooks agree on the
format.
+
+@item Linemap sections (@code{.gnu.lto_.linemap.<N>})
+
+These sections contain data necessary to reconstruct the linemap
+structure, which provides information about the source location for
+each entity in the LTO stream. A typical LTO object contains just one
+linemap section (@code{linemap.0}), but WPA will create an object
+containing more than one linemap section if it has copied function
+bodies from more than one translation unit into a single partition.
@end itemize
previous run of the LTO in WPA mode. In the LTRANS mode, LTO
optimizes an object and produces the final assembly.
+@opindex fltrans-linemap-file
+@item -fltrans-linemap-file=@var{file}
+This option specifies an object file (output during the WPA phase)
+containing additional linemap sections to be used during LTRANS. It
+is used internally by WPA to avoid copying the same linemap data into
+multiple LTRANS partitions.
+
@opindex fltrans-output-list
@item -fltrans-output-list=@var{file}
This option specifies a file to which the names of LTRANS output
case OPT_fcanon_prefix_map:
case OPT_fwhole_program:
case OPT_fltrans_output_list_:
+ case OPT_fltrans_linemap_file_:
case OPT_flto_incremental_:
case OPT_flto_incremental_cache_size_:
continue;
"ipa_sra",
"odr_types",
"ipa_modref",
+ "linemap",
};
/* Hooks so that the ipa passes can call into the lto front end to get
}
}
-/* Pointer to currently alive instance of lto_location_cache. */
-
-lto_location_cache *lto_location_cache::current_cache;
+/* Given a map index and offset from the streamed data, convert it to a
+ location_t in the global line map. */
-/* Sort locations in source order. Start with file from last application. */
-
-int
-lto_location_cache::cmp_loc (const void *pa, const void *pb)
+static location_t
+get_location_from_idx (size_t map_idx, location_t offset,
+ const lto_loc_map *loc_map)
{
- const cached_location *a = ((const cached_location *)pa);
- const cached_location *b = ((const cached_location *)pb);
- const char *current_file = current_cache->current_file;
- int current_line = current_cache->current_line;
-
- if (a->file == current_file && b->file != current_file)
- return -1;
- if (a->file != current_file && b->file == current_file)
- return 1;
- if (a->file == current_file && b->file == current_file)
- {
- if (a->line == current_line && b->line != current_line)
- return -1;
- if (a->line != current_line && b->line == current_line)
- return 1;
- }
- if (a->file != b->file)
- return strcmp (a->file, b->file);
- if (a->sysp != b->sysp)
- return a->sysp ? 1 : -1;
- if (a->line != b->line)
- return a->line - b->line;
- if (a->col != b->col)
- return a->col - b->col;
- if (a->discr != b->discr)
- return a->discr - b->discr;
- if ((a->block == NULL_TREE) != (b->block == NULL_TREE))
- return a->block ? 1 : -1;
- if (a->block)
- {
- if (BLOCK_NUMBER (a->block) < BLOCK_NUMBER (b->block))
- return -1;
- if (BLOCK_NUMBER (a->block) > BLOCK_NUMBER (b->block))
- return 1;
- }
- return 0;
+ if (!map_idx)
+ return offset;
+ gcc_checking_assert (loc_map);
+ --map_idx;
+ gcc_assert (map_idx < loc_map->nmaps);
+ const auto map = LINEMAPS_ORDINARY_MAP_AT (line_table, loc_map->map[map_idx]);
+ const location_t res = map->start_location + offset;
+ gcc_checking_assert (res < (map == LINEMAPS_LAST_ORDINARY_MAP (line_table)
+ ? line_table->highest_location + 1
+ : map[1].start_location));
+ return res;
}
+/* Pointer to currently alive instance of lto_location_cache. */
+
+lto_location_cache *lto_location_cache::current_cache;
+
/* Apply all changes in location cache. Add locations into linemap and patch
trees. */
bool
lto_location_cache::apply_location_cache ()
{
- static const char *prev_file;
- if (!loc_cache.length ())
- return false;
- if (loc_cache.length () > 1)
- loc_cache.qsort (cmp_loc);
+ if (loc_cache.is_empty ())
+ return true;
- for (unsigned int i = 0; i < loc_cache.length (); i++)
+ for (const auto &cloc: loc_cache)
{
- struct cached_location loc = loc_cache[i];
-
- if (current_file != loc.file)
- linemap_add (line_table, prev_file ? LC_RENAME : LC_ENTER,
- loc.sysp, loc.file, loc.line);
- else if (current_line != loc.line)
- {
- int max = loc.col;
-
- for (unsigned int j = i + 1; j < loc_cache.length (); j++)
- if (loc.file != loc_cache[j].file
- || loc.line != loc_cache[j].line)
- break;
- else if (max < loc_cache[j].col)
- max = loc_cache[j].col;
- linemap_line_start (line_table, loc.line, max + 1);
- }
- gcc_assert (*loc.loc == BUILTINS_LOCATION + 1);
- if (current_file != loc.file
- || current_line != loc.line
- || current_col != loc.col)
- {
- current_loc = linemap_position_for_column (line_table, loc.col);
- if (loc.block)
- current_loc = set_block (current_loc, loc.block);
- if (loc.discr)
- current_loc = location_with_discriminator (current_loc, loc.discr);
- }
- else if (current_block != loc.block)
- {
- if (loc.block)
- current_loc = set_block (current_loc, loc.block);
- else
- current_loc = LOCATION_LOCUS (current_loc);
- if (loc.discr)
- current_loc = location_with_discriminator (current_loc, loc.discr);
- }
- else if (current_discr != loc.discr)
- current_loc = location_with_discriminator (current_loc, loc.discr);
- *loc.loc = current_loc;
- current_line = loc.line;
- prev_file = current_file = loc.file;
- current_col = loc.col;
- current_block = loc.block;
- current_discr = loc.discr;
+ const location_t loc = cloc.loc;
+ const auto range = source_range::from_location (loc);
+ *cloc.dest = line_table->get_or_create_combined_loc (loc, range,
+ cloc.block,
+ cloc.discr);
}
+ current_cloc = loc_cache[loc_cache.length () - 1];
+ current_loc = *current_cloc.dest;
loc_cache.truncate (0);
accepted_length = 0;
return true;
loc_cache.truncate (accepted_length);
}
-/* Read a location bitpack from bit pack BP and either update *LOC directly
- or add it to the location cache. If IB is non-NULL, stream in a block
- afterwards.
- It is necessary to call apply_location_cache to get *LOC updated. */
-
-void
-lto_location_cache::input_location_and_block (location_t *loc,
- struct bitpack_d *bp,
- class lto_input_block *ib,
- class data_in *data_in)
+/* Bitpack packing is more efficient for small values since every 4th bit is a
+ continuation bit, so it helps to pack values as the delta from the previous
+ if they can get large. */
+template<typename Int>
+static Int
+bp_unpack_delta (bitpack_d *bp, Int &prev)
{
- static const char *stream_file;
- static int stream_line;
- static int stream_col;
- static bool stream_sysp;
- static tree stream_block;
- static unsigned stream_discr;
- static const char *stream_relative_path_prefix;
+ const bool decrease = bp_unpack_value (bp, 1);
+ const Int delta = bp_unpack_var_len_unsigned (bp);
+ return prev = (decrease ? prev - delta : prev + delta);
+}
- gcc_assert (current_cache == this);
+/* Read the linemap section of order LINEMAP_ID from FILE_DATA and create an
+ lto_loc_map object that can be used to find which ordinary map in the
+ global line_table corresponds to a given streamed-out map index. Always
+ either returns a non-NULL pointer, or calls fatal_error(). */
+
+static lto_loc_map *
+create_loc_map (lto_file_decl_data *file_data, unsigned linemap_id)
+{
+ timevar_push (TV_IPA_LTO_LINEMAP_IN);
- *loc = bp_unpack_int_in_range (bp, "location", 0,
- RESERVED_LOCATION_COUNT + 1);
+ size_t len;
+ const auto data = lto_get_section_data (file_data, LTO_section_linemap,
+ nullptr, linemap_id, &len, true);
+ if (!data)
+ fatal_error (UNKNOWN_LOCATION,
+ "linemap section #%u not found in file %qs",
+ linemap_id, file_data->file_name);
+
+ const auto header = (const lto_simple_header_with_strings *) data;
+ const char *const main_begin = data + sizeof (*header);
+ const auto data_in
+ = lto_data_in_create (file_data, main_begin + header->main_size,
+ header->string_size, vNULL, false);
+ lto_input_block ib (main_begin, header->main_size, file_data);
+ bitpack_d bp = streamer_read_bitpack (&ib);
- if (*loc < RESERVED_LOCATION_COUNT)
+ /* Create the location map object. */
+ const size_t nmaps = bp_unpack_var_len_unsigned (&bp);
+ size_t loc_map_sz = sizeof (lto_loc_map);
+ if (nmaps > 1)
+ loc_map_sz += (nmaps - 1) * sizeof (size_t);
+ const auto loc_map = (lto_loc_map *) ggc_internal_alloc (loc_map_sz);
+ loc_map->nmaps = nmaps;
+
+ /* Read the line map data. */
+ const char *stream_relative_path_prefix = nullptr;
+ const char *stream_file = nullptr;
+ size_t cur_map_idx = 0;
+ linenum_type cur_line = 0;
+ for (size_t i = 0; i != nmaps; ++i)
{
- if (ib)
+ const size_t map_idx = bp_unpack_delta (&bp, cur_map_idx);
+ gcc_assert (map_idx && map_idx <= nmaps);
+ const line_map_uint_t num_lines = bp_unpack_var_len_unsigned (&bp);
+ const bool sysp = bp_unpack_value (&bp, 1);
+ const unsigned int column_bits = bp_unpack_value (&bp, 8);
+ const linenum_type to_line = bp_unpack_delta (&bp, cur_line);
+ const bool file_change = bp_unpack_value (&bp, 1);
+ if (file_change)
{
- bool block_change = bp_unpack_value (bp, 1);
- if (block_change)
- stream_block = stream_read_tree (ib, data_in);
- if (stream_block)
- *loc = set_block (*loc, stream_block);
+ const bool pwd_change = bp_unpack_value (&bp, 1);
+ if (pwd_change)
+ {
+ const char *pwd = bp_unpack_string (data_in, &bp);
+ const char *src_pwd = get_src_pwd ();
+ stream_relative_path_prefix
+ = strcmp (pwd, src_pwd) == 0 ? nullptr
+ : canon_relative_path_prefix (pwd, src_pwd);
+ }
+ stream_file = canon_file_name (stream_relative_path_prefix,
+ bp_unpack_string (data_in, &bp));
+ }
+ gcc_assert (stream_file);
+ const auto map
+ = linemap_add_raw_map (line_table,
+ line_table->depth ? LC_RENAME : LC_ENTER,
+ line_table->highest_location + 1, sysp,
+ column_bits, 0, stream_file, to_line, num_lines);
+ if (!map)
+ fatal_error (UNKNOWN_LOCATION,
+ "Ran out of locations while reading linemap section #%u",
+ linemap_id);
+ loc_map->map[map_idx - 1] = map - line_table->info_ordinary.maps;
+ if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
+ {
+ const auto out_id = lto_linemap_output_id (linemap_id, file_data);
+ lto_register_linemap_for_output (map_idx, out_id);
}
- return;
}
- bool file_change = (*loc == RESERVED_LOCATION_COUNT + 1);
- /* Keep value RESERVED_LOCATION_COUNT in *loc as linemap lookups will
- ICE on it. */
- *loc = RESERVED_LOCATION_COUNT;
- bool line_change = bp_unpack_value (bp, 1);
- bool column_change = bp_unpack_value (bp, 1);
- bool discr_change = bp_unpack_value (bp, 1);
+ lto_data_in_delete (data_in);
+ lto_free_section_data (file_data, LTO_section_linemap, nullptr,
+ data, len, true);
+
+ timevar_pop (TV_IPA_LTO_LINEMAP_IN);
+ return loc_map;
+}
+
+/* Return the location map with given ID, reading it from the LTO object if
+ necessary. */
+
+static const lto_loc_map *
+get_loc_map (lto_file_decl_data *file_data, unsigned linemap_id)
+{
+ /* During LTRANS, the location maps are stored in a different object. */
+ while (file_data->loc_map_decl_data)
+ file_data = file_data->loc_map_decl_data;
+
+ if (vec_safe_length (file_data->loc_maps) <= linemap_id)
+ vec_safe_grow_cleared (file_data->loc_maps, linemap_id + 1);
+ auto &res = (*file_data->loc_maps)[linemap_id];
+ if (!res)
+ res = create_loc_map (file_data, linemap_id);
+ return res;
+}
+
+
+/* Read a location bitpack from bit pack BP and either update *LOC directly or
+ add it to the location cache. It is necessary to call apply_location_cache
+ to guarantee that *LOC has been updated. */
+
+void
+lto_location_cache::input_location_and_block (location_t *dest,
+ struct bitpack_d *bp,
+ class lto_input_block *ib,
+ class data_in *data_in)
+{
+ gcc_checking_assert (decl_data);
- if (file_change)
+ location_t loc;
+ unsigned this_discr;
+ const bool is_reserved = bp_unpack_value (bp, 1);
+ if (is_reserved)
{
- bool pwd_change = bp_unpack_value (bp, 1);
- if (pwd_change)
+ loc = bp_unpack_int_in_range (bp, "loc", 0, RESERVED_LOCATION_COUNT - 1);
+ this_discr = 0;
+ }
+ else
+ {
+ const bool linemap_change = bp_unpack_value (bp, 1);
+ if (linemap_change)
{
- const char *pwd = bp_unpack_string (data_in, bp);
- const char *src_pwd = get_src_pwd ();
- if (strcmp (pwd, src_pwd) == 0)
- stream_relative_path_prefix = NULL;
- else
- stream_relative_path_prefix
- = canon_relative_path_prefix (pwd, src_pwd);
+ const unsigned linemap_id = bp_unpack_var_len_unsigned (bp);
+ cur_loc_map = get_loc_map (decl_data, linemap_id + linemap_offset);
}
- stream_file = canon_file_name (stream_relative_path_prefix,
- bp_unpack_string (data_in, bp));
- stream_sysp = bp_unpack_value (bp, 1);
+ const auto prev_idx = stream_map_idx;
+ bp_unpack_delta (bp, stream_map_idx);
+ bp_unpack_delta (bp, stream_loc_offset);
+ if (stream_map_idx != prev_idx)
+ /* The hash code is only there for the benefit of -flto-incremental;
+ we don't need to do anything with it here. */
+ bp_unpack_var_len_unsigned (bp);
+
+ loc = get_location_from_idx (stream_map_idx, stream_loc_offset,
+ cur_loc_map);
+ if (bp_unpack_value (bp, 1))
+ stream_discr = bp_unpack_var_len_unsigned (bp);
+ this_discr = stream_discr;
}
- if (line_change)
- stream_line = bp_unpack_var_len_unsigned (bp);
-
- if (column_change)
- stream_col = bp_unpack_var_len_unsigned (bp);
-
- if (discr_change)
- stream_discr = bp_unpack_var_len_unsigned (bp);
-
- tree block = NULL_TREE;
+ tree this_block = NULL_TREE;
if (ib)
{
- bool block_change = bp_unpack_value (bp, 1);
- if (block_change)
+ if (bp_unpack_value (bp, 1))
stream_block = stream_read_tree (ib, data_in);
- block = stream_block;
+ this_block = stream_block;
+ }
+
+ /* If this location can be ordinary rather than ad-hoc, then there is no more
+ overhead associated with it, so we may as well finalize it now. */
+ if (!(this_discr || this_block))
+ {
+ *dest = loc;
+ return;
}
/* This optimization saves location cache operations during gimple
streaming. */
-
- if (current_file == stream_file
- && current_line == stream_line
- && current_col == stream_col
- && current_sysp == stream_sysp
- && current_discr == stream_discr)
+ if (loc == current_cloc.loc
+ && this_block == current_cloc.block
+ && this_discr == current_cloc.discr)
{
- if (current_block == block)
- *loc = current_loc;
- else if (block)
- *loc = set_block (current_loc, block);
- else
- *loc = LOCATION_LOCUS (current_loc);
+ *dest = current_loc;
return;
}
- struct cached_location entry
- = {stream_file, loc, stream_line, stream_col, stream_sysp, block, stream_discr};
+ /* Keep value RESERVED_LOCATION_COUNT in *dest so linemap lookups will ICE on
+ it if we erroneously try to use the location before it is ready. */
+ *dest = RESERVED_LOCATION_COUNT;
+
+ /* This location needs to be ad-hoc; remember the details for now and create
+ the ad-hoc location later once we know we need it. */
+ cached_location entry = {};
+ entry.dest = dest;
+ entry.loc = loc;
+ entry.block = this_block;
+ entry.discr = this_discr;
loc_cache.safe_push (entry);
}
-/* Read a location bitpack from bit pack BP and either update *LOC directly
- or add it to the location cache.
- It is necessary to call apply_location_cache to get *LOC updated. */
-
void
-lto_location_cache::input_location (location_t *loc, struct bitpack_d *bp,
+lto_location_cache::input_location (location_t *dest, struct bitpack_d *bp,
class data_in *data_in)
{
- return input_location_and_block (loc, bp, NULL, data_in);
+ return input_location_and_block (dest, bp, NULL, data_in);
}
-/* Read a location bitpack from input block IB and either update *LOC directly
- or add it to the location cache.
- It is necessary to call apply_location_cache to get *LOC updated. */
-
void
lto_input_location (location_t *loc, struct bitpack_d *bp,
class data_in *data_in)
decl_state = lto_get_function_in_decl_state (file_data, fn_decl);
gcc_assert (decl_state);
file_data->current_decl_state = decl_state;
-
+ data_in->location_cache.set_linemap_offset (decl_state->linemap_id);
/* Set up the struct function. */
from = data_in->reader_cache->nodes.length ();
class data_in *
lto_data_in_create (struct lto_file_decl_data *file_data, const char *strings,
unsigned len,
- vec<ld_plugin_symbol_resolution_t> resolutions)
+ vec<ld_plugin_symbol_resolution_t> resolutions,
+ bool need_location_cache)
{
- class data_in *data_in = new (class data_in);
- data_in->file_data = file_data;
- data_in->strings = strings;
- data_in->strings_len = len;
- data_in->globals_resolution = resolutions;
- data_in->reader_cache = streamer_tree_cache_create (false, false, true);
- return data_in;
+ const auto d = new data_in{need_location_cache ? file_data : nullptr};
+ d->file_data = file_data;
+ d->strings = strings;
+ d->strings_len = len;
+ d->globals_resolution = resolutions;
+ d->reader_cache = streamer_tree_cache_create (false, false, true);
+ return d;
}
static void
clear_line_info (struct output_block *ob)
{
- ob->current_file = NULL;
- ob->current_line = 0;
- ob->current_col = 0;
- ob->current_sysp = false;
- ob->reset_locus = true;
- ob->emit_pwd = true;
/* Initialize to something that will never appear as block,
so that the first location with block in a function etc.
always streams a change_block bit and the first block. */
ob->current_block = void_node;
ob->current_discr = UINT_MAX;
+ ob->current_map_idx = 0;
+ ob->current_loc_offset = 0;
+ ob->current_linemap_id = -1U;
}
return (IS_TYPE_OR_DECL_P (t) || TREE_CODE (t) == SSA_NAME);
}
+namespace {
-/* Output info about new location into bitpack BP.
- After outputting bitpack, lto_output_location_data has
- to be done to output actual data. */
+/* Compute a 32-bit hash of the linemap details. This is currently used to
+ ensure that WPA streamed output will change whenever the linemap details
+ change, otherwise there could be potential issues with the validity of
+ the cache used to implement -flto-incremental. */
-static void
-lto_output_location_1 (struct output_block *ob, struct bitpack_d *bp,
- location_t orig_loc, bool block_p)
+hashval_t
+compute_map_hash (const line_map_ordinary *map)
+{
+ inchash::hash h;
+ h.add_int (map->sysp);
+ h.add_int (map->m_column_and_range_bits - map->m_range_bits);
+ h.add_int (map->to_line);
+ h.add_object (map->included_from);
+ h.add (map->to_file, strlen (map->to_file));
+ return h.end ();
+}
+
+class location_output
{
- location_t loc = LOCATION_LOCUS (orig_loc);
+public:
- if (loc >= RESERVED_LOCATION_COUNT)
+ struct map_id_t
+ {
+ size_t idx;
+ unsigned linemap_id;
+ hashval_t hash;
+ };
+
+ struct location_id_t
+ {
+ map_id_t map_id;
+ location_t offset;
+ };
+
+ location_id_t record_location (location_t loc);
+
+ void register_map_id (size_t map_idx, unsigned linemap_id)
+ {
+ gcc_checking_assert (LINEMAPS_ORDINARY_USED (line_table)
+ == orig_map_ids.length () + 1);
+ const auto map = LINEMAPS_LAST_ORDINARY_MAP (line_table);
+ const hashval_t hash = compute_map_hash (map);
+ orig_map_ids.safe_push (map_id_t{map_idx, linemap_id, hash});
+ }
+
+ void produce_linemap_section ();
+
+private:
+ struct map_data
+ {
+ size_t idx;
+ hashval_t hash;
+ location_t highest_location;
+ };
+ hash_map<nofree_ptr_hash<const line_map_ordinary>, map_data> map_data_map;
+ vec<map_id_t> orig_map_ids = {};
+};
+
+location_output::location_id_t
+location_output::record_location (location_t loc)
+{
+ /* Strip away any macro expansion data or embedded range information. */
+ loc = linemap_resolve_location (line_table, loc, LRK_MACRO_EXPANSION_POINT,
+ nullptr);
+ loc = get_pure_location (loc);
+ location_id_t loc_id = {};
+ if (loc < RESERVED_LOCATION_COUNT)
{
- expanded_location xloc = expand_location (loc);
- unsigned discr = get_discriminator_from_loc (orig_loc);
+ /* IDX 0 is for reserved locations. */
+ loc_id.offset = loc;
+ return loc_id;
+ }
- if (ob->reset_locus)
- {
- if (xloc.file == NULL)
- ob->current_file = "";
- if (xloc.line == 0)
- ob->current_line = 1;
- if (xloc.column == 0)
- ob->current_col = 1;
- ob->reset_locus = false;
- }
+ const auto map = linemap_check_ordinary (linemap_lookup (line_table, loc));
- /* As RESERVED_LOCATION_COUNT is 2, we can use the spare value of
- 3 without wasting additional bits to signalize file change.
- If RESERVED_LOCATION_COUNT changes, reconsider this. */
- gcc_checking_assert (RESERVED_LOCATION_COUNT == 2);
- bp_pack_int_in_range (bp, 0, RESERVED_LOCATION_COUNT + 1,
- RESERVED_LOCATION_COUNT
- + (ob->current_file != xloc.file));
+ if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
+ {
+ /* In these modes, we don't create new locations, we only work with what
+ was read, so we will re-output the locations in the same way. */
+ gcc_checking_assert (orig_map_ids.length ()
+ == LINEMAPS_ORDINARY_USED (line_table));
+ gcc_checking_assert (!map->m_range_bits);
+ loc_id.map_id = orig_map_ids[map - line_table->info_ordinary.maps];
+ loc_id.offset = loc - map->start_location;
+ return loc_id;
+ }
- bp_pack_value (bp, ob->current_line != xloc.line, 1);
- bp_pack_value (bp, ob->current_col != xloc.column, 1);
- bp_pack_value (bp, ob->current_discr != discr, 1);
+ /* Represent each location_t as the offset from the map start,
+ without any range bits. */
+ map_data &md = map_data_map.get_or_insert (map);
+ if (!md.idx)
+ {
+ md.idx = map_data_map.elements ();
+ md.hash = compute_map_hash (map);
+ }
+ md.highest_location = MAX (md.highest_location, loc);
+ loc_id.map_id.idx = md.idx;
+ loc_id.map_id.hash = md.hash;
+ loc_id.offset = (loc - map->start_location) >> map->m_range_bits;
+ return loc_id;
+}
- if (ob->current_file != xloc.file)
+/* Bitpack packing is more efficient for small values since every 4th bit is a
+ continuation bit, so it helps to pack values as the delta from the previous
+ if they can get large. */
+template<typename Int>
+static void
+bp_pack_delta (bitpack_d *bp, Int val, Int &prev)
+{
+ const bool decrease = (val < prev);
+ bp_pack_value (bp, decrease, 1);
+ bp_pack_var_len_unsigned (bp, decrease ? prev - val : val - prev);
+ prev = val;
+}
+
+void
+location_output::produce_linemap_section ()
+{
+ timevar_push (TV_IPA_LTO_LINEMAP_OUT);
+
+ const auto ob = create_output_block (LTO_section_linemap);
+ auto bp = bitpack_create (ob->main_stream);
+
+ /* Sort the maps in the order they need to be inserted later. */
+ const size_t nmaps = map_data_map.elements ();
+ using KV = std::pair<const line_map_ordinary *, map_data>;
+ const std::unique_ptr<KV[]> sorted_maps{new KV[nmaps]};
+ size_t map_i = 0;
+ for (auto iter = map_data_map.begin (), end = map_data_map.end ();
+ iter != end; ++iter)
+ sorted_maps[map_i++] = *iter;
+ gcc_qsort (sorted_maps.get (), nmaps, sizeof (KV),
+ [] (const void *p1, const void *p2)
+ {
+ const auto map1 = static_cast<const KV *> (p1)->first;
+ const auto map2 = static_cast<const KV *> (p2)->first;
+ const location_t loc1 = map1->start_location;
+ const location_t loc2 = map2->start_location;
+ return (loc2 < loc1) - (loc1 < loc2);
+ });
+
+ /* Output the maps. */
+ bp_pack_var_len_unsigned (&bp, nmaps);
+ const char *current_file = nullptr;
+ bool emit_pwd = true;
+ size_t prev_idx = 0;
+ linenum_type prev_line = 0;
+ for (map_i = 0; map_i != nmaps; ++map_i)
+ {
+ const auto map = sorted_maps[map_i].first;
+ const map_data &md = sorted_maps[map_i].second;
+ bp_pack_delta (&bp, md.idx, prev_idx);
+ const auto num_lines
+ = 1 + ((md.highest_location - map->start_location)
+ >> map->m_column_and_range_bits);
+ bp_pack_var_len_unsigned (&bp, num_lines);
+ bp_pack_value (&bp, map->sysp != 0, 1);
+ bp_pack_value (&bp, map->m_column_and_range_bits - map->m_range_bits, 8);
+ bp_pack_delta (&bp, map->to_line, prev_line);
+ const bool file_change = (map->to_file != current_file);
+ bp_pack_value (&bp, file_change, 1);
+ if (file_change)
{
bool stream_pwd = false;
- const char *remapped = remap_debug_filename (xloc.file);
- if (ob->emit_pwd && remapped && !IS_ABSOLUTE_PATH (remapped))
+ const char *remapped = remap_debug_filename (map->to_file);
+ if (emit_pwd && remapped && !IS_ABSOLUTE_PATH (remapped))
{
stream_pwd = true;
- ob->emit_pwd = false;
+ emit_pwd = false;
}
- bp_pack_value (bp, stream_pwd, 1);
+ bp_pack_value (&bp, stream_pwd, 1);
if (stream_pwd)
- bp_pack_string (ob, bp, get_src_pwd (), true);
- bp_pack_string (ob, bp, remapped, true);
- bp_pack_value (bp, xloc.sysp, 1);
+ bp_pack_string (ob, &bp, get_src_pwd (), true);
+ bp_pack_string (ob, &bp, remapped, true);
}
- ob->current_file = xloc.file;
- ob->current_sysp = xloc.sysp;
+ }
- if (ob->current_line != xloc.line)
- bp_pack_var_len_unsigned (bp, xloc.line);
- ob->current_line = xloc.line;
+ /* Finalize the section. */
+ streamer_write_bitpack (&bp);
+ {
+ const auto section_name
+ = lto_get_section_name (LTO_section_linemap, nullptr, 0, nullptr);
+ lto_begin_section (section_name, true);
+ free (section_name);
+ }
- if (ob->current_col != xloc.column)
- bp_pack_var_len_unsigned (bp, xloc.column);
- ob->current_col = xloc.column;
+ lto_simple_header_with_strings header = {};
+ header.main_size = ob->main_stream->total_size;
+ header.string_size = ob->string_stream->total_size;
+ lto_write_data (&header, sizeof header);
+ lto_write_stream (ob->main_stream);
+ lto_write_stream (ob->string_stream);
+ lto_end_section ();
+ destroy_output_block (ob);
- if (ob->current_discr != discr)
- bp_pack_var_len_unsigned (bp, discr);
- ob->current_discr = discr;
+ timevar_pop (TV_IPA_LTO_LINEMAP_OUT);
+}
+
+location_output loc_output;
+
+} /* unnamed namespace */
+
+/* Get a mapping index for LOC and stream it along with optional ancillary
+ data. */
+
+static void
+lto_output_location_1 (struct output_block *ob, struct bitpack_d *bp,
+ location_t loc, bool block_p)
+{
+ const auto loc_id = loc_output.record_location (loc);
+ if (!loc_id.map_id.idx)
+ {
+ bp_pack_value (bp, true, 1);
+ bp_pack_int_in_range (bp, 0, RESERVED_LOCATION_COUNT - 1, loc_id.offset);
}
else
- bp_pack_int_in_range (bp, 0, RESERVED_LOCATION_COUNT + 1, loc);
+ {
+ bp_pack_value (bp, false, 1);
+ if (loc_id.map_id.linemap_id == ob->current_linemap_id)
+ bp_pack_value (bp, false, 1);
+ else
+ {
+ bp_pack_value (bp, true, 1);
+ bp_pack_var_len_unsigned (bp, loc_id.map_id.linemap_id);
+ ob->current_linemap_id = loc_id.map_id.linemap_id;
+ }
+ const bool is_new_map = (loc_id.map_id.idx != ob->current_map_idx);
+ bp_pack_delta (bp, loc_id.map_id.idx, ob->current_map_idx);
+ bp_pack_delta (bp, loc_id.offset, ob->current_loc_offset);
+ if (is_new_map)
+ bp_pack_var_len_unsigned (bp, loc_id.map_id.hash);
+ const unsigned discr = get_discriminator_from_loc (loc);
+ bp_pack_value (bp, ob->current_discr != discr, 1);
+ if (ob->current_discr != discr)
+ {
+ bp_pack_var_len_unsigned (bp, discr);
+ ob->current_discr = discr;
+ }
+ }
if (block_p)
{
- tree block = LOCATION_BLOCK (orig_loc);
+ tree block = LOCATION_BLOCK (loc);
bp_pack_value (bp, ob->current_block != block, 1);
streamer_write_bitpack (bp);
if (ob->current_block != block)
- lto_output_tree (ob, block, true, true);
- ob->current_block = block;
+ {
+ lto_output_tree (ob, block, true, true);
+ ob->current_block = block;
+ }
}
}
lto_free_raw_section_data (file_data, LTO_section_function_body, name,
data, len);
lto_end_section ();
+
+ /* Make sure the reader knows which linemap section to use. */
+ out_state->linemap_id = lto_linemap_output_id (in_state->linemap_id,
+ file_data);
}
/* Wrap symbol references in *TP inside a type-preserving MEM_REF. */
destroy_output_block (ob);
}
+/* If we have copied a function, we need to make sure the linemap it refers to
+ is also streamed out. */
+
+static void
+copy_linemap_section (lto_file_decl_data *file_data, unsigned order)
+{
+ const auto in_section_name
+ = lto_get_section_name (LTO_section_linemap, nullptr, order, file_data);
+ const auto out_section_name
+ = lto_get_section_name (LTO_section_linemap, nullptr,
+ lto_linemap_output_id (order, file_data), nullptr);
+
+ if (streamer_dump_file)
+ fprintf (streamer_dump_file, "Copying linemap section from %s to %s\n",
+ in_section_name, out_section_name);
+
+ size_t len;
+ const auto data = lto_get_raw_section_data (file_data, LTO_section_linemap,
+ nullptr, order, &len);
+ gcc_assert (data);
+ lto_begin_section (out_section_name, false);
+ free (in_section_name);
+ free (out_section_name);
+ lto_write_raw_data (data, len);
+ lto_free_raw_section_data (file_data, LTO_section_linemap,
+ nullptr, data, len);
+ lto_end_section ();
+}
+
+static void
+copy_linemap_sections (lto_file_decl_data *file_data)
+{
+ for (unsigned i = 0; i != file_data->num_linemap_sections; ++i)
+ copy_linemap_section (file_data, i);
+}
+
+/* Copy all the linemaps we read into an object file so LTRANS can find them
+ later. */
+
+void
+lto_copy_linemaps ()
+{
+ timevar_push (TV_IPA_LTO_LINEMAP_COPY);
+ lto_streamer_init ();
+ lto_push_out_decl_state (nullptr);
+
+ /* In WPA, we write these out to a standalone file; give it an LTO header
+ section. */
+ if (flag_wpa)
+ produce_lto_section ();
+
+ for (auto file_data = lto_get_file_decl_data (); *file_data; ++file_data)
+ copy_linemap_sections (*file_data);
+
+ lto_pop_out_decl_state ();
+ timevar_pop (TV_IPA_LTO_LINEMAP_COPY);
+}
+
/* Compare symbols to get them sorted by filename (to optimize streaming) */
static int
}
}
+/* When WPA writes out its outputs, there are two different ways a location
+ may be streamed out: either streamed freshly, e.g. when trees are
+ streamed out in the decls section, or else copied verbatim from the input
+ files. In the former case, we need to remember how a location_t was
+ originally referenced in the input data, so we can stream it out the same
+ way; otherwise it would be necessary to stream out a new linemap section
+ just for WPA-generated locations, which would a) be wasteful given that
+ all locations originated from one of the linemap sections that already
+ exists and b) inhibit incremental LTO since a change to one partition
+ would affect the linemap for all of them. */
+
+void lto_register_linemap_for_output (size_t map_idx, unsigned linemap_id)
+{
+ loc_output.register_map_id (map_idx, linemap_id);
+}
+
/* Main entry point from the pass manager. */
void
struct lto_out_decl_state *state)
{
unsigned i;
- unsigned ref;
+ uint32_t ref, lm_order;
tree decl;
/* Write reference to FUNCTION_DECL. If there is not function,
write reference to void_type_node. */
decl = (state->fn_decl) ? state->fn_decl : void_type_node;
streamer_tree_cache_lookup (ob->writer_cache, decl, &ref);
- gcc_assert (ref != (unsigned)-1);
+ gcc_assert (ref != (uint32_t)-1);
ref = ref * 2 + (state->compressed ? 1 : 0);
lto_write_data (&ref, sizeof (uint32_t));
-
+ if (state->fn_decl)
+ {
+ lm_order = state->linemap_id;
+ lto_write_data (&lm_order, sizeof (lm_order));
+ }
for (i = 0; i < LTO_N_DECL_STREAMS; i++)
write_global_references (ob, &state->streams[i]);
}
size_t size;
size = sizeof (int32_t); /* fn_ref. */
+ if (state->fn_decl)
+ size += sizeof (int32_t); /* linemap_id. */
for (i = 0; i < LTO_N_DECL_STREAMS; i++)
{
size += sizeof (int32_t); /* vector size. */
destroy_output_block (ob);
if (lto_stream_offload_p)
lto_write_mode_table ();
+
+ /* Copy or write the linemap section(s) as needed. For incremental LTO, we
+ copy them into the output file now. For WPA, we will copy them into a
+ dedicated file later. Otherwise, we create a new one from scratch and
+ output it now. */
+ if (flag_incremental_link == INCREMENTAL_LINK_LTO)
+ lto_copy_linemaps ();
+ else if (!flag_wpa)
+ {
+ gcc_checking_assert (!in_lto_p);
+ loc_output.produce_linemap_section ();
+ }
}
}
-/* Get a section name for a particular type or name. The NAME field
- is only used if SECTION_TYPE is LTO_section_function_body. For all
- others it is ignored. The callee of this function is responsible
- to free the returned name. */
+/* Get a section name for a particular type or name. The NAME and NODE_ORDER
+ fields are only used if SECTION_TYPE is LTO_section_function_body or
+ LTO_section_linemap. The callee of this function is responsible for freeing
+ the returned name. */
char *
lto_get_section_name (int section_type, const char *name,
{
const char *add;
char post[32];
- const char *sep;
+ const char *sep = ".";
char *buffer = NULL;
if (section_type == LTO_section_function_body)
add = buffer;
sep = "";
}
- else if (section_type < LTO_N_SECTION_TYPES)
+ else if (section_type == LTO_section_linemap)
{
- add = lto_section_name[section_type];
- sep = ".";
+ gcc_checking_assert (!name);
+ const auto section_name = lto_section_name[section_type];
+ buffer = XNEWVEC (char, strlen (section_name) + 32);
+ sprintf (buffer, "%s.%d", section_name, node_order);
+ add = buffer;
}
+ else if (section_type < LTO_N_SECTION_TYPES)
+ add = lto_section_name[section_type];
else
internal_error ("bytecode stream: unexpected LTO section %s", name);
to terminate the statements and exception
regions within this block.
- 12) STRINGS
+ 13) STRINGS
String are represented in the table as pairs, a length in ULEB128
form followed by the data for the string. */
LTO_section_ipa_sra,
LTO_section_odr_types,
LTO_section_ipa_modref,
+ LTO_section_linemap,
LTO_N_SECTION_TYPES /* Must be last. */
};
const char *,
size_t);
-/* The location cache holds expanded locations for streamed in trees.
- This is done to reduce memory usage of libcpp linemap that strongly prefers
- locations to be inserted in the source order. */
+/* Structure to map ordinary_map indices from streamed-in data to
+ the linemap they correspond to. */
+struct GTY(()) lto_loc_map
+{
+ size_t nmaps;
+ size_t map[1];
+};
+/* The location cache holds the ancillary data for streamed in trees. This is
+ done to reduce memory usage in the libcpp linemap; we don't need to create an
+ adhoc location and store the ancillary data if the tree ends up being
+ merged. */
class lto_location_cache
{
public:
void accept_location_cache ();
/* Tree merging did succeed; throw away recent changes. */
void revert_location_cache ();
- void input_location (location_t *loc, struct bitpack_d *bp,
+ void input_location (location_t *dest, struct bitpack_d *bp,
class data_in *data_in);
- void input_location_and_block (location_t *loc, struct bitpack_d *bp,
+ void input_location_and_block (location_t *dest, struct bitpack_d *bp,
class lto_input_block *ib,
class data_in *data_in);
- lto_location_cache ()
- : loc_cache (), accepted_length (0), current_file (NULL), current_line (0),
- current_col (0), current_sysp (false), current_loc (UNKNOWN_LOCATION),
- current_block (NULL_TREE)
+ void set_linemap_offset (unsigned offset) { linemap_offset = offset; }
+
+ explicit lto_location_cache (lto_file_decl_data *loc_data)
+ : decl_data{loc_data}
{
- gcc_assert (!current_cache);
- current_cache = this;
+ if (decl_data)
+ {
+ gcc_assert (!current_cache);
+ current_cache = this;
+ }
}
~lto_location_cache ()
{
- apply_location_cache ();
- gcc_assert (current_cache == this);
- current_cache = NULL;
+ if (decl_data)
+ {
+ apply_location_cache ();
+ gcc_assert (current_cache == this);
+ current_cache = NULL;
+ }
}
- /* There can be at most one instance of location cache (combining multiple
- would bring it out of sync with libcpp linemap); point to current
- one. */
+ /* There can be at most one active instance of location_cache, so that IPA
+ passes can find it if needed; point to current one. */
static lto_location_cache *current_cache;
private:
- static int cmp_loc (const void *pa, const void *pb);
-
struct cached_location
{
- const char *file;
- location_t *loc;
- int line, col;
- bool sysp;
+ location_t *dest;
+ location_t loc;
tree block;
unsigned discr;
};
- /* The location cache. */
+ /* Which linemap section we are using. */
+ lto_file_decl_data *const decl_data;
+ const lto_loc_map *cur_loc_map = nullptr;
+ unsigned linemap_offset = 0;
+ /* The location cache. */
auto_vec<cached_location> loc_cache;
- /* Accepted entries are ones used by trees that are known to be not unified
- by tree merging. */
-
- int accepted_length;
+ /* These keep track of most recently seen values as they are streamed in. */
+ tree stream_block = NULL_TREE;
+ unsigned stream_discr = 0;
+ size_t stream_map_idx = 0;
+ location_t stream_loc_offset = 0;
+ unsigned stream_linemap_order = -1U;
- /* Bookkeeping to remember state in between calls to lto_apply_location_cache
- When streaming gimple, the location cache is not used and thus
- lto_apply_location_cache happens per location basis. It is then
- useful to avoid redundant calls of linemap API. */
+ /* These keep track of most recently accepted values. */
+ cached_location current_cloc = {};
+ location_t current_loc = UNKNOWN_LOCATION;
- const char *current_file;
- int current_line;
- int current_col;
- bool current_sysp;
- location_t current_loc;
- tree current_block;
- unsigned current_discr;
+ /* Accepted entries are ones used by trees that are known to be not unified
+ by tree merging. */
+ unsigned accepted_length = 0;
};
/* Structure used as buffer for reading an LTO file. */
/* True if decl state is compressed. */
bool compressed;
+
+ /* Order of the linemap section to be used for interpreting the locations
+ streamed for this decl. */
+ unsigned linemap_id;
};
typedef struct lto_in_decl_state *lto_in_decl_state_ptr;
/* True if offload tables should be output. */
bool output_offload_tables_p;
+
+ /* Order of the linemap section to be used for interpreting the locations
+ streamed for this decl. */
+ unsigned linemap_id;
};
typedef struct lto_out_decl_state *lto_out_decl_state_ptr;
int unit_base;
unsigned mode_bits;
+
+ /* Number of linemap sections contained in this file. There is typically only
+ 1, but WPA and INCREMENTAL_LINK_LTO modes may create files with more than
+ one linemap. */
+ unsigned num_linemap_sections;
+
+ /* Location maps for locations streamed in this file. */
+ lto_file_decl_data *loc_map_decl_data;
+ vec<lto_loc_map *, va_gc> *loc_maps;
};
+/* Given an input linemap ID, compute how it will be known in the output, given
+ that the output could be the combination of multiple input files. */
+inline unsigned
+lto_linemap_output_id (unsigned linemap_id, const lto_file_decl_data *file_data)
+{
+ return linemap_id + file_data->order;
+}
+
typedef struct lto_file_decl_data *lto_file_decl_data_ptr;
struct lto_char_ptr_base
if we are serializing something else. */
symtab_node *symbol;
- /* These are the last file and line that were seen in the stream.
- If the current node differs from these, it needs to insert
- something into the stream and fix these up. */
- const char *current_file;
- int current_line;
- int current_col;
- bool current_sysp;
- bool reset_locus;
- bool emit_pwd;
+ /* These record the most-recently-streamed values, to avoid streaming
+ them unnecessarily. */
tree current_block;
unsigned current_discr;
+ size_t current_map_idx;
+ location_t current_loc_offset;
+ unsigned current_linemap_id;
/* Cache of nodes written in this section. */
struct streamer_tree_cache_d *writer_cache;
/* Cache of source code location. */
lto_location_cache location_cache;
+
+ explicit data_in (lto_file_decl_data *data_for_loc)
+ : location_cache{data_for_loc}
+ {}
};
extern void lto_input_toplevel_asms (struct lto_file_decl_data *, int);
extern void lto_input_mode_table (struct lto_file_decl_data *);
extern class data_in *lto_data_in_create (struct lto_file_decl_data *,
- const char *, unsigned,
- vec<ld_plugin_symbol_resolution_t> );
+ const char *, unsigned,
+ vec<ld_plugin_symbol_resolution_t>,
+ bool need_location_cache = true);
extern void lto_data_in_delete (class data_in *);
extern void lto_input_data_block (class lto_input_block *, void *, size_t);
void lto_input_location (location_t *, struct bitpack_d *, class data_in *);
extern void produce_asm (struct output_block *ob);
extern void lto_output ();
extern void produce_asm_for_decls ();
+void lto_register_linemap_for_output (size_t, unsigned);
+void lto_copy_linemaps ();
void lto_output_decl_state_streams (struct output_block *,
struct lto_out_decl_state *);
void lto_output_decl_state_refs (struct output_block *,
for (i = 0; i < ltoobj_argc; ++i)
obstack_ptr_grow (&argv_obstack, ltoobj_argv[i]);
obstack_ptr_grow (&argv_obstack, NULL);
+ obstack_ptr_grow (&argv_obstack, NULL);
new_argv = XOBFINISH (&argv_obstack, const char **);
argv_ptr = &new_argv[new_head_argc];
/* Parse the list of LTRANS inputs from the WPA stage. */
obstack_init (&env_obstack);
nr = 0;
+ const char *linemap_name = nullptr;
+ char *linemap_arg = nullptr;
for (;;)
{
const unsigned piece = 32;
}
input_name[len - 1] = '\0';
+ if (!linemap_arg)
+ {
+ constexpr auto lf_opt = "-fltrans-linemap-file=";
+ linemap_arg = concat (lf_opt, input_name, nullptr);
+ free (input_name);
+ linemap_name = linemap_arg + strlen (lf_opt);
+ continue;
+ }
+
if (input_name[0] == '*')
output_name = &input_name[1];
argv_ptr[2] = "-o";
argv_ptr[3] = output_name;
argv_ptr[4] = input_name;
- argv_ptr[5] = NULL;
+ argv_ptr[5] = linemap_arg;
+ argv_ptr[6] = NULL;
if (parallel)
{
fprintf (mstream, "%s:\n\t@%s ", output_name, new_argv[0]);
if (early_debug_object_names[i] != NULL)
printf ("%s\n", early_debug_object_names[i]);
}
+
+ if (linemap_arg)
+ {
+ /* This should be done even if(ltrans_cache), since the linemap file
+ changes when any of the inputs changes and is not part of the
+ cache. */
+ maybe_unlink (linemap_name);
+ free (linemap_arg);
+ }
+
nr = 0;
free (ltrans_priorities);
free (output_names);
LTO Joined Var(ltrans_output_list)
Specify a file to which a list of files output by LTRANS is written.
+fltrans-linemap-file=
+LTO Joined Var(ltrans_linemap_file)
+Specify the object file containing copied linemap sections; used internally during LTRANS phase.
+
fresolution=
LTO Joined
The resolution file.
gcc_assert (decl == void_type_node);
decl = NULL_TREE;
}
+ else
+ state->linemap_id = *data++;
+
state->fn_decl = decl;
for (i = 0; i < LTO_N_DECL_STREAMS; i++)
return sscanf (s, "." HOST_WIDE_INT_PRINT_HEX_PURE, id) == 1;
}
+/* Return the linemap ID if NAME refers to an LTO linemap section,
+ otherwise -1U. */
+
+static unsigned linemap_section_id (const char *name)
+{
+ const int prefix_len = strlen (section_name_prefix);
+ gcc_checking_assert (!strncmp (name, section_name_prefix, prefix_len));
+ name += prefix_len;
+ if (*name++ != '.')
+ return -1U;
+ const auto lm_name = lto_section_name[LTO_section_linemap];
+ const int lm_len = strlen (lm_name);
+ if (strncmp (name, lm_name, lm_len))
+ return -1U;
+ name += lm_len;
+ unsigned linemap_id;
+ return sscanf (name, ".%u", &linemap_id) == 1 ? linemap_id : -1U;
+}
+
/* Create file_data of each sub file id. */
static int
list->last = file_data;
}
+ const auto lsid = linemap_section_id (ls->name);
+ file_data->num_linemap_sections = MAX (file_data->num_linemap_sections,
+ lsid + 1);
+
/* Copy section into sub module hash table. */
new_name = XDUPVEC (char, ls->name, strlen (ls->name) + 1);
s_slot.name = new_name;
return 1;
}
+/* In LTRANS, the linemap data is all stored in a separate object, namely this
+ one. */
+static GTY(()) lto_file_decl_data *loc_map_decl_data;
+
/* Read declarations and other initializations for a FILE_DATA. */
static void
resolutions[rp->index] = rp->res;
file_data->respairs.release ();
- file_data->renaming_hash_table = lto_create_renaming_table ();
file_data->file_name = file->filename;
file_data->order = order;
file_data->lto_section_header.minor_version,
file_data->file_name);
+ if (flag_ltrans)
+ {
+ if (!loc_map_decl_data)
+ /* This is not a real LTRANS file; it is just here to hold the line
+ maps. */
+ return;
+ else
+ file_data->loc_map_decl_data = loc_map_decl_data;
+ }
+
+ file_data->renaming_hash_table = lto_create_renaming_table ();
+
#ifdef ACCEL_COMPILER
lto_input_mode_table (file_data);
#else
lto_resolution_read (file_ids, resolution_file, file);
/* Finalize each lto file for each submodule in the merged object. */
- int order = 0;
+ static int order = 0;
for (file_data = file_list.first; file_data != NULL;
file_data = file_data->next)
- lto_create_files_from_ids (file, file_data, count, order++);
+ {
+ lto_create_files_from_ids (file, file_data, count, order);
+ order += file_data->num_linemap_sections;
+ }
splay_tree_delete (file_ids);
htab_delete (section_hash_table);
if (!quiet_flag)
fprintf (stderr, "Reading object files:");
+ if (flag_ltrans)
+ {
+ if (!ltrans_linemap_file)
+ fatal_error (UNKNOWN_LOCATION,
+ "%<-fltrans-linemap-file%> is required with %<-fltrans%>");
+ if (!quiet_flag)
+ {
+ fprintf (stderr, " %s", ltrans_linemap_file);
+ fflush (stderr);
+ }
+ current_lto_file = lto_obj_file_open (ltrans_linemap_file, false);
+ int lm_count = 0;
+ if (!(current_lto_file
+ && (loc_map_decl_data = lto_file_read (current_lto_file, resolution,
+ &lm_count))
+ && lm_count == 1
+ && loc_map_decl_data->next == nullptr))
+ fatal_error (UNKNOWN_LOCATION,
+ "unexpected error reading LTRANS linemap section from %qs",
+ ltrans_linemap_file);
+ lto_obj_file_close (current_lto_file);
+ free (current_lto_file);
+ current_lto_file = nullptr;
+ }
+
/* Read all of the object files specified on the command line. */
for (i = 0, last_file_ix = 0; i < nfiles; ++i)
{
/* Indicate that the cgraph is built and ready. */
symtab->function_flags_ready = true;
- ggc_free (all_file_decl_data);
- all_file_decl_data = NULL;
+
+ /* N.B. No longer calling ggc_free (all_file_decl_data) here; it is helpful to
+ keep the ordered list of files available e.g. for lto_copy_linemaps(). */
}
timevar_pop (lto_timer);
}
+/* Stream out all the linemap sections so they are available for LTRANS. */
+
+static void
+stream_out_linemaps (const char *filename)
+{
+ const auto file = lto_obj_file_open (filename, true);
+ if (!file)
+ fatal_error (input_location, "%<lto_obj_file_open()%> failed");
+ lto_set_current_out_file (file);
+ lto_copy_linemaps ();
+ free (const_cast<char *> (file->filename));
+ lto_set_current_out_file (nullptr);
+ lto_obj_file_close (file);
+ free (file);
+}
+
/* Actually stream out ENCODER into TEMP_FILENAME. */
static void
sets_per_worker = (n_sets + lto_parallelism - 1) / lto_parallelism;
}
+ /* Write out all the linemaps since they will be needed during LTRANS. */
+ sprintf (temp_filename + blen, "%u.o", n_sets);
+ const auto linemap_filename = xstrdup (temp_filename);
+ stream_out_linemaps (linemap_filename);
+
+ /* Write out the partitions. */
for (i = 0; i < n_sets; i++)
{
ltrans_partition part = ltrans_partitions[i];
if (ltrans_output_list_stream == NULL)
fatal_error (input_location,
"opening LTRANS output list %s: %m", ltrans_output_list);
+ fprintf (ltrans_output_list_stream, "0\n%s\n", linemap_filename);
+ free (linemap_filename);
for (i = 0; i < n_sets; i++)
{
unsigned int len = strlen (temp_filenames[i]);
case OPT_nostdinc__:
case OPT_fpreprocessed:
case OPT_fltrans_output_list_:
+ case OPT_fltrans_linemap_file_:
case OPT_fresolution_:
case OPT_fdebug_prefix_map_:
case OPT_fmacro_prefix_map_:
outest "$b-292 lto sing nameddir-2" $sing "-o dir/$b.exe -O2 -flto -fno-use-linker-plugin -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf --0.c.???r.final .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
outest "$b-293 lto mult nameddir-2" $mult "-o dir/$b.exe -O2 -flto -fno-use-linker-plugin -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --1.c.???r.final --2.c.???i.icf --2.c.???r.final .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}}
if !$skip_atsave {
-outest "$b-294 lto sing unnamed-3" $sing "@$devnull -O2 -flto -fno-use-linker-plugin -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage -save-temps $oaout" {} {{a--0.c.???i.icf a--0.c.???r.final a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a--0.o a--0.s a--0.i a.ltrans0.o a.ltrans.out a.ltrans0.ltrans.o a.ltrans0.ltrans_args a.args.0 a.ltrans0.ltrans.s a.wpa.args.0 a.lto_args a.ld1_args a.ltrans_args a.ltrans0.ltrans.args.0 a.ld_args $aout}}
+outest "$b-294 lto sing unnamed-3" $sing "@$devnull -O2 -flto -fno-use-linker-plugin -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage -save-temps $oaout" {} {{a--0.c.???i.icf a--0.c.???r.final a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a--0.o a--0.s a--0.i a.ltrans0.o a.ltrans1.o a.ltrans.out a.ltrans0.ltrans.o a.ltrans0.ltrans_args a.args.0 a.ltrans0.ltrans.s a.wpa.args.0 a.lto_args a.ld1_args a.ltrans_args a.ltrans0.ltrans.args.0 a.ld_args $aout}}
}
}
outest "$b-336 lto mult empty dumpdir empty dumpbase namedb" $mult "-dumpdir \"\" -dumpbase \"\" -o dir/$b.exe -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{.exe} {-1.c.???i.icf !$ltop -1.c.???r.final !0 -2.c.???i.icf !$ltop -2.c.???r.final !0 .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su}}
# Now -flto with -save-temps, not exhaustive.
-outest "$b-337 lto st sing empty dumpbase unnamed" $sing "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{-0.i -0.s -0.o -0.c.???i.icf !$ltop -0.c.???r.final !!$ltop a.lto_wrapper_args !0 a.wpa.???i.icf a.ltrans.out a.ltrans_args !!$ltop a.res !0 a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.ltrans0.ltrans_args a.ltrans0.ltrans.args.0 a.wpa.args.0 $aout}}
-outest "$b-338 lto st mult empty dumpbase unnamed" $mult "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{-1.i -1.s -1.o -1.c.???i.icf !$ltop -1.c.???r.final !0 -2.i -2.s -2.o -2.c.???i.icf !$ltop -2.c.???r.final !!$ltop a.lto_wrapper_args !0 a.wpa.???i.icf a.ltrans.out a.ltrans_args !!$ltop a.res !0 a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.ltrans0.ltrans_args a.ltrans0.ltrans.args.0 a.wpa.args.0 $aout}}
-outest "$b-339 lto st sing dumpdir empty dumpbase named" $sing "-dumpdir dir/ -dumpbase \"\" -o $b-0.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.i -0.s -0.o -0.c.???i.icf !$ltop -0.c.???r.final !!$ltop -0.lto_wrapper_args !0 -0.wpa.???i.icf -0.ltrans.out -0.ltrans_args !!$ltop -0.res !0 -0.ltrans0.o -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su -0.ltrans0.ltrans.s -0.ltrans0.ltrans.o -0.ltrans0.ltrans_args -0.ltrans0.ltrans.args.0 -0.wpa.args.0} {-0.exe}}
-outest "$b-340 lto st mult dumpdir empty dumpbase named" $mult "-dumpdir dir/ -dumpbase \"\" -o $b-1.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.i -1.s -1.o -1.c.???i.icf !$ltop -1.c.???r.final !0 -2.i -2.s -2.o -2.c.???i.icf !$ltop -2.c.???r.final !!$ltop -1.lto_wrapper_args !0 -1.wpa.???i.icf -1.ltrans.out -1.ltrans_args !!$ltop -1.res !0 -1.ltrans0.o -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su -1.ltrans0.ltrans.s -1.ltrans0.ltrans.o -1.ltrans0.ltrans_args -1.ltrans0.ltrans.args.0 -1.wpa.args.0} {-1.exe}}
-outest "$b-341 lto st sing empty dumpbase namedb" $sing "-dumpbase \"\" -o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.i -0.s -0.o -0.c.???i.icf !$ltop -0.c.???r.final !!$ltop .lto_wrapper_args !0 .wpa.???i.icf .ltrans.out .ltrans_args !!$ltop .res !0 .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .ltrans0.ltrans_args .ltrans0.ltrans.args.0 .wpa.args.0 .exe} {}}
-outest "$b-342 lto st mult empty dumpbase namedb" $mult "-dumpbase \"\" -o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.i -1.s -1.o -1.c.???i.icf !$ltop -1.c.???r.final !0 -2.i -2.s -2.o -2.c.???i.icf !$ltop -2.c.???r.final !!$ltop .lto_wrapper_args !0 .wpa.???i.icf .ltrans.out .ltrans_args !!$ltop .res !0 .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .ltrans0.ltrans_args .ltrans0.ltrans.args.0 .wpa.args.0 .exe} {}}
+outest "$b-337 lto st sing empty dumpbase unnamed" $sing "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{-0.i -0.s -0.o -0.c.???i.icf !$ltop -0.c.???r.final !!$ltop a.lto_wrapper_args !0 a.wpa.???i.icf a.ltrans.out a.ltrans_args !!$ltop a.res !0 a.ltrans0.o a.ltrans1.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.ltrans0.ltrans_args a.ltrans0.ltrans.args.0 a.wpa.args.0 $aout}}
+outest "$b-338 lto st mult empty dumpbase unnamed" $mult "-dumpbase \"\" -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{-1.i -1.s -1.o -1.c.???i.icf !$ltop -1.c.???r.final !0 -2.i -2.s -2.o -2.c.???i.icf !$ltop -2.c.???r.final !!$ltop a.lto_wrapper_args !0 a.wpa.???i.icf a.ltrans.out a.ltrans_args !!$ltop a.res !0 a.ltrans0.o a.ltrans1.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.ltrans0.ltrans_args a.ltrans0.ltrans.args.0 a.wpa.args.0 $aout}}
+outest "$b-339 lto st sing dumpdir empty dumpbase named" $sing "-dumpdir dir/ -dumpbase \"\" -o $b-0.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.i -0.s -0.o -0.c.???i.icf !$ltop -0.c.???r.final !!$ltop -0.lto_wrapper_args !0 -0.wpa.???i.icf -0.ltrans.out -0.ltrans_args !!$ltop -0.res !0 -0.ltrans0.o -0.ltrans1.o -0.ltrans0.ltrans.???r.final -0.ltrans0.ltrans.su -0.ltrans0.ltrans.s -0.ltrans0.ltrans.o -0.ltrans0.ltrans_args -0.ltrans0.ltrans.args.0 -0.wpa.args.0} {-0.exe}}
+outest "$b-340 lto st mult dumpdir empty dumpbase named" $mult "-dumpdir dir/ -dumpbase \"\" -o $b-1.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.i -1.s -1.o -1.c.???i.icf !$ltop -1.c.???r.final !0 -2.i -2.s -2.o -2.c.???i.icf !$ltop -2.c.???r.final !!$ltop -1.lto_wrapper_args !0 -1.wpa.???i.icf -1.ltrans.out -1.ltrans_args !!$ltop -1.res !0 -1.ltrans0.o -1.ltrans1.o -1.ltrans0.ltrans.???r.final -1.ltrans0.ltrans.su -1.ltrans0.ltrans.s -1.ltrans0.ltrans.o -1.ltrans0.ltrans_args -1.ltrans0.ltrans.args.0 -1.wpa.args.0} {-1.exe}}
+outest "$b-341 lto st sing empty dumpbase namedb" $sing "-dumpbase \"\" -o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-0.i -0.s -0.o -0.c.???i.icf !$ltop -0.c.???r.final !!$ltop .lto_wrapper_args !0 .wpa.???i.icf .ltrans.out .ltrans_args !!$ltop .res !0 .ltrans0.o .ltrans1.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .ltrans0.ltrans_args .ltrans0.ltrans.args.0 .wpa.args.0 .exe} {}}
+outest "$b-342 lto st mult empty dumpbase namedb" $mult "-dumpbase \"\" -o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{-1.i -1.s -1.o -1.c.???i.icf !$ltop -1.c.???r.final !0 -2.i -2.s -2.o -2.c.???i.icf !$ltop -2.c.???r.final !!$ltop .lto_wrapper_args !0 .wpa.???i.icf .ltrans.out .ltrans_args !!$ltop .res !0 .ltrans0.o .ltrans1.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .ltrans0.ltrans_args .ltrans0.ltrans.args.0 .wpa.args.0 .exe} {}}
# lto save-temps without -dumpbase.
-outest "$b-343 lto st sing unnamed" $sing "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{a--0.i a--0.s a--0.o a--0.c.???i.icf !$ltop a--0.c.???r.final !!$ltop a.lto_wrapper_args !0 a.wpa.???i.icf a.ltrans.out a.ltrans_args !!$ltop a.res !0 a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.ltrans0.ltrans_args a.ltrans0.ltrans.args.0 a.wpa.args.0 $aout}}
-outest "$b-344 lto st mult unnamed" $mult "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{a--1.i a--1.s a--1.o a--1.c.???i.icf !$ltop a--1.c.???r.final !0 a--2.i a--2.s a--2.o a--2.c.???i.icf !$ltop a--2.c.???r.final !!$ltop a.lto_wrapper_args !0 a.wpa.???i.icf a.ltrans.out a.ltrans_args !!$ltop a.res !0 a.ltrans0.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.ltrans0.ltrans_args a.ltrans0.ltrans.args.0 a.wpa.args.0 $aout}}
-outest "$b-345 lto st sing dumpdir named" $sing "-dumpdir dir/$b- -o $b-0.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.i --0.s --0.o --0.c.???i.icf !$ltop --0.c.???r.final !!$ltop -lto_wrapper_args !0 -wpa.???i.icf -ltrans.out -ltrans_args !!$ltop -res !0 -ltrans0.o -ltrans0.ltrans.???r.final -ltrans0.ltrans.su -ltrans0.ltrans.s -ltrans0.ltrans.o -ltrans0.ltrans_args -ltrans0.ltrans.args.0 -wpa.args.0} {-0.exe}}
-outest "$b-346 lto st mult dumpdir named" $mult "-dumpdir dir/$b- -o $b-1.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.i --1.s --1.o --1.c.???i.icf !$ltop --1.c.???r.final !0 --2.i --2.s --2.o --2.c.???i.icf !$ltop --2.c.???r.final !!$ltop -lto_wrapper_args !0 -wpa.???i.icf -ltrans.out -ltrans_args !!$ltop -res !0 -ltrans0.o -ltrans0.ltrans.???r.final -ltrans0.ltrans.su -ltrans0.ltrans.s -ltrans0.ltrans.o -ltrans0.ltrans_args -ltrans0.ltrans.args.0 -wpa.args.0} {-1.exe}}
-outest "$b-347 lto st sing namedb" $sing "-o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.i --0.s --0.o --0.c.???i.icf !$ltop --0.c.???r.final !!$ltop .lto_wrapper_args !0 .wpa.???i.icf .ltrans.out .ltrans_args !!$ltop .res !0 .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .ltrans0.ltrans_args .ltrans0.ltrans.args.0 .wpa.args.0 .exe} {}}
-outest "$b-348 lto st mult namedb" $mult "-o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.i --1.s --1.o --1.c.???i.icf !$ltop --1.c.???r.final !0 --2.i --2.s --2.o --2.c.???i.icf !$ltop --2.c.???r.final !!$ltop .lto_wrapper_args !0 .wpa.???i.icf .ltrans.out .ltrans_args !!$ltop .res !0 .ltrans0.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .ltrans0.ltrans_args .ltrans0.ltrans.args.0 .wpa.args.0 .exe} {}}
+outest "$b-343 lto st sing unnamed" $sing "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{a--0.i a--0.s a--0.o a--0.c.???i.icf !$ltop a--0.c.???r.final !!$ltop a.lto_wrapper_args !0 a.wpa.???i.icf a.ltrans.out a.ltrans_args !!$ltop a.res !0 a.ltrans0.o a.ltrans1.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.ltrans0.ltrans_args a.ltrans0.ltrans.args.0 a.wpa.args.0 $aout}}
+outest "$b-344 lto st mult unnamed" $mult "-save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage $oaout" {} {{a--1.i a--1.s a--1.o a--1.c.???i.icf !$ltop a--1.c.???r.final !0 a--2.i a--2.s a--2.o a--2.c.???i.icf !$ltop a--2.c.???r.final !!$ltop a.lto_wrapper_args !0 a.wpa.???i.icf a.ltrans.out a.ltrans_args !!$ltop a.res !0 a.ltrans0.o a.ltrans1.o a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a.ltrans0.ltrans.s a.ltrans0.ltrans.o a.ltrans0.ltrans_args a.ltrans0.ltrans.args.0 a.wpa.args.0 $aout}}
+outest "$b-345 lto st sing dumpdir named" $sing "-dumpdir dir/$b- -o $b-0.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.i --0.s --0.o --0.c.???i.icf !$ltop --0.c.???r.final !!$ltop -lto_wrapper_args !0 -wpa.???i.icf -ltrans.out -ltrans_args !!$ltop -res !0 -ltrans0.o -ltrans1.o -ltrans0.ltrans.???r.final -ltrans0.ltrans.su -ltrans0.ltrans.s -ltrans0.ltrans.o -ltrans0.ltrans_args -ltrans0.ltrans.args.0 -wpa.args.0} {-0.exe}}
+outest "$b-346 lto st mult dumpdir named" $mult "-dumpdir dir/$b- -o $b-1.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.i --1.s --1.o --1.c.???i.icf !$ltop --1.c.???r.final !0 --2.i --2.s --2.o --2.c.???i.icf !$ltop --2.c.???r.final !!$ltop -lto_wrapper_args !0 -wpa.???i.icf -ltrans.out -ltrans_args !!$ltop -res !0 -ltrans0.o -ltrans1.o -ltrans0.ltrans.???r.final -ltrans0.ltrans.su -ltrans0.ltrans.s -ltrans0.ltrans.o -ltrans0.ltrans_args -ltrans0.ltrans.args.0 -wpa.args.0} {-1.exe}}
+outest "$b-347 lto st sing namedb" $sing "-o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.i --0.s --0.o --0.c.???i.icf !$ltop --0.c.???r.final !!$ltop .lto_wrapper_args !0 .wpa.???i.icf .ltrans.out .ltrans_args !!$ltop .res !0 .ltrans0.o .ltrans1.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .ltrans0.ltrans_args .ltrans0.ltrans.args.0 .wpa.args.0 .exe} {}}
+outest "$b-348 lto st mult namedb" $mult "-o dir/$b.exe -save-temps -O2 -flto -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.i --1.s --1.o --1.c.???i.icf !$ltop --1.c.???r.final !0 --2.i --2.s --2.o --2.c.???i.icf !$ltop --2.c.???r.final !!$ltop .lto_wrapper_args !0 .wpa.???i.icf .ltrans.out .ltrans_args !!$ltop .res !0 .ltrans0.o .ltrans1.o .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .ltrans0.ltrans.s .ltrans0.ltrans.o .ltrans0.ltrans_args .ltrans0.ltrans.args.0 .wpa.args.0 .exe} {}}
# !$skip_lto
}
DEFTIMEVAR (TV_IPA_LTO_CGRAPH_IO , "ipa lto cgraph I/O")
DEFTIMEVAR (TV_IPA_LTO_DECL_MERGE , "ipa lto decl merge")
DEFTIMEVAR (TV_IPA_LTO_CGRAPH_MERGE , "ipa lto cgraph merge")
+DEFTIMEVAR (TV_IPA_LTO_LINEMAP_IN , "ipa lto linemap in")
+DEFTIMEVAR (TV_IPA_LTO_LINEMAP_OUT , "ipa lto linemap out")
+DEFTIMEVAR (TV_IPA_LTO_LINEMAP_COPY , "ipa lto linemap copy")
DEFTIMEVAR (TV_LTO , "lto")
DEFTIMEVAR (TV_WHOPR_WPA , "whopr wpa")
DEFTIMEVAR (TV_WHOPR_WPA_IO , "whopr wpa I/O")