PR65536 is about location-related issues that arise when the LTO front end
reads one or several large object files and runs out of location_t space to
encode all the locations. The main reason for the potential problem is that
the libcpp linemap is designed to be used for incrementally reading source
files (and their included header files) in the natural order. When it is
used in another way, such as by LTO, which adds locations in the order in
which it happened to read different entities, then the assumptions that
justify its design are no longer applicable, and it is not hard to run out
of location_t values (e.g., because of a large number of file changes, or
lines being added out of order.)

The PR remains open because it is not theoretically resolved, but it has
been resolved for all practical purposes by the following two improvements:

    1) The lto_location_cache class now tries hard to optimize the number of
       maps that it creates, especially by sorting the locations before
       adding them. This approach only goes so far, because it can only work
       at the LTO section level, so each function is handled independently
       of the others, but it helps a lot with reducing the number of maps
       required for a single function.

    2) We moved to 64-bit location_t, which means everything is a lot more
       forgiving of wasting location_t space.

Point 2) made this not much of an issue in practice, although sufficiently
large files (especially with very long lines) could still trigger a problem
in theory. While locations are now by and large working fine in LTO, there
was an interesting discussion on PR65536, starting around:

    https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65536#c8

about how the location streaming might be optimized by streaming the linemap
structure itself, rather than a (file name, line number, column number)
triplet for each location. In the end, this approach was not taken because
solution 1) above was adequate and less disruptive. But the arguments
presented in favor of streaming the linemap directly are still interesting.

That discussion did not touch on another topic, namely the need to make
`#pragma GCC diagnostic' usable in LTO. Right now, it does not work, because
the diagnostic pragmas are not streamed out. But even if they were streamed
out, the existing approach to locations in the LTO front end is not
compatible with enforcing the pragmas. Diagnostic pragmas require a global
ordering on location_t values, so that the machinery in option-classifier.cc
can determine which pragmas are in force at each location. This requires
remembering the order in which each source line was encountered, and that is
exactly what is encoded in the linemap. This cannot be reconstructed just
from source file names and line numbers; consider, for example, that the
same file might be used in different translation units or multiple times in
the same translation unit with different diagnostic pragmas in place each
time.

These considerations tip the scales in favor of adding linemap streaming as
Manuel proposed on the PR. This patch prepares to support `#pragma GCC
diagnostic' in the LTO front end by changing the approach to location
streaming along these lines. The new approach has these general
characteristics:

    o There is a new LTO section (LTO_section_linemap) that contains the
      information needed to reconstruct the linemap. There is an entry for
      each line_map_ordinary object that was used by at least one
      streamed-out location. When the LTO front end reads one of these map
      entries, it adds a new map with the corresponding properties to its
      own linemap using the new line_map_add_raw_map interface in libcpp.

    o When a location needs to be output, we stream out two integers: one to
      identify which linemap contains the location, and one containing the
      offset from the start of that map to the location.

    o When the language front ends stream out their data, they produce a
      single linemap section (labeled as linemap.0) that applies to the
      whole translation unit. When WPA prepares partitioned files for
      LTRANS, it may copy function bodies into the LTRANS files without
      reading them, so it needs also to copy the linemap sections they refer
      to. Since the same linemap section will often be needed by more than
      one partition, this is done by putting all of the linemap sections
      into one additional object file, which is provided as input to each
      LTRANS process via the new option -fltrans-linemap-file.

    o The naming of the LTRANS linemap sections is stable so as not to
      inhibit incremental LTO.

    o Once the reader has processed the linemap sections, there is no
      further overhead associated with inputting a location, unless it is an
      adhoc location for the purpose of associating a discriminator or a
      tree with the location. For the adhoc location case, the existing
      lto_location_cache setup is still useful to avoid creating unneeded
      adhoc locations, so this has been left in place as before. The
      restriction that there be only one lto_location_cache at a time is no
      longer strictly necessary; but it is still useful so that the IPA
      passes can access the currently active one simply, so I have not
      changed this for now.

With this new setup, PR65536 can be closed.  The subsequent patches in this
series will enable support for diagnostic pragmas.

gcc/lto/ChangeLog:

        * lang.opt: Add -fltrans-linemap-file.
        * lto-common.cc (lto_read_in_decl_state): Read the linemap ID from
        function sections.
        (loc_map_decl_data): New GC root.
        (lto_file_read): Make ORDER into a static variable so it counts
        continuously across all files and sub-files provided on the command
        line.
        (lto_file_finalize): Handle reading the new LTRANS linemap file.
        (read_cgraph_and_symbols): Likewise. Also stop freeing
        ALL_FILE_DECL_DATA at the end; the ordered list of files is now
        useful later on for lto_copy_linemaps().
        * lto.cc (stream_out_linemaps): New function.
        (lto_wpa_write_files): Stream out the linemaps for LTRANS to use.

gcc/testsuite/ChangeLog:

        * gcc.misc-tests/outputs.exp: Adjust LTO -save-temps tests to expect
        the new linemap file.

gcc/ChangeLog:

        * doc/lto.texi: Document the new LTO_section_linemap and the new
        option -fltrans-linemap-file.
        * lto-opts.cc (lto_write_options): Handle the new option.
        * opts.cc (gen_command_line_string): Likewise.
        * lto-section-in.cc (lto_section_name[]): Add new name for
        LTO_section_linemap.
        * lto-streamer-in.cc (get_location_from_idx): New function.
        (lto_location_cache::cmp_loc): Remove.
        (bp_unpack_delta): New function.
        (create_loc_map): New function.
        (get_loc_map): New function.
        (lto_location_cache::override_loc_map): New function.
        (lto_location_cache::apply_location_cache): Pervasive changes to
        implement new location streaming format.
        (lto_location_cache::input_location_and_block): Likewise.
        (lto_location_cache::input_location): Rename argument LOC -> DEST
        for clarity.
        (lto_read_body_or_constructor): Handle LINEMAP_ID in the decl state.
        (lto_data_in_create): Add NEED_LOCATION_CACHE argument. Rename local
        variable DATA_IN to D to avoid clash with the type name.
        * lto-streamer-out.cc (clear_line_info): Update for change to class
        output_block.
        (class location_output): New class.
        (location_output::record_location): New function.
        (bp_pack_delta): New function.
        (location_output::produce_linemap_section): New function.
        (lto_output_location_1): Pervasive changes to implement new location
        streaming format.
        (copy_function_or_variable): Set the LINEMAP_ID in the decl state.
        (copy_linemap_section): New function.
        (lto_copy_linemaps): New function.
        (lto_register_linemap_for_output): New function.
        (lto_output_decl_state_refs): Output the LINEMAP_ID for function
        decls.
        (lto_out_decl_state_written_size): Adapt for new LINEMAP_ID output.
        (produce_asm_for_decls): Output the linemap section when needed.
        * lto-streamer.cc (lto_get_section_name): Handle linemap sections,
        which need an order suffix.
        * lto-streamer.h (enum lto_section_type): Fix typo in the
        comment. Add LTO_section_linemap.
        (struct lto_loc_map): New struct.
        (class lto_location_cache): Pervasive changes to implement new
        location streaming format.
        (struct lto_in_decl_state): Add LINEMAP_ID member.
        (struct lto_out_decl_state): Likewise.
        (struct lto_file_decl_data): Add LOC_MAP_DECL_DATA and LOC_MAPS
        members.
        (struct output_block): Adjust members for new streaming format.
        (data_in::data_in): New function.
        (lto_data_in_create): Adjust prototype for new NEED_LOCATION_CACHE
        argument.
        (lto_register_linemap_for_output): Declare.
        (lto_copy_linemaps): Declare.
        * lto-wrapper.cc (run_gcc): Pass new argument -fltrans-linemap-file.
        * timevar.def (TV_IPA_LTO_LINEMAP_IN): New timevar.
        (TV_IPA_LTO_LINEMAP_OUT): New timevar.
        (TV_IPA_LTO_LINEMAP_COPY): New timevar.
---
 gcc/doc/lto.texi                         |  16 +
 gcc/lto-opts.cc                          |   1 +
 gcc/lto-section-in.cc                    |   1 +
 gcc/lto-streamer-in.cc                   | 415 +++++++++++++----------
 gcc/lto-streamer-out.cc                  | 361 ++++++++++++++++----
 gcc/lto-streamer.cc                      |  21 +-
 gcc/lto-streamer.h                       | 133 +++++---
 gcc/lto-wrapper.cc                       |  25 +-
 gcc/lto/lang.opt                         |   4 +
 gcc/lto/lto-common.cc                    |  52 ++-
 gcc/lto/lto.cc                           |  24 ++
 gcc/opts.cc                              |   1 +
 gcc/timevar.def                          |   3 +
 gcc/testsuite/gcc.misc-tests/outputs.exp |  26 +-
 14 files changed, 741 insertions(+), 342 deletions(-)

diff --git a/gcc/doc/lto.texi b/gcc/doc/lto.texi
index 0e525276f58..ec675553c63 100644
--- a/gcc/doc/lto.texi
+++ b/gcc/doc/lto.texi
@@ -258,6 +258,15 @@ hooks: one for writing the summary and another for reading 
it in.  The
 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
 
 
@@ -575,6 +584,13 @@ local-transformation (LTRANS) mode, which reads in output 
from a
 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
diff --git a/gcc/lto-opts.cc b/gcc/lto-opts.cc
index 62a3fb28063..5dd4a514c82 100644
--- a/gcc/lto-opts.cc
+++ b/gcc/lto-opts.cc
@@ -154,6 +154,7 @@ lto_write_options (void)
        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;
diff --git a/gcc/lto-section-in.cc b/gcc/lto-section-in.cc
index bf8621925dc..f97d1fce13b 100644
--- a/gcc/lto-section-in.cc
+++ b/gcc/lto-section-in.cc
@@ -57,6 +57,7 @@ const char *lto_section_name[LTO_N_SECTION_TYPES] =
   "ipa_sra",
   "odr_types",
   "ipa_modref",
+  "linemap",
 };
 
 /* Hooks so that the ipa passes can call into the lto front end to get
diff --git a/gcc/lto-streamer-in.cc b/gcc/lto-streamer-in.cc
index 2efa1f33967..88e35f18076 100644
--- a/gcc/lto-streamer-in.cc
+++ b/gcc/lto-streamer-in.cc
@@ -376,113 +376,49 @@ canon_file_name (const char *relative_prefix, const char 
*string)
     }
 }
 
+/* Given a map index and offset from the streamed data, convert it to a
+   location_t in the global line map.  */
+
+static location_t
+get_location_from_idx (size_t map_idx, location_t offset,
+                      const lto_loc_map *loc_map)
+{
+  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;
 
-/* Sort locations in source order. Start with file from last application.  */
-
-int
-lto_location_cache::cmp_loc (const void *pa, const void *pb)
-{
-  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;
-}
-
 /* 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;
@@ -505,125 +441,226 @@ lto_location_cache::revert_location_cache ()
   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 neccesary to call apply_location_cache to get *LOC updated.  */
+/* 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)
+{
+  const bool decrease = bp_unpack_value (bp, 1);
+  const Int delta = bp_unpack_var_len_unsigned (bp);
+  return prev = (decrease ? prev - delta : prev + delta);
+}
+
+/* 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);
+
+  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);
+
+  /* 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)
+    {
+      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)
+       {
+         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)
+       lto_register_linemap_for_output (map_idx, file_data->order + 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;
+}
+
+
+/* Force the locations read from now on to be interpreted relative to a
+   different lto_loc_map than the one indicated in the LTO section data.
+   This allows function sections copied for LTRANS to find the linemap
+   section that goes with them.  */
 
 void
-lto_location_cache::input_location_and_block (location_t *loc,
+lto_location_cache::override_loc_map (unsigned linemap_id)
+{
+  gcc_checking_assert (decl_data);
+  cur_loc_map = get_loc_map (decl_data, linemap_id);
+  loc_map_override_p = true;
+}
+
+
+/* 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)
 {
-  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;
+  gcc_checking_assert (decl_data);
 
-  gcc_assert (current_cache == this);
-
-  *loc = bp_unpack_int_in_range (bp, "location", 0,
-                                RESERVED_LOCATION_COUNT + 1);
-
-  if (*loc < RESERVED_LOCATION_COUNT)
+  location_t loc;
+  unsigned this_discr;
+  const bool is_reserved = bp_unpack_value (bp, 1);
+  if (is_reserved)
     {
-      if (ib)
-       {
-         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);
-       }
-      return;
+      loc = bp_unpack_int_in_range (bp, "loc", 0, RESERVED_LOCATION_COUNT - 1);
+      this_discr = 0;
     }
-
-  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);
-
-  if (file_change)
+  else
     {
-      bool pwd_change = bp_unpack_value (bp, 1);
-      if (pwd_change)
+      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;
+         const unsigned linemap_id = bp_unpack_var_len_unsigned (bp);
+         if (loc_map_override_p)
+           /* We should only ever be overriding the loc map for functions
+              copied during WPA, and those would always have used just a single
+              linemap section.  */
+           gcc_assert (linemap_id == 0);
          else
-           stream_relative_path_prefix
-             = canon_relative_path_prefix (pwd, src_pwd);
+           cur_loc_map = get_loc_map (decl_data, linemap_id);
        }
-      stream_file = canon_file_name (stream_relative_path_prefix,
-                                    bp_unpack_string (data_in, bp));
-      stream_sysp = bp_unpack_value (bp, 1);
+      bp_unpack_delta (bp, stream_map_idx);
+      bp_unpack_delta (bp, stream_loc_offset);
+      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 neccesary 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 neccesary 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)
@@ -1633,7 +1670,8 @@ lto_read_body_or_constructor (struct lto_file_decl_data 
*file_data, struct symta
       decl_state = lto_get_function_in_decl_state (file_data, fn_decl);
       gcc_assert (decl_state);
       file_data->current_decl_state = decl_state;
-
+      if (decl_state->linemap_id)
+       data_in->location_cache.override_loc_map (decl_state->linemap_id);
 
       /* Set up the struct function.  */
       from = data_in->reader_cache->nodes.length ();
@@ -2199,15 +2237,16 @@ lto_free_file_name_hash (void)
 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;
 }
 
 
diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc
index 54f6110c933..2a2a40dbcfb 100644
--- a/gcc/lto-streamer-out.cc
+++ b/gcc/lto-streamer-out.cc
@@ -57,17 +57,14 @@ static void lto_write_tree (struct output_block*, tree, 
bool);
 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;
 }
 
 
@@ -181,86 +178,223 @@ tree_is_indexable (tree t)
     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.  */
+class location_output
+{
+public:
+
+  struct map_id_t
+  {
+    size_t idx;
+    unsigned linemap_id;
+  };
+
+  struct location_id_t
+  {
+    map_id_t map_id;
+    location_t offset;
+  };
+
+  location_id_t record_location (location_t loc);
+  void register_map_id (map_id_t map_id) { orig_map_ids.safe_push (map_id); }
+  void produce_linemap_section ();
+
+private:
+  struct map_data
+  {
+    size_t idx;
+    location_t highest_location;
+  };
+  hash_map<nofree_ptr_hash<const line_map_ordinary>, map_data> map_data_map;
+  auto_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)
+    {
+      /* IDX 0 is for reserved locations.  */
+      loc_id.offset = loc;
+      return loc_id;
+    }
+
+  const auto map = linemap_check_ordinary (linemap_lookup (line_table, loc));
+
+  if (flag_wpa)
+    {
+      /* In WPA, we don't create new locations, we only work with what was 
read,
+        so we will re-output it 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;
+    }
+
+  /* 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.highest_location = MAX (md.highest_location, loc);
+  loc_id.map_id.idx = md.idx;
+  loc_id.offset = (loc - map->start_location) >> map->m_range_bits;
+  return loc_id;
+}
+
+/* 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 (map->to_file);
+         if (emit_pwd && remapped && !IS_ABSOLUTE_PATH (remapped))
+           {
+             stream_pwd = true;
+             emit_pwd = false;
+           }
+         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);
+       }
+    }
+
+  /* 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);
+  }
+
+  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);
+
+  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 orig_loc, bool block_p)
+                      location_t loc, bool block_p)
 {
-  location_t loc = LOCATION_LOCUS (orig_loc);
-
-  if (loc >= RESERVED_LOCATION_COUNT)
+  const auto loc_id = loc_output.record_location (loc);
+  if (!loc_id.map_id.idx)
     {
-      expanded_location xloc = expand_location (loc);
-      unsigned discr = get_discriminator_from_loc (orig_loc);
-
-      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;
-       }
-
-      /* 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));
-
-      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);
-
-      if (ob->current_file != xloc.file)
-       {
-         bool stream_pwd = false;
-         const char *remapped = remap_debug_filename (xloc.file);
-         if (ob->emit_pwd && remapped && !IS_ABSOLUTE_PATH (remapped))
-           {
-             stream_pwd = true;
-             ob->emit_pwd = false;
-           }
-         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);
-       }
-      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;
-
-      if (ob->current_col != xloc.column)
-       bp_pack_var_len_unsigned (bp, xloc.column);
-      ob->current_col = xloc.column;
-
-      if (ob->current_discr != discr)
-       bp_pack_var_len_unsigned (bp, discr);
-      ob->current_discr = discr;
+      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;
+       }
+      bp_pack_delta (bp, loc_id.map_id.idx, ob->current_map_idx);
+      bp_pack_delta (bp, loc_id.offset, ob->current_loc_offset);
+      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;
+       }
     }
 }
 
@@ -2671,6 +2805,9 @@ copy_function_or_variable (struct symtab_node *node, int 
output_order)
   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 = file_data->order + 1;
 }
 
 /* Wrap symbol references in *TP inside a type-preserving MEM_REF.  */
@@ -2745,6 +2882,53 @@ produce_lto_section ()
   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)
+{
+  const auto in_section_name
+    = lto_get_section_name (LTO_section_linemap, nullptr, 0,
+                           file_data);
+  const auto out_section_name
+    = lto_get_section_name (LTO_section_linemap, nullptr, file_data->order + 1,
+                           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, 0, &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 ();
+}
+
+
+/* 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);
+  produce_lto_section ();
+  for (auto file_data = lto_get_file_decl_data (); *file_data; ++file_data)
+    copy_linemap_section (*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
@@ -2813,6 +2997,22 @@ create_order_remap (lto_symtab_encoder_t encoder)
     }
 }
 
+/* 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
@@ -3029,17 +3229,21 @@ lto_output_decl_state_refs (struct output_block *ob,
                            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]);
 }
@@ -3054,6 +3258,8 @@ lto_out_decl_state_written_size (struct 
lto_out_decl_state *state)
   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. */
@@ -3503,4 +3709,9 @@ produce_asm_for_decls (void)
   destroy_output_block (ob);
   if (lto_stream_offload_p)
     lto_write_mode_table ();
+
+  /* Write the linemap section.  During WPA, we copy all needed linemaps later,
+     and do not generate our own new one here.  */
+  if (!flag_wpa)
+    loc_output.produce_linemap_section ();
 }
diff --git a/gcc/lto-streamer.cc b/gcc/lto-streamer.cc
index e4a19617763..d264e76bc76 100644
--- a/gcc/lto-streamer.cc
+++ b/gcc/lto-streamer.cc
@@ -94,10 +94,10 @@ lto_tag_name (enum LTO_tags tag)
 }
 
 
-/* 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,
@@ -105,7 +105,7 @@ 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)
@@ -120,11 +120,16 @@ lto_get_section_name (int section_type, const char *name,
       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);
 
diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
index c7c6c8fbf06..734fecb070f 100644
--- a/gcc/lto-streamer.h
+++ b/gcc/lto-streamer.h
@@ -116,7 +116,7 @@ along with GCC; see the file COPYING3.  If not see
                          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.  */
@@ -225,6 +225,7 @@ enum lto_section_type
   LTO_section_ipa_sra,
   LTO_section_odr_types,
   LTO_section_ipa_modref,
+  LTO_section_linemap,
   LTO_N_SECTION_TYPES          /* Must be last.  */
 };
 
@@ -258,79 +259,90 @@ typedef void (lto_free_section_data_f) (struct 
lto_file_decl_data *,
                                        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:
   /* Apply all changes in location cache.  Add locations into linemap and patch
      trees.  */
   bool apply_location_cache ();
-  /* Tree merging did not suceed; mark all changes in the cache as accepted.  
*/
+  /* Tree merging did not succeed; mark all changes in the cache as
+     accepted.  */
   void accept_location_cache ();
-  /* Tree merging did suceed; throw away recent changes.  */
+  /* 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 override_loc_map (unsigned linemap_id);
+
+  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;
+  bool loc_map_override_p = false;
 
+  /* The location cache.  */
   auto_vec<cached_location> loc_cache;
 
+  /* 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;
+  size_t stream_loc_offset = 0;
+  unsigned stream_linemap_order = -1U;
+
+  /* These keep track of most recently accepted values.  */
+  cached_location current_cloc = {};
+  location_t current_loc = UNKNOWN_LOCATION;
+
   /* Accepted entries are ones used by trees that are known to be not unified
      by tree merging.  */
-
-  int accepted_length;
-
-  /* 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.  */
-
-  const char *current_file;
-  int current_line;
-  int current_col;
-  bool current_sysp;
-  location_t current_loc;
-  tree current_block;
-  unsigned current_discr;
+  unsigned accepted_length = 0;
 };
 
 /* Structure used as buffer for reading an LTO file.  */
@@ -506,6 +518,10 @@ struct GTY((for_user)) lto_in_decl_state
 
   /* 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;
@@ -545,6 +561,10 @@ struct lto_out_decl_state
 
   /* 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;
@@ -616,6 +636,10 @@ struct GTY(()) lto_file_decl_data
   int unit_base;
 
   unsigned mode_bits;
+
+  /* Location maps for locations streamed in this file.  */
+  lto_file_decl_data *loc_map_decl_data;
+  vec<lto_loc_map *, va_gc> *loc_maps;
 };
 
 typedef struct lto_file_decl_data *lto_file_decl_data_ptr;
@@ -727,17 +751,13 @@ struct output_block
      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;
@@ -772,6 +792,10 @@ public:
 
   /* 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}
+  {}
 };
 
 
@@ -868,8 +892,9 @@ extern void lto_input_constructors_and_inits (struct 
lto_file_decl_data *,
 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 *);
@@ -901,6 +926,8 @@ extern void lto_output_toplevel_asms (lto_symtab_encoder_t);
 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 *,
diff --git a/gcc/lto-wrapper.cc b/gcc/lto-wrapper.cc
index ae63dbb8263..42e76c9d595 100644
--- a/gcc/lto-wrapper.cc
+++ b/gcc/lto-wrapper.cc
@@ -1926,6 +1926,7 @@ cont1:
   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];
@@ -1975,6 +1976,8 @@ cont1:
       /* 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;
@@ -2003,6 +2006,15 @@ cont:
            }
          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];
 
@@ -2133,7 +2145,8 @@ cont:
          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]);
@@ -2252,6 +2265,16 @@ cont:
            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);
diff --git a/gcc/lto/lang.opt b/gcc/lto/lang.opt
index e4ca1b60552..dfaa9d9b805 100644
--- a/gcc/lto/lang.opt
+++ b/gcc/lto/lang.opt
@@ -57,6 +57,10 @@ fltrans-output-list=
 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 intenerally 
during LTRANS phase.
+
 fresolution=
 LTO Joined
 The resolution file.
diff --git a/gcc/lto/lto-common.cc b/gcc/lto/lto-common.cc
index 80e04268103..3d82f9fa4fe 100644
--- a/gcc/lto/lto-common.cc
+++ b/gcc/lto/lto-common.cc
@@ -195,6 +195,9 @@ lto_read_in_decl_state (class data_in *data_in, const 
uint32_t *data,
       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++)
@@ -2254,6 +2257,10 @@ create_subid_section_table (struct lto_section_slot *ls, 
splay_tree file_ids,
   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
@@ -2274,7 +2281,6 @@ lto_file_finalize (struct lto_file_decl_data *file_data, 
lto_file *file,
     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;
 
@@ -2292,6 +2298,18 @@ lto_file_finalize (struct lto_file_decl_data *file_data, 
lto_file *file,
                     file_data->lto_section_header.minor_version,
                     file_data->file_name);
 
+  if (flag_ltrans)
+    {
+      if (order == 0)
+       /* 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
@@ -2369,7 +2387,7 @@ lto_file_read (lto_file *file, FILE *resolution_file, int 
*count)
   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++);
@@ -2812,6 +2830,31 @@ read_cgraph_and_symbols (unsigned nfiles, const char 
**fnames)
   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)
     {
@@ -3026,8 +3069,9 @@ read_cgraph_and_symbols (unsigned nfiles, const char 
**fnames)
   /* 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().  */
 }
 
 
diff --git a/gcc/lto/lto.cc b/gcc/lto/lto.cc
index a4b1bc22cdf..0d522e24344 100644
--- a/gcc/lto/lto.cc
+++ b/gcc/lto/lto.cc
@@ -166,6 +166,22 @@ materialize_cgraph (void)
   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
@@ -357,6 +373,12 @@ lto_wpa_write_files (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];
@@ -428,6 +450,8 @@ lto_wpa_write_files (void)
   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]);
diff --git a/gcc/opts.cc b/gcc/opts.cc
index 7f1a0351a6c..71c19956776 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -3942,6 +3942,7 @@ gen_command_line_string (cl_decoded_option *options,
       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_:
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 4f60f04baa1..af38b08a734 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -93,6 +93,9 @@ DEFTIMEVAR (TV_IPA_LTO_CTORS_OUT     , "ipa lto constructors 
out")
 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")
diff --git a/gcc/testsuite/gcc.misc-tests/outputs.exp 
b/gcc/testsuite/gcc.misc-tests/outputs.exp
index 6fd40d714e0..ec6221121d6 100644
--- a/gcc/testsuite/gcc.misc-tests/outputs.exp
+++ b/gcc/testsuite/gcc.misc-tests/outputs.exp
@@ -729,7 +729,7 @@ outest "$b-291 lto mult named-2" $mult "-o $b.exe -O2 -flto 
-fno-use-linker-plug
 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}}
 }
 }
 
@@ -796,20 +796,20 @@ outest "$b-335 lto sing empty dumpdir empty dumpbase 
namedb" $sing "-dumpdir \"\
 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
 }

Reply via email to