]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/lto-streamer-in.c
PR fortran/95090 - ICE: identifier overflow
[thirdparty/gcc.git] / gcc / lto-streamer-in.c
index ee85efc9754b0cd76dea6439eddc2d095ae5bc0b..d0532c5ac51ab61c87f95ca2a14f825b8d90ee75 100644 (file)
@@ -1,6 +1,6 @@
 /* Read the GIMPLE representation from a file stream.
 
-   Copyright (C) 2009-2017 Free Software Foundation, Inc.
+   Copyright (C) 2009-2020 Free Software Foundation, Inc.
    Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
    Re-implemented by Diego Novillo <dnovillo@google.com>
 
@@ -42,21 +42,18 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "cfgloop.h"
 #include "debug.h"
+#include "alloc-pool.h"
 
-
-struct freeing_string_slot_hasher : string_slot_hasher
-{
-  static inline void remove (value_type *);
-};
-
-inline void
-freeing_string_slot_hasher::remove (value_type *v)
-{
-  free (v);
-}
+/* Allocator used to hold string slot entries for line map streaming.  */
+static struct object_allocator<struct string_slot> *string_slot_allocator;
 
 /* The table to hold the file names.  */
-static hash_table<freeing_string_slot_hasher> *file_name_hash_table;
+static hash_table<string_slot_hasher> *file_name_hash_table;
+
+/* This obstack holds file names used in locators. Line map datastructures
+   points here and thus it needs to be kept allocated as long as linemaps
+   exists.  */
+static struct obstack file_name_obstack;
 
 
 /* Check that tag ACTUAL has one of the given values.  NUM_TAGS is the
@@ -84,7 +81,7 @@ lto_tag_check_set (enum LTO_tags actual, int ntags, ...)
 /* Read LENGTH bytes from STREAM to ADDR.  */
 
 void
-lto_input_data_block (struct lto_input_block *ib, void *addr, size_t length)
+lto_input_data_block (class lto_input_block *ib, void *addr, size_t length)
 {
   size_t i;
   unsigned char *const buffer = (unsigned char *) addr;
@@ -113,8 +110,8 @@ canon_file_name (const char *string)
       char *saved_string;
       struct string_slot *new_slot;
 
-      saved_string = (char *) xmalloc (len + 1);
-      new_slot = XCNEW (struct string_slot);
+      saved_string = XOBNEWVEC (&file_name_obstack, char, len + 1);
+      new_slot = string_slot_allocator->allocate ();
       memcpy (saved_string, string, len + 1);
       new_slot->s = saved_string;
       new_slot->len = len;
@@ -232,7 +229,7 @@ lto_location_cache::revert_location_cache ()
 
 void
 lto_location_cache::input_location (location_t *loc, struct bitpack_d *bp,
-                                   struct data_in *data_in)
+                                   class data_in *data_in)
 {
   static const char *stream_file;
   static int stream_line;
@@ -287,7 +284,7 @@ lto_location_cache::input_location (location_t *loc, struct bitpack_d *bp,
 
 void
 lto_input_location (location_t *loc, struct bitpack_d *bp,
-                   struct data_in *data_in)
+                   class data_in *data_in)
 {
   data_in->location_cache.input_location (loc, bp, data_in);
 }
@@ -297,7 +294,7 @@ lto_input_location (location_t *loc, struct bitpack_d *bp,
    discarded.  */
 
 location_t
-stream_input_location_now (struct bitpack_d *bp, struct data_in *data_in)
+stream_input_location_now (struct bitpack_d *bp, class data_in *data_in)
 {
   location_t loc;
   stream_input_location (&loc, bp, data_in);
@@ -313,7 +310,7 @@ stream_input_location_now (struct bitpack_d *bp, struct data_in *data_in)
    function scope for the read tree.  */
 
 tree
-lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
+lto_input_tree_ref (class lto_input_block *ib, class data_in *data_in,
                    struct function *fn, enum LTO_tags tag)
 {
   unsigned HOST_WIDE_INT ix_u;
@@ -378,7 +375,7 @@ lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
    block IB, using descriptors in DATA_IN.  */
 
 static struct eh_catch_d *
-lto_input_eh_catch_list (struct lto_input_block *ib, struct data_in *data_in,
+lto_input_eh_catch_list (class lto_input_block *ib, class data_in *data_in,
                         eh_catch *last_p)
 {
   eh_catch first;
@@ -424,7 +421,7 @@ lto_input_eh_catch_list (struct lto_input_block *ib, struct data_in *data_in,
    in DATA_IN.  */
 
 static eh_region
-input_eh_region (struct lto_input_block *ib, struct data_in *data_in, int ix)
+input_eh_region (class lto_input_block *ib, class data_in *data_in, int ix)
 {
   enum LTO_tags tag;
   eh_region r;
@@ -499,7 +496,7 @@ input_eh_region (struct lto_input_block *ib, struct data_in *data_in, int ix)
    in DATA_IN.  */
 
 static eh_landing_pad
-input_eh_lp (struct lto_input_block *ib, struct data_in *data_in, int ix)
+input_eh_lp (class lto_input_block *ib, class data_in *data_in, int ix)
 {
   enum LTO_tags tag;
   eh_landing_pad lp;
@@ -603,7 +600,7 @@ lto_init_eh (void)
    in DATA_IN.  */
 
 static void
-input_eh_regions (struct lto_input_block *ib, struct data_in *data_in,
+input_eh_regions (class lto_input_block *ib, class data_in *data_in,
                  struct function *fn)
 {
   HOST_WIDE_INT i, root_region, len;
@@ -615,11 +612,6 @@ input_eh_regions (struct lto_input_block *ib, struct data_in *data_in,
 
   lto_tag_check_range (tag, LTO_eh_table, LTO_eh_table);
 
-  /* If the file contains EH regions, then it was compiled with
-     -fexceptions.  In that case, initialize the backend EH
-     machinery.  */
-  lto_init_eh ();
-
   gcc_assert (fn->eh);
 
   root_region = streamer_read_hwi (ib);
@@ -714,9 +706,8 @@ make_new_block (struct function *fn, unsigned int index)
 /* Read the CFG for function FN from input block IB.  */
 
 static void
-input_cfg (struct lto_input_block *ib, struct data_in *data_in,
-          struct function *fn,
-          int count_materialization_scale)
+input_cfg (class lto_input_block *ib, class data_in *data_in,
+          struct function *fn)
 {
   unsigned int bb_count;
   basic_block p_bb;
@@ -756,13 +747,10 @@ input_cfg (struct lto_input_block *ib, struct data_in *data_in,
          unsigned int edge_flags;
          basic_block dest;
          profile_probability probability;
-         profile_count count;
          edge e;
 
          dest_index = streamer_read_uhwi (ib);
          probability = profile_probability::stream_in (ib);
-         count = profile_count::stream_in (ib).apply_scale
-                        (count_materialization_scale, REG_BR_PROB_BASE);
          edge_flags = streamer_read_uhwi (ib);
 
          dest = BASIC_BLOCK_FOR_FN (fn, dest_index);
@@ -772,7 +760,6 @@ input_cfg (struct lto_input_block *ib, struct data_in *data_in,
 
          e = make_edge (bb, dest, edge_flags);
          e->probability = probability;
-         e->count = count;
        }
 
       index = streamer_read_hwi (ib);
@@ -812,7 +799,7 @@ input_cfg (struct lto_input_block *ib, struct data_in *data_in,
          continue;
        }
 
-      struct loop *loop = alloc_loop ();
+      class loop *loop = alloc_loop ();
       loop->header = BASIC_BLOCK_FOR_FN (fn, header_index);
       loop->header->loop_father = loop;
 
@@ -830,8 +817,11 @@ input_cfg (struct lto_input_block *ib, struct data_in *data_in,
 
       /* Read OMP SIMD related info.  */
       loop->safelen = streamer_read_hwi (ib);
+      loop->unroll = streamer_read_hwi (ib);
+      loop->owned_clique = streamer_read_hwi (ib);
       loop->dont_vectorize = streamer_read_hwi (ib);
       loop->force_vectorize = streamer_read_hwi (ib);
+      loop->finite_p = streamer_read_hwi (ib);
       loop->simduid = stream_read_tree (ib, data_in);
 
       place_new_loop (fn, loop);
@@ -850,7 +840,7 @@ input_cfg (struct lto_input_block *ib, struct data_in *data_in,
    block IB.  */
 
 static void
-input_ssa_names (struct lto_input_block *ib, struct data_in *data_in,
+input_ssa_names (class lto_input_block *ib, class data_in *data_in,
                 struct function *fn)
 {
   unsigned int i, size;
@@ -903,6 +893,7 @@ fixup_call_stmt_edges_1 (struct cgraph_node *node, gimple **stmts,
         fatal_error (input_location,
                     "Cgraph edge statement index out of range");
       cedge->call_stmt = as_a <gcall *> (stmts[cedge->lto_stmt_uid - 1]);
+      cedge->lto_stmt_uid = 0;
       if (!cedge->call_stmt)
         fatal_error (input_location,
                     "Cgraph edge statement index not found");
@@ -913,6 +904,7 @@ fixup_call_stmt_edges_1 (struct cgraph_node *node, gimple **stmts,
         fatal_error (input_location,
                     "Cgraph edge statement index out of range");
       cedge->call_stmt = as_a <gcall *> (stmts[cedge->lto_stmt_uid - 1]);
+      cedge->lto_stmt_uid = 0;
       if (!cedge->call_stmt)
         fatal_error (input_location, "Cgraph edge statement index not found");
     }
@@ -923,6 +915,7 @@ fixup_call_stmt_edges_1 (struct cgraph_node *node, gimple **stmts,
          fatal_error (input_location,
                       "Reference statement index out of range");
        ref->stmt = stmts[ref->lto_stmt_uid - 1];
+       ref->lto_stmt_uid = 0;
        if (!ref->stmt)
          fatal_error (input_location, "Reference statement index not found");
       }
@@ -967,8 +960,8 @@ fixup_call_stmt_edges (struct cgraph_node *orig, gimple **stmts)
    using input block IB.  */
 
 static void
-input_struct_function_base (struct function *fn, struct data_in *data_in,
-                            struct lto_input_block *ib)
+input_struct_function_base (struct function *fn, class data_in *data_in,
+                           class lto_input_block *ib)
 {
   struct bitpack_d bp;
   int len;
@@ -1008,6 +1001,7 @@ input_struct_function_base (struct function *fn, struct data_in *data_in,
   fn->has_forced_label_in_static = bp_unpack_value (&bp, 1);
   fn->calls_alloca = bp_unpack_value (&bp, 1);
   fn->calls_setjmp = bp_unpack_value (&bp, 1);
+  fn->calls_eh_return = bp_unpack_value (&bp, 1);
   fn->has_force_vectorize_loops = bp_unpack_value (&bp, 1);
   fn->has_simduid_loops = bp_unpack_value (&bp, 1);
   fn->va_list_fpr_size = bp_unpack_value (&bp, 8);
@@ -1017,20 +1011,28 @@ input_struct_function_base (struct function *fn, struct data_in *data_in,
   /* Input the function start and end loci.  */
   fn->function_start_locus = stream_input_location_now (&bp, data_in);
   fn->function_end_locus = stream_input_location_now (&bp, data_in);
+
+  /* Restore the instance discriminators if present.  */
+  int instance_number = bp_unpack_value (&bp, 1);
+  if (instance_number)
+    {
+      instance_number = bp_unpack_value (&bp, sizeof (int) * CHAR_BIT);
+      maybe_create_decl_to_instance_map ()->put (fn->decl, instance_number);
+    }
 }
 
 
 /* Read the body of function FN_DECL from DATA_IN using input block IB.  */
 
 static void
-input_function (tree fn_decl, struct data_in *data_in,
-               struct lto_input_block *ib, struct lto_input_block *ib_cfg)
+input_function (tree fn_decl, class data_in *data_in,
+               class lto_input_block *ib, class lto_input_block *ib_cfg,
+               cgraph_node *node)
 {
   struct function *fn;
   enum LTO_tags tag;
   gimple **stmts;
   basic_block bb;
-  struct cgraph_node *node;
 
   tag = streamer_read_record_start (ib);
   lto_tag_check (tag, LTO_function);
@@ -1066,11 +1068,8 @@ input_function (tree fn_decl, struct data_in *data_in,
 
   gimple_register_cfg_hooks ();
 
-  node = cgraph_node::get (fn_decl);
-  if (!node)
-    node = cgraph_node::create (fn_decl);
   input_struct_function_base (fn, data_in, ib);
-  input_cfg (ib_cfg, data_in, fn, node->count_materialization_scale);
+  input_cfg (ib_cfg, data_in, fn);
 
   /* Read all the SSA names.  */
   input_ssa_names (ib, data_in, fn);
@@ -1130,46 +1129,64 @@ input_function (tree fn_decl, struct data_in *data_in,
             Similarly remove all IFN_*SAN_* internal calls   */
          if (!flag_wpa)
            {
-             if (!MAY_HAVE_DEBUG_STMTS && is_gimple_debug (stmt))
+             if (is_gimple_debug (stmt)
+                 && (gimple_debug_nonbind_marker_p (stmt)
+                     ? !MAY_HAVE_DEBUG_MARKER_STMTS
+                     : !MAY_HAVE_DEBUG_BIND_STMTS))
+               remove = true;
+             /* In case the linemap overflows locations can be dropped
+                to zero.  Thus do not keep nonsensical inline entry markers
+                we'd later ICE on.  */
+             tree block;
+             if (gimple_debug_inline_entry_p (stmt)
+                 && (((block = gimple_block (stmt))
+                      && !inlined_function_outer_scope_p (block))
+                     || !debug_inline_points))
                remove = true;
              if (is_gimple_call (stmt)
                  && gimple_call_internal_p (stmt))
                {
+                 bool replace = false;
                  switch (gimple_call_internal_fn (stmt))
                    {
                    case IFN_UBSAN_NULL:
                      if ((flag_sanitize
                          & (SANITIZE_NULL | SANITIZE_ALIGNMENT)) == 0)
-                       remove = true;
+                       replace = true;
                      break;
                    case IFN_UBSAN_BOUNDS:
                      if ((flag_sanitize & SANITIZE_BOUNDS) == 0)
-                       remove = true;
+                       replace = true;
                      break;
                    case IFN_UBSAN_VPTR:
                      if ((flag_sanitize & SANITIZE_VPTR) == 0)
-                       remove = true;
+                       replace = true;
                      break;
                    case IFN_UBSAN_OBJECT_SIZE:
                      if ((flag_sanitize & SANITIZE_OBJECT_SIZE) == 0)
-                       remove = true;
+                       replace = true;
                      break;
                    case IFN_UBSAN_PTR:
                      if ((flag_sanitize & SANITIZE_POINTER_OVERFLOW) == 0)
-                       remove = true;
+                       replace = true;
                      break;
                    case IFN_ASAN_MARK:
                      if ((flag_sanitize & SANITIZE_ADDRESS) == 0)
-                       remove = true;
+                       replace = true;
                      break;
                    case IFN_TSAN_FUNC_EXIT:
                      if ((flag_sanitize & SANITIZE_THREAD) == 0)
-                       remove = true;
+                       replace = true;
                      break;
                    default:
                      break;
                    }
-                 gcc_assert (!remove || gimple_call_lhs (stmt) == NULL_TREE);
+                 if (replace)
+                   {
+                     gimple_call_set_internal_fn (as_a <gcall *> (stmt),
+                                                  IFN_NOP);
+                     update_stmt (stmt);
+                   }
                }
            }
          if (remove)
@@ -1184,6 +1201,13 @@ input_function (tree fn_decl, struct data_in *data_in,
            {
              gsi_next (&bsi);
              stmts[gimple_uid (stmt)] = stmt;
+
+             /* Remember that the input function has begin stmt
+                markers, so that we know to expect them when emitting
+                debug info.  */
+             if (!cfun->debug_nonbind_markers
+                 && gimple_debug_nonbind_marker_p (stmt))
+               cfun->debug_nonbind_markers = true;
            }
        }
     }
@@ -1197,10 +1221,10 @@ input_function (tree fn_decl, struct data_in *data_in,
     gimple_set_body (fn_decl, bb_seq (ei_edge (ei)->dest));
   }
 
+  update_max_bb_count ();
   fixup_call_stmt_edges (node, stmts);
   execute_all_ipa_stmt_fixups (node, stmts);
 
-  update_ssa (TODO_update_ssa_only_virtuals);
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);
   free (stmts);
@@ -1210,8 +1234,8 @@ input_function (tree fn_decl, struct data_in *data_in,
 /* Read the body of function FN_DECL from DATA_IN using input block IB.  */
 
 static void
-input_constructor (tree var, struct data_in *data_in,
-                  struct lto_input_block *ib)
+input_constructor (tree var, class data_in *data_in,
+                  class lto_input_block *ib)
 {
   DECL_INITIAL (var) = stream_read_tree (ib, data_in);
 }
@@ -1228,7 +1252,7 @@ lto_read_body_or_constructor (struct lto_file_decl_data *file_data, struct symta
                              const char *data, enum lto_section_type section_type)
 {
   const struct lto_function_header *header;
-  struct data_in *data_in;
+  class data_in *data_in;
   int cfg_offset;
   int main_offset;
   int string_offset;
@@ -1271,7 +1295,8 @@ lto_read_body_or_constructor (struct lto_file_decl_data *file_data, struct symta
        {
          lto_input_block ib_cfg (data + cfg_offset, header->cfg_size,
                                  file_data->mode_table);
-         input_function (fn_decl, data_in, &ib_main, &ib_cfg);
+         input_function (fn_decl, data_in, &ib_main, &ib_cfg,
+                         dyn_cast <cgraph_node *>(node));
        }
       else
         input_constructor (fn_decl, data_in, &ib_main);
@@ -1341,7 +1366,7 @@ vec<dref_entry> dref_queue;
    input block IB using the per-file context in DATA_IN.  */
 
 static void
-lto_read_tree_1 (struct lto_input_block *ib, struct data_in *data_in, tree expr)
+lto_read_tree_1 (class lto_input_block *ib, class data_in *data_in, tree expr)
 {
   /* Read all the bitfield values in EXPR.  Note that for LTO, we
      only write language-independent bitfields, so no more unpacking is
@@ -1379,7 +1404,7 @@ lto_read_tree_1 (struct lto_input_block *ib, struct data_in *data_in, tree expr)
    input block IB using the per-file context in DATA_IN.  */
 
 static tree
-lto_read_tree (struct lto_input_block *ib, struct data_in *data_in,
+lto_read_tree (class lto_input_block *ib, class data_in *data_in,
               enum LTO_tags tag, hashval_t hash)
 {
   /* Instantiate a new tree node.  */
@@ -1392,25 +1417,30 @@ lto_read_tree (struct lto_input_block *ib, struct data_in *data_in,
 
   lto_read_tree_1 (ib, data_in, result);
 
-  /* end_marker = */ streamer_read_uchar (ib);
-
   return result;
 }
 
 
 /* Populate the reader cache with trees materialized from the SCC
-   following in the IB, DATA_IN stream.  */
+   following in the IB, DATA_IN stream.
+   If SHARED_SCC is true we input LTO_tree_scc.  */
 
 hashval_t
-lto_input_scc (struct lto_input_block *ib, struct data_in *data_in,
-              unsigned *len, unsigned *entry_len)
+lto_input_scc (class lto_input_block *ib, class data_in *data_in,
+              unsigned *len, unsigned *entry_len, bool shared_scc)
 {
-  /* A blob of unnamed tree nodes, fill the cache from it and
-     recurse.  */
   unsigned size = streamer_read_uhwi (ib);
-  hashval_t scc_hash = streamer_read_uhwi (ib);
+  hashval_t scc_hash = 0;
   unsigned scc_entry_len = 1;
 
+  if (shared_scc)
+    {
+      if (size & 1)
+       scc_entry_len = streamer_read_uhwi (ib);
+      size /= 2;
+      scc_hash = streamer_read_uhwi (ib);
+    }
+
   if (size == 1)
     {
       enum LTO_tags tag = streamer_read_record_start (ib);
@@ -1421,8 +1451,6 @@ lto_input_scc (struct lto_input_block *ib, struct data_in *data_in,
       unsigned int first = data_in->reader_cache->nodes.length ();
       tree result;
 
-      scc_entry_len = streamer_read_uhwi (ib);
-
       /* Materialize size trees by reading their headers.  */
       for (unsigned i = 0; i < size; ++i)
        {
@@ -1431,7 +1459,8 @@ lto_input_scc (struct lto_input_block *ib, struct data_in *data_in,
              || (tag >= LTO_field_decl_ref && tag <= LTO_global_decl_ref)
              || tag == LTO_tree_pickle_reference
              || tag == LTO_integer_cst
-             || tag == LTO_tree_scc)
+             || tag == LTO_tree_scc
+             || tag == LTO_trees)
            gcc_unreachable ();
 
          result = streamer_alloc_tree (ib, data_in, tag);
@@ -1444,7 +1473,6 @@ lto_input_scc (struct lto_input_block *ib, struct data_in *data_in,
          result = streamer_tree_cache_get_tree (data_in->reader_cache,
                                                 first + i);
          lto_read_tree_1 (ib, data_in, result);
-         /* end_marker = */ streamer_read_uchar (ib);
        }
     }
 
@@ -1459,7 +1487,7 @@ lto_input_scc (struct lto_input_block *ib, struct data_in *data_in,
    to previously read nodes.  */
 
 tree
-lto_input_tree_1 (struct lto_input_block *ib, struct data_in *data_in,
+lto_input_tree_1 (class lto_input_block *ib, class data_in *data_in,
                  enum LTO_tags tag, hashval_t hash)
 {
   tree result;
@@ -1497,7 +1525,7 @@ lto_input_tree_1 (struct lto_input_block *ib, struct data_in *data_in,
                                 (a, len, TYPE_PRECISION (type)));
       streamer_tree_cache_append (data_in->reader_cache, result, hash);
     }
-  else if (tag == LTO_tree_scc)
+  else if (tag == LTO_tree_scc || tag == LTO_trees)
     gcc_unreachable ();
   else
     {
@@ -1509,15 +1537,15 @@ lto_input_tree_1 (struct lto_input_block *ib, struct data_in *data_in,
 }
 
 tree
-lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
+lto_input_tree (class lto_input_block *ib, class data_in *data_in)
 {
   enum LTO_tags tag;
 
-  /* Input and skip SCCs.  */
-  while ((tag = streamer_read_record_start (ib)) == LTO_tree_scc)
+  /* Input pickled trees needed to stream in the reference.  */
+  while ((tag = streamer_read_record_start (ib)) == LTO_trees)
     {
       unsigned len, entry_len;
-      lto_input_scc (ib, data_in, &len, &entry_len);
+      lto_input_scc (ib, data_in, &len, &entry_len, false);
 
       /* Register DECLs with the debuginfo machinery.  */
       while (!dref_queue.is_empty ())
@@ -1526,7 +1554,15 @@ lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
          debug_hooks->register_external_die (e.decl, e.sym, e.off);
        }
     }
-  return lto_input_tree_1 (ib, data_in, tag, 0);
+  tree t = lto_input_tree_1 (ib, data_in, tag, 0);
+
+  if (!dref_queue.is_empty ())
+    {
+      dref_entry e = dref_queue.pop ();
+      debug_hooks->register_external_die (e.decl, e.sym, e.off);
+      gcc_checking_assert (dref_queue.is_empty ());
+    }
+  return t;
 }
 
 
@@ -1536,12 +1572,12 @@ void
 lto_input_toplevel_asms (struct lto_file_decl_data *file_data, int order_base)
 {
   size_t len;
-  const char *data = lto_get_section_data (file_data, LTO_section_asm,
-                                          NULL, &len);
+  const char *data
+    = lto_get_summary_section_data (file_data, LTO_section_asm, &len);
   const struct lto_simple_header_with_strings *header
     = (const struct lto_simple_header_with_strings *) data;
   int string_offset;
-  struct data_in *data_in;
+  class data_in *data_in;
   tree str;
 
   if (! data)
@@ -1575,8 +1611,8 @@ void
 lto_input_mode_table (struct lto_file_decl_data *file_data)
 {
   size_t len;
-  const char *data = lto_get_section_data (file_data, LTO_section_mode_table,
-                                          NULL, &len);
+  const char *data
+    = lto_get_summary_section_data (file_data, LTO_section_mode_table, &len);
   if (! data)
     {
       internal_error ("cannot read LTO mode table from %s",
@@ -1589,7 +1625,7 @@ lto_input_mode_table (struct lto_file_decl_data *file_data)
   const struct lto_simple_header_with_strings *header
     = (const struct lto_simple_header_with_strings *) data;
   int string_offset;
-  struct data_in *data_in;
+  class data_in *data_in;
   string_offset = sizeof (*header) + header->main_size;
 
   lto_input_block ib (data + sizeof (*header), header->main_size, NULL);
@@ -1604,10 +1640,10 @@ lto_input_mode_table (struct lto_file_decl_data *file_data)
     {
       enum mode_class mclass
        = bp_unpack_enum (&bp, mode_class, MAX_MODE_CLASS);
-      unsigned int size = bp_unpack_value (&bp, 8);
-      unsigned int prec = bp_unpack_value (&bp, 16);
+      poly_uint16 size = bp_unpack_poly_value (&bp, 16);
+      poly_uint16 prec = bp_unpack_poly_value (&bp, 16);
       machine_mode inner = (machine_mode) bp_unpack_value (&bp, 8);
-      unsigned int nunits = bp_unpack_value (&bp, 8);
+      poly_uint16 nunits = bp_unpack_poly_value (&bp, 16);
       unsigned int ibit = 0, fbit = 0;
       unsigned int real_fmt_len = 0;
       const char *real_fmt_name = NULL;
@@ -1636,16 +1672,16 @@ lto_input_mode_table (struct lto_file_decl_data *file_data)
                                    : GET_CLASS_NARROWEST_MODE (mclass);
             pass ? mr < MAX_MACHINE_MODE : mr != VOIDmode;
             pass ? mr = (machine_mode) (mr + 1)
-                 : mr = GET_MODE_WIDER_MODE (mr))
+                 : mr = GET_MODE_WIDER_MODE (mr).else_void ())
          if (GET_MODE_CLASS (mr) != mclass
-             || GET_MODE_SIZE (mr) != size
-             || GET_MODE_PRECISION (mr) != prec
+             || maybe_ne (GET_MODE_SIZE (mr), size)
+             || maybe_ne (GET_MODE_PRECISION (mr), prec)
              || (inner == m
                  ? GET_MODE_INNER (mr) != mr
                  : GET_MODE_INNER (mr) != table[(int) inner])
              || GET_MODE_IBIT (mr) != ibit
              || GET_MODE_FBIT (mr) != fbit
-             || GET_MODE_NUNITS (mr) != nunits)
+             || maybe_ne (GET_MODE_NUNITS (mr), nunits))
            continue;
          else if ((mclass == MODE_FLOAT || mclass == MODE_DECIMAL_FLOAT)
                   && strcmp (REAL_MODE_FORMAT (mr)->name, real_fmt_name) != 0)
@@ -1662,6 +1698,7 @@ lto_input_mode_table (struct lto_file_decl_data *file_data)
        {
          switch (mclass)
            {
+           case MODE_VECTOR_BOOL:
            case MODE_VECTOR_INT:
            case MODE_VECTOR_FLOAT:
            case MODE_VECTOR_FRACT:
@@ -1677,7 +1714,31 @@ lto_input_mode_table (struct lto_file_decl_data *file_data)
                }
              /* FALLTHRU */
            default:
-             fatal_error (UNKNOWN_LOCATION, "unsupported mode %s\n", mname);
+             /* This is only used for offloading-target compilations and
+                is a user-facing error.  Give a better error message for
+                the common modes; see also mode-classes.def.   */
+             if (mclass == MODE_FLOAT)
+               fatal_error (UNKNOWN_LOCATION,
+                            "%s - %u-bit-precision floating-point numbers "
+                            "unsupported (mode %qs)", TARGET_MACHINE,
+                            prec.to_constant (), mname);
+             else if (mclass == MODE_DECIMAL_FLOAT)
+               fatal_error (UNKNOWN_LOCATION,
+                            "%s - %u-bit-precision decimal floating-point "
+                            "numbers unsupported (mode %qs)", TARGET_MACHINE,
+                            prec.to_constant (), mname);
+             else if (mclass == MODE_COMPLEX_FLOAT)
+               fatal_error (UNKNOWN_LOCATION,
+                            "%s - %u-bit-precision complex floating-point "
+                            "numbers unsupported (mode %qs)", TARGET_MACHINE,
+                            prec.to_constant (), mname);
+             else if (mclass == MODE_INT)
+               fatal_error (UNKNOWN_LOCATION,
+                            "%s - %u-bit integer numbers unsupported (mode "
+                            "%qs)", TARGET_MACHINE, prec.to_constant (), mname);
+             else
+               fatal_error (UNKNOWN_LOCATION, "%s - unsupported mode %qs",
+                            TARGET_MACHINE, mname);
              break;
            }
        }
@@ -1695,7 +1756,23 @@ lto_reader_init (void)
 {
   lto_streamer_init ();
   file_name_hash_table
-    = new hash_table<freeing_string_slot_hasher> (37);
+    = new hash_table<string_slot_hasher> (37);
+  string_slot_allocator = new object_allocator <struct string_slot>
+                               ("line map file name hash");
+  gcc_obstack_init (&file_name_obstack);
+}
+
+/* Free hash table used to stream in location file names.  */
+
+void
+lto_free_file_name_hash (void)
+{
+  delete file_name_hash_table;
+  file_name_hash_table = NULL;
+  delete string_slot_allocator;
+  string_slot_allocator = NULL;
+  /* file_name_obstack must stay allocated since it is referred to by
+     line map table.  */
 }
 
 
@@ -1703,12 +1780,12 @@ lto_reader_init (void)
    table to use with LEN strings.  RESOLUTIONS is the vector of linker
    resolutions (NULL if not using a linker plugin).  */
 
-struct data_in *
+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)
 {
-  struct data_in *data_in = new (struct data_in);
+  class data_in *data_in = new (class data_in);
   data_in->file_data = file_data;
   data_in->strings = strings;
   data_in->strings_len = len;
@@ -1721,7 +1798,7 @@ lto_data_in_create (struct lto_file_decl_data *file_data, const char *strings,
 /* Remove DATA_IN.  */
 
 void
-lto_data_in_delete (struct data_in *data_in)
+lto_data_in_delete (class data_in *data_in)
 {
   data_in->globals_resolution.release ();
   streamer_tree_cache_delete (data_in->reader_cache);