OSDN Git Service

* lto-symtab.c (lto_symtab_entry_def) Add vnode.
[pf3gnuchains/gcc-fork.git] / gcc / lto / lto.c
index d1ccc5a..7aa1f3e 100644 (file)
@@ -84,6 +84,7 @@ lto_materialize_function (struct cgraph_node *node)
   struct lto_file_decl_data *file_data;
   const char *data, *name;
   size_t len;
+  tree step;
 
   /* Ignore clone nodes.  Read the body only from the original one.
      We may find clone nodes during LTRANS after WPA has made inlining
@@ -102,33 +103,46 @@ lto_materialize_function (struct cgraph_node *node)
                               name, &len);
   if (data)
     {
+      struct function *fn;
+
       gcc_assert (!DECL_IS_BUILTIN (decl));
 
       /* This function has a definition.  */
       TREE_STATIC (decl) = 1;
 
       gcc_assert (DECL_STRUCT_FUNCTION (decl) == NULL);
+      allocate_struct_function (decl, false);
 
       /* Load the function body only if not operating in WPA mode.  In
         WPA mode, the body of the function is not needed.  */
       if (!flag_wpa)
        {
-         allocate_struct_function (decl, false);
-         announce_function (node->decl);
          lto_input_function_body (file_data, decl, data);
          lto_stats.num_function_bodies++;
        }
 
+      fn = DECL_STRUCT_FUNCTION (decl);
       lto_free_section_data (file_data, LTO_section_function_body, name,
                             data, len);
-      if (!flag_wpa)
-       ggc_collect ();
+
+      /* Look for initializers of constant variables and private
+        statics.  */
+      for (step = fn->local_decls; step; step = TREE_CHAIN (step))
+       {
+         tree decl = TREE_VALUE (step);
+         if (TREE_CODE (decl) == VAR_DECL
+             && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
+             && flag_unit_at_a_time)
+           varpool_finalize_decl (decl);
+       }
     }
   else
     DECL_EXTERNAL (decl) = 1;
 
   /* Let the middle end know about the function.  */
   rest_of_decl_compilation (decl, 1, 0);
+  if (cgraph_node (decl)->needed)
+    cgraph_mark_reachable_node (cgraph_node (decl));
 }
 
 
@@ -156,7 +170,7 @@ lto_read_in_decl_state (struct data_in *data_in, const uint32_t *data,
   for (i = 0; i < LTO_N_DECL_STREAMS; i++)
     {
       uint32_t size = *data++;
-      tree *decls = GGC_NEWVEC (tree, size);
+      tree *decls = (tree *) xcalloc (size, sizeof (tree));
 
       for (j = 0; j < size; j++)
        {
@@ -221,7 +235,7 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data,
 
   /* Read in per-function decl states and enter them in hash table.  */
   decl_data->function_decl_states =
-    htab_create_ggc (37, lto_hash_in_decl_state, lto_eq_in_decl_state, NULL);
+    htab_create (37, lto_hash_in_decl_state, lto_eq_in_decl_state, free);
 
   for (i = 1; i < num_decl_states; i++)
     {
@@ -362,7 +376,7 @@ lto_file_read (lto_file *file, FILE *resolution_file)
   
   resolutions = lto_resolution_read (resolution_file, file);
 
-  file_data = GGC_NEW (struct lto_file_decl_data);
+  file_data = XCNEW (struct lto_file_decl_data);
   file_data->file_name = file->filename;
   file_data->section_hash_table = lto_obj_build_section_table (file);
   file_data->renaming_hash_table = lto_create_renaming_table ();
@@ -537,15 +551,18 @@ lto_1_to_1_map (void)
 
   for (node = cgraph_nodes; node; node = node->next)
     {
-      /* We will get proper partition based on function they are inlined to.  */
-      if (node->global.inlined_to)
+      /* We will get proper partition based on function they are inlined to or
+        cloned from.  */
+      if (node->global.inlined_to || node->clone_of)
        continue;
       /* Nodes without a body do not need partitioning.  */
-      if (!node->analyzed)
+      if (!node->analyzed || node->same_body_alias)
        continue;
-
+      /* We only need to partition the nodes that we read from the
+        gimple bytecode files.  */
       file_data = node->local.lto_file_data;
-      gcc_assert (!node->same_body_alias && file_data);
+      if (file_data == NULL)
+       continue;
 
       slot = pointer_map_contains (pmap, file_data);
       if (slot)
@@ -567,7 +584,7 @@ lto_1_to_1_map (void)
 
   for (vnode = varpool_nodes; vnode; vnode = vnode->next)
     {
-      if (vnode->alias || !vnode->needed)
+      if (vnode->alias)
        continue;
       slot = pointer_map_contains (vpmap, file_data);
       if (slot)
@@ -691,42 +708,6 @@ lto_add_all_inlinees (cgraph_node_set set)
   lto_bitmap_free (original_decls);
 }
 
-/* Promote variable VNODE to be static.  */
-
-static bool
-promote_var (struct varpool_node *vnode)
-{
-  if (TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl))
-    return false;
-  gcc_assert (flag_wpa);
-  TREE_PUBLIC (vnode->decl) = 1;
-  DECL_VISIBILITY (vnode->decl) = VISIBILITY_HIDDEN;
-  return true;
-}
-
-/* Promote function NODE to be static.  */
-
-static bool
-promote_fn (struct cgraph_node *node)
-{
-  gcc_assert (flag_wpa);
-  if (TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl))
-    return false;
-  TREE_PUBLIC (node->decl) = 1;
-  DECL_VISIBILITY (node->decl) = VISIBILITY_HIDDEN;
-  if (node->same_body)
-    {
-      struct cgraph_node *alias;
-      for (alias = node->same_body;
-          alias; alias = alias->next)
-       {
-         TREE_PUBLIC (alias->decl) = 1;
-         DECL_VISIBILITY (alias->decl) = VISIBILITY_HIDDEN;
-       }
-    }
-  return true;
-}
-
 /* Find out all static decls that need to be promoted to global because
    of cross file sharing.  This function must be run in the WPA mode after
    all inlinees are added.  */
@@ -737,108 +718,58 @@ lto_promote_cross_file_statics (void)
   struct varpool_node *vnode;
   unsigned i, n_sets;
   cgraph_node_set set;
-  varpool_node_set vset;
   cgraph_node_set_iterator csi;
-  varpool_node_set_iterator vsi;
-  VEC(varpool_node_ptr, heap) *promoted_initializers = NULL;
-  struct pointer_set_t *inserted = pointer_set_create ();
 
   gcc_assert (flag_wpa);
 
+  /* At moment we make no attempt to figure out who is refering the variables,
+     so all must become global.  */
+  for (vnode = varpool_nodes; vnode; vnode = vnode->next)
+    if (!vnode->externally_visible && vnode->analyzed)
+       {
+         TREE_PUBLIC (vnode->decl) = 1;
+         DECL_VISIBILITY (vnode->decl) = VISIBILITY_HIDDEN;
+       }
   n_sets = VEC_length (cgraph_node_set, lto_cgraph_node_sets);
   for (i = 0; i < n_sets; i++)
     {
       set = VEC_index (cgraph_node_set, lto_cgraph_node_sets, i);
-      vset = VEC_index (varpool_node_set, lto_varpool_node_sets, i);
 
       /* If node has either address taken (and we have no clue from where)
         or it is called from other partition, it needs to be globalized.  */
       for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
        {
          struct cgraph_node *node = csi_node (csi);
+         bool globalize = node->address_taken || node->local.vtable_method;
+         struct cgraph_edge *e;
          if (node->local.externally_visible)
            continue;
-         if (node->global.inlined_to)
-           continue;
-         if (!DECL_EXTERNAL (node->decl)
-             && (referenced_from_other_partition_p (&node->ref_list, set, vset)
-                 || reachable_from_other_partition_p (node, set)))
-           promote_fn (node);
-       }
-      for (vsi = vsi_start (vset); !vsi_end_p (vsi); vsi_next (&vsi))
-       {
-         vnode = vsi_node (vsi);
-         /* Constant pool references use internal labels and thus can not
-            be made global.  It is sensible to keep those ltrans local to
-            allow better optimization.  */
-         if (!DECL_IN_CONSTANT_POOL (vnode->decl)
-            && !vnode->externally_visible && vnode->analyzed
-            && referenced_from_other_partition_p (&vnode->ref_list,
-                                                  set, vset))
-           promote_var (vnode);
-       }
-
-      /* We export initializers of read-only var into each partition
-        referencing it.  Folding might take declarations from the
-        initializers and use it; so everything referenced from the
-        initializers needs can be accessed from this partition after
-        folding.
-
-        This means that we need to promote all variables and functions
-        referenced from all initializers from readonly vars referenced
-        from this partition that are not in this partition.
-        This needs to be done recursively.  */
-      for (vnode = varpool_nodes; vnode; vnode = vnode->next)
-       if ((TREE_READONLY (vnode->decl) || DECL_IN_CONSTANT_POOL (vnode->decl))
-           && DECL_INITIAL (vnode->decl)
-           && !varpool_node_in_set_p (vnode, vset)
-           && referenced_from_this_partition_p (&vnode->ref_list, set, vset)
-           && !pointer_set_insert (inserted, vnode))
-       VEC_safe_push (varpool_node_ptr, heap, promoted_initializers, vnode);
-      while (!VEC_empty (varpool_node_ptr, promoted_initializers))
-       {
-         int i;
-         struct ipa_ref *ref;
-
-         vnode = VEC_pop (varpool_node_ptr, promoted_initializers);
-         for (i = 0; ipa_ref_list_reference_iterate (&vnode->ref_list, i, ref); i++)
+         for (e = node->callers; e && !globalize; e = e->next_caller)
            {
-             if (ref->refered_type == IPA_REF_CGRAPH)
-               {
-                 struct cgraph_node *n = ipa_ref_node (ref);
-                 gcc_assert (!n->global.inlined_to);
-                 if (!n->local.externally_visible
-                     && !cgraph_node_in_set_p (n, set))
-                   promote_fn (n);
-               }
-             else
-               {
-                 struct varpool_node *v = ipa_ref_varpool_node (ref);
-                 if (varpool_node_in_set_p (v, vset))
-                   continue;
-                 /* Constant pool references use internal labels and thus can not
-                    be made global.  It is sensible to keep those ltrans local to
-                    allow better optimization.  */
-                 if (DECL_IN_CONSTANT_POOL (v->decl))
-                   {
-                     if (!pointer_set_insert (inserted, vnode))
-                       VEC_safe_push (varpool_node_ptr, heap,
-                                      promoted_initializers, v);
-                   }
-                 else if (!DECL_IN_CONSTANT_POOL (v->decl)
-                          && !v->externally_visible && v->analyzed)
-                   {
-                     if (promote_var (v)
-                         && DECL_INITIAL (v->decl) && TREE_READONLY (v->decl)
-                         && !pointer_set_insert (inserted, vnode))
-                       VEC_safe_push (varpool_node_ptr, heap,
-                                      promoted_initializers, v);
-                   }
-               }
+             struct cgraph_node *caller = e->caller;
+             if (caller->global.inlined_to)
+               caller = caller->global.inlined_to;
+             if (!cgraph_node_in_set_p (caller, set))
+               globalize = true;
            }
+         if (globalize)
+            {
+               TREE_PUBLIC (node->decl) = 1;
+               DECL_VISIBILITY (node->decl) = VISIBILITY_HIDDEN;
+               if (node->same_body)
+                 {
+                   struct cgraph_node *alias;
+                   for (alias = node->same_body;
+                        alias; alias = alias->next)
+                     {
+                       TREE_PUBLIC (alias->decl) = 1;
+                       DECL_VISIBILITY (alias->decl) = VISIBILITY_HIDDEN;
+                     }
+                 }
+            }
        }
+
     }
-  pointer_set_destroy (inserted);
 }
 
 
@@ -882,50 +813,57 @@ get_filename_for_set (cgraph_node_set set)
   char *fname = NULL;
   static const size_t max_fname_len = 100;
 
-  /* Create a new temporary file to store SET.  To facilitate
-     debugging, use file names from SET as part of the new
-     temporary file name.  */
-  cgraph_node_set_iterator si;
-  struct pointer_set_t *pset = pointer_set_create ();
-  for (si = csi_start (set); !csi_end_p (si); csi_next (&si))
+  if (cgraph_node_set_needs_ltrans_p (set))
     {
-      struct cgraph_node *n = csi_node (si);
-      const char *node_fname;
-      char *f;
+      /* Create a new temporary file to store SET.  To facilitate
+        debugging, use file names from SET as part of the new
+        temporary file name.  */
+      cgraph_node_set_iterator si;
+      struct pointer_set_t *pset = pointer_set_create ();
+      for (si = csi_start (set); !csi_end_p (si); csi_next (&si))
+       {
+         struct cgraph_node *n = csi_node (si);
+         const char *node_fname;
+         char *f;
 
-      /* Don't use the same file name more than once.  */
-      if (pointer_set_insert (pset, n->local.lto_file_data))
-       continue;
+         /* Don't use the same file name more than once.  */
+         if (pointer_set_insert (pset, n->local.lto_file_data))
+           continue;
 
-      /* The first file name found in SET determines the output
-        directory.  For the remaining files, we use their
-        base names.  */
-      node_fname = n->local.lto_file_data->file_name;
-      if (fname == NULL)
-       {
-         fname = strip_extension (node_fname);
-         continue;
-       }
+         /* The first file name found in SET determines the output
+            directory.  For the remaining files, we use their
+            base names.  */
+         node_fname = n->local.lto_file_data->file_name;
+         if (fname == NULL)
+           {
+             fname = strip_extension (node_fname);
+             continue;
+           }
 
-      f = strip_extension (lbasename (node_fname));
+         f = strip_extension (lbasename (node_fname));
 
-      /* If the new name causes an excessively long file name,
-        make the last component "___" to indicate overflow.  */
-      if (strlen (fname) + strlen (f) > max_fname_len - 3)
-       {
-         fname = reconcat (fname, fname, "___", NULL);
-         break;
-       }
-      else
-       {
-         fname = reconcat (fname, fname, "_", f, NULL);
-         free (f);
+         /* If the new name causes an excessively long file name,
+            make the last component "___" to indicate overflow.  */
+         if (strlen (fname) + strlen (f) > max_fname_len - 3)
+           {
+             fname = reconcat (fname, fname, "___", NULL);
+             break;
+           }
+         else
+           {
+             fname = reconcat (fname, fname, "_", f, NULL);
+             free (f);
+           }
        }
-    }
 
-  pointer_set_destroy (pset);
+      pointer_set_destroy (pset);
 
-  if (!fname)
+      /* Add the extension .wpa.o to indicate that this file has been
+        produced by WPA.  */
+      fname = reconcat (fname, fname, ".wpa.o", NULL);
+      gcc_assert (fname);
+    }
+  else
     {
       /* Since SET does not need to be processed by LTRANS, use
         the original file name and mark it with a '*' prefix so that
@@ -934,13 +872,6 @@ get_filename_for_set (cgraph_node_set set)
       struct cgraph_node *first = csi_node (si);
       fname = prefix_name_with_star (first->local.lto_file_data->file_name);
     }
-  else
-    {
-      /* Add the extension .wpa.o to indicate that this file has been
-        produced by WPA.  */
-      fname = reconcat (fname, fname, ".wpa.o", NULL);
-      gcc_assert (fname);
-    }
 
   return fname;
 }
@@ -998,16 +929,13 @@ lto_wpa_write_files (void)
       temp_filename = get_filename_for_set (set);
       output_files[i] = temp_filename;
 
-      if (cgraph_node_set_nonempty_p (set) || varpool_node_set_nonempty_p (vset))
+      if (cgraph_node_set_needs_ltrans_p (set))
        {
          /* Write all the nodes in SET to TEMP_FILENAME.  */
          file = lto_obj_file_open (temp_filename, true);
          if (!file)
            fatal_error ("lto_obj_file_open() failed");
 
-         if (!quiet_flag)
-           fprintf (stderr, " %s", temp_filename);
-
          lto_set_current_out_file (file);
 
          ipa_write_optimization_summaries (set, vset);
@@ -1028,39 +956,187 @@ lto_wpa_write_files (void)
   return output_files;
 }
 
+/* Template of LTRANS dumpbase suffix.  */
+#define DUMPBASE_SUFFIX        ".ltrans18446744073709551615"
+
 /* Perform local transformations (LTRANS) on the files in the NULL-terminated
    FILES array.  These should have been written previously by
    lto_wpa_write_files ().  Transformations are performed via executing
    COLLECT_GCC for reach file.  */
 
 static void
-lto_write_ltrans_list (char *const *files)
+lto_execute_ltrans (char *const *files)
 {
+  struct pex_obj *pex;
+  const char *collect_gcc_options, *collect_gcc;
+  struct obstack env_obstack;
+  const char **argv;
+  const char **argv_ptr;
+  const char *errmsg;
+  size_t i, j;
+  int err;
+  int status;
   FILE *ltrans_output_list_stream = NULL;
-  unsigned i;
+  bool seen_dumpbase = false;
+  char *dumpbase_suffix = NULL;
+
+  timevar_push (TV_WHOPR_WPA_LTRANS_EXEC);
+
+  /* Get the driver and options.  */
+  collect_gcc = getenv ("COLLECT_GCC");
+  if (!collect_gcc)
+    fatal_error ("environment variable COLLECT_GCC must be set");
+
+  /* Set the CFLAGS environment variable.  */
+  collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS");
+  if (!collect_gcc_options)
+    fatal_error ("environment variable COLLECT_GCC_OPTIONS must be set");
+
+  /* Count arguments.  */
+  i = 0;
+  for (j = 0; collect_gcc_options[j] != '\0'; ++j)
+    if (collect_gcc_options[j] == '\'')
+      ++i;
+
+  if (i % 2 != 0)
+    fatal_error ("malformed COLLECT_GCC_OPTIONS");
+
+  /* Initalize the arguments for the LTRANS driver.  */
+  argv = XNEWVEC (const char *, 8 + i / 2);
+  argv_ptr = argv;
+  *argv_ptr++ = collect_gcc;
+  *argv_ptr++ = "-xlto";
+  for (j = 0; collect_gcc_options[j] != '\0'; ++j)
+    if (collect_gcc_options[j] == '\'')
+      {
+       char *option;
+
+       ++j;
+       i = j;
+       while (collect_gcc_options[j] != '\'')
+         ++j;
+       obstack_init (&env_obstack);
+       obstack_grow (&env_obstack, &collect_gcc_options[i], j - i);
+       if (seen_dumpbase)
+         obstack_grow (&env_obstack, DUMPBASE_SUFFIX,
+                       sizeof (DUMPBASE_SUFFIX));
+       else
+         obstack_1grow (&env_obstack, 0);
+       option = XOBFINISH (&env_obstack, char *);
+       if (seen_dumpbase)
+         {
+           dumpbase_suffix = option + 7 + j - i;
+           seen_dumpbase = false;
+         }
+
+       /* LTRANS does not need -fwpa nor -fltrans-*.  */
+       if (strncmp (option, "-fwpa", 5) != 0
+           && strncmp (option, "-fltrans-", 9) != 0)
+         {
+           if (strncmp (option, "-dumpbase", 9) == 0)
+             seen_dumpbase = true;
+           *argv_ptr++ = option;
+         }
+      }
+  *argv_ptr++ = "-fltrans";
 
   /* Open the LTRANS output list.  */
-  if (!ltrans_output_list)
-    error ("no LTRANS output filename provided");
-
-  ltrans_output_list_stream = fopen (ltrans_output_list, "w");
-  if (ltrans_output_list_stream == NULL)
-    error ("opening LTRANS output list %s: %m", ltrans_output_list);
+  if (ltrans_output_list)
+    {
+      ltrans_output_list_stream = fopen (ltrans_output_list, "w");
+      if (ltrans_output_list_stream == NULL)
+       error ("opening LTRANS output list %s: %m", ltrans_output_list);
+    }
 
   for (i = 0; files[i]; ++i)
     {
       size_t len;
 
-      len = strlen (files[i]);
-      if (fwrite (files[i], 1, len, ltrans_output_list_stream) < len
-         || fwrite ("\n", 1, 1, ltrans_output_list_stream) < 1)
-       error ("writing to LTRANS output list %s: %m",
-              ltrans_output_list);
+      /* If the file is prefixed with a '*', it means that we do not
+        need to re-compile it with LTRANS because it has not been
+        modified by WPA.  Skip it from the command line to
+        lto_execute_ltrans, but add it to ltrans_output_list_stream
+        so it is linked after we are done.  */
+      if (files[i][0] == '*')
+       {
+         size_t len = strlen (files[i]) - 1;
+         if (ltrans_output_list_stream)
+           if (fwrite (&files[i][1], 1, len, ltrans_output_list_stream) < len
+               || fwrite ("\n", 1, 1, ltrans_output_list_stream) < 1)
+             error ("writing to LTRANS output list %s: %m",
+                    ltrans_output_list);
+       }
+      else
+       {
+         char *output_name;
+
+         /* Otherwise, add FILES[I] to lto_execute_ltrans command line
+            and add the resulting file to LTRANS output list.  */
+
+         /* Replace the .o suffix with a .ltrans.o suffix and write
+            the resulting name to the LTRANS output list.  */
+         obstack_init (&env_obstack);
+         obstack_grow (&env_obstack, files[i], strlen (files[i]) - 2);
+         obstack_grow (&env_obstack, ".ltrans.o", sizeof (".ltrans.o"));
+         output_name = XOBFINISH (&env_obstack, char *);
+         if (ltrans_output_list_stream)
+           {
+             len = strlen (output_name);
+
+             if (fwrite (output_name, 1, len, ltrans_output_list_stream) < len
+                 || fwrite ("\n", 1, 1, ltrans_output_list_stream) < 1)
+               error ("writing to LTRANS output list %s: %m",
+                      ltrans_output_list);
+           }
+
+         argv_ptr[0] = "-o";
+         argv_ptr[1] = output_name;
+         argv_ptr[2] = files[i];
+         argv_ptr[3] = NULL;
+
+         /* Append a sequence number to -dumpbase for LTRANS.  */
+         if (dumpbase_suffix)
+           snprintf (dumpbase_suffix, sizeof (DUMPBASE_SUFFIX) - 7,
+                     "%lu", (unsigned long) i);
+
+         /* Execute the driver.  */
+         pex = pex_init (0, "lto1", NULL);
+         if (pex == NULL)
+           fatal_error ("pex_init failed: %s", xstrerror (errno));
+
+         errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0],
+                           CONST_CAST (char **, argv), NULL, NULL, &err);
+         if (errmsg)
+           fatal_error ("%s: %s", errmsg, xstrerror (err));
+
+         if (!pex_get_status (pex, 1, &status))
+           fatal_error ("can't get program status: %s", xstrerror (errno));
+
+         if (status)
+           {
+             if (WIFSIGNALED (status))
+               {
+                 int sig = WTERMSIG (status);
+                 fatal_error ("%s terminated with signal %d [%s]%s",
+                              argv[0], sig, strsignal (sig),
+                              WCOREDUMP (status) ? ", core dumped" : "");
+               }
+             else
+               fatal_error ("%s terminated with status %d", argv[0], status);
+           }
+
+         pex_free (pex);
+       }
     }
 
   /* Close the LTRANS output list.  */
-  if (fclose (ltrans_output_list_stream))
+  if (ltrans_output_list_stream && fclose (ltrans_output_list_stream))
     error ("closing LTRANS output list %s: %m", ltrans_output_list);
+
+  obstack_free (&env_obstack, NULL);
+  free (argv);
+
+  timevar_pop (TV_WHOPR_WPA_LTRANS_EXEC);
 }
 
 
@@ -1374,7 +1450,7 @@ lto_fixup_tree (tree *tp, int *walk_subtrees, void *data)
 
   t = *tp;
   *walk_subtrees = 0;
-  if (!t || pointer_set_contains (fixup_data->seen, t))
+  if (pointer_set_contains (fixup_data->seen, t))
     return NULL;
 
   if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == FUNCTION_DECL)
@@ -1523,6 +1599,20 @@ lto_fixup_decls (struct lto_file_decl_data **files)
   pointer_set_destroy (seen);
 }
 
+/* Unlink a temporary LTRANS file unless requested otherwise.  */
+
+static void
+lto_maybe_unlink (const char *file)
+{
+  if (!getenv ("WPA_SAVE_LTRANS"))
+    {
+      if (unlink_if_ordinary (file))
+        error ("deleting LTRANS input file %s: %m", file);
+    }
+  else
+    fprintf (stderr, "[Leaving LTRANS input file %s]\n", file);
+}
+
 /* Read the options saved from each file in the command line.  Called
    from lang_hooks.post_options which is called by process_options
    right before all the options are used to initialize the compiler.
@@ -1567,7 +1657,6 @@ lto_read_all_file_options (void)
   lto_reissue_options ();
 }
 
-static GTY((length ("lto_stats.num_input_files + 1"))) struct lto_file_decl_data **all_file_decl_data;
 
 /* Read all the symbols from the input files FNAMES.  NFILES is the
    number of files requested in the command line.  Instantiate a
@@ -1578,6 +1667,7 @@ static void
 read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
 {
   unsigned int i, last_file_ix;
+  struct lto_file_decl_data **all_file_decl_data;
   FILE *resolution;
   struct cgraph_node *node;
 
@@ -1586,7 +1676,7 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
   timevar_push (TV_IPA_LTO_DECL_IO);
 
   /* Set the hooks so that all of the ipa passes can read in their data.  */
-  all_file_decl_data = GGC_CNEWVEC (struct lto_file_decl_data *, nfiles + 1);
+  all_file_decl_data = XNEWVEC (struct lto_file_decl_data *, nfiles + 1);
   lto_set_in_hooks (all_file_decl_data, get_section_data, free_section_data);
 
   /* Read the resolution file.  */
@@ -1633,8 +1723,6 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
 
       lto_obj_file_close (current_lto_file);
       current_lto_file = NULL;
-      /* ???  We'd want but can't ggc_collect () here as the type merging
-         code in gimple.c uses hashtables that are not ggc aware.  */
     }
 
   if (resolution_file_name)
@@ -1645,30 +1733,24 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
   /* Set the hooks so that all of the ipa passes can read in their data.  */
   lto_set_in_hooks (all_file_decl_data, get_section_data, free_section_data);
 
+  /* Each pass will set the appropriate timer.  */
   timevar_pop (TV_IPA_LTO_DECL_IO);
 
   if (!quiet_flag)
     fprintf (stderr, "\nReading the callgraph\n");
 
-  timevar_push (TV_IPA_LTO_CGRAPH_IO);
   /* Read the callgraph.  */
   input_cgraph ();
-  timevar_pop (TV_IPA_LTO_CGRAPH_IO);
 
   if (!quiet_flag)
     fprintf (stderr, "Merging declarations\n");
 
-  timevar_push (TV_IPA_LTO_DECL_MERGE);
   /* Merge global decls.  */
   lto_symtab_merge_decls ();
 
   /* Fixup all decls and types and free the type hash tables.  */
   lto_fixup_decls (all_file_decl_data);
   free_gimple_type_tables ();
-  ggc_collect ();
-
-  timevar_pop (TV_IPA_LTO_DECL_MERGE);
-  /* Each pass will set the appropriate timer.  */
 
   if (!quiet_flag)
     fprintf (stderr, "Reading summaries\n");
@@ -1680,9 +1762,7 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
     ipa_read_summaries ();
 
   /* Finally merge the cgraph according to the decl merging decisions.  */
-  timevar_push (TV_IPA_LTO_CGRAPH_MERGE);
   lto_symtab_merge_cgraph_nodes ();
-  ggc_collect ();
 
   if (flag_ltrans)
     for (node = cgraph_nodes; node; node = node->next)
@@ -1696,11 +1776,8 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
                         node->ipa_transforms_to_apply,
                         (ipa_opt_pass)&pass_ipa_inline);
       }
-  lto_symtab_free ();
 
-  timevar_pop (TV_IPA_LTO_CGRAPH_MERGE);
-
-  timevar_push (TV_IPA_LTO_DECL_INIT_IO);
+  timevar_push (TV_IPA_LTO_DECL_IO);
 
   /* FIXME lto. This loop needs to be changed to use the pass manager to
      call the ipa passes directly.  */
@@ -1714,9 +1791,7 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
   /* Indicate that the cgraph is built and ready.  */
   cgraph_function_flags_ready = true;
 
-  timevar_pop (TV_IPA_LTO_DECL_INIT_IO);
-  ggc_free (all_file_decl_data);
-  all_file_decl_data = NULL;
+  timevar_pop (TV_IPA_LTO_DECL_IO);
 }
 
 
@@ -1753,6 +1828,7 @@ materialize_cgraph (void)
       if (node->local.lto_file_data
           && !DECL_IS_BUILTIN (node->decl))
        {
+         announce_function (node->decl);
          lto_materialize_function (node);
          lto_stats.num_input_cgraph_nodes++;
        }
@@ -1788,6 +1864,7 @@ static void
 do_whole_program_analysis (void)
 {
   char **output_files;
+  size_t i;
 
   /* Note that since we are in WPA mode, materialize_cgraph will not
      actually read in all the function bodies.  It only materializes
@@ -1797,12 +1874,6 @@ do_whole_program_analysis (void)
   /* Reading in the cgraph uses different timers, start timing WPA now.  */
   timevar_push (TV_WHOPR_WPA);
 
-  if (pre_ipa_mem_report)
-    {
-      fprintf (stderr, "Memory consumption before IPA\n");
-      dump_memory_report (false);
-    }
-
   cgraph_function_flags_ready = true;
   bitmap_obstack_initialize (NULL);
   ipa_register_cgraph_hooks ();
@@ -1824,21 +1895,22 @@ do_whole_program_analysis (void)
       fflush (stderr);
     }
   output_files = lto_wpa_write_files ();
-  ggc_collect ();
   if (!quiet_flag)
     fprintf (stderr, "\n");
 
-  if (post_ipa_mem_report)
-    {
-      fprintf (stderr, "Memory consumption after IPA\n");
-      dump_memory_report (false);
-    }
-
   /* Show the LTO report before launching LTRANS.  */
   if (flag_lto_report)
     print_lto_report ();
 
-  lto_write_ltrans_list (output_files);
+  lto_execute_ltrans (output_files);
+
+  for (i = 0; output_files[i]; ++i)
+    {
+      if (output_files[i][0] != '*')
+       lto_maybe_unlink (output_files[i]);
+
+      free (output_files[i]);
+    }
 
   XDELETEVEC (output_files);
 }