OSDN Git Service

* lto-symtab.c (lto_symtab_free): New function.
[pf3gnuchains/gcc-fork.git] / gcc / lto / lto.c
index 1608e56..9f6ad40 100644 (file)
@@ -50,6 +50,14 @@ along with GCC; see the file COPYING3.  If not see
 #include <sys/mman.h>
 #endif
 
+/* Handle opening elf files on hosts, such as Windows, that may use 
+   text file handling that will break binary access.  */
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+
 DEF_VEC_P(bitmap);
 DEF_VEC_ALLOC_P(bitmap,heap);
 
@@ -162,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 = (tree *) xcalloc (size, sizeof (tree));
+      tree *decls = GGC_NEWVEC (tree, size);
 
       for (j = 0; j < size; j++)
        {
@@ -227,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 (37, lto_hash_in_decl_state, lto_eq_in_decl_state, free);
+    htab_create_ggc (37, lto_hash_in_decl_state, lto_eq_in_decl_state, NULL);
 
   for (i = 1; i < num_decl_states; i++)
     {
@@ -368,9 +376,9 @@ lto_file_read (lto_file *file, FILE *resolution_file)
   
   resolutions = lto_resolution_read (resolution_file, file);
 
-  file_data = XCNEW (struct lto_file_decl_data);
+  file_data = GGC_NEW (struct lto_file_decl_data);
   file_data->file_name = file->filename;
-  file_data->section_hash_table = lto_elf_build_section_table (file);
+  file_data->section_hash_table = lto_obj_build_section_table (file);
   file_data->renaming_hash_table = lto_create_renaming_table ();
 
   data = lto_get_section_data (file_data, LTO_section_decls, NULL, &len);
@@ -421,7 +429,7 @@ lto_read_section_data (struct lto_file_decl_data *file_data,
   if (fd == -1)
     {
       fd_name = xstrdup (file_data->file_name);
-      fd = open (file_data->file_name, O_RDONLY);
+      fd = open (file_data->file_name, O_RDONLY|O_BINARY);
       if (fd == -1)
        return NULL;
     }
@@ -515,6 +523,7 @@ free_section_data (struct lto_file_decl_data *file_data ATTRIBUTE_UNUSED,
 
 /* Vector of all cgraph node sets. */
 static GTY (()) VEC(cgraph_node_set, gc) *lto_cgraph_node_sets;
+static GTY (()) VEC(varpool_node_set, gc) *lto_varpool_node_sets;
 
 
 /* Group cgrah nodes by input files.  This is used mainly for testing
@@ -524,34 +533,35 @@ static void
 lto_1_to_1_map (void)
 {
   struct cgraph_node *node;
+  struct varpool_node *vnode;
   struct lto_file_decl_data *file_data;
   struct pointer_map_t *pmap;
+  struct pointer_map_t *vpmap;
   cgraph_node_set set;
+  varpool_node_set vset;
   void **slot;
 
   timevar_push (TV_WHOPR_WPA);
 
   lto_cgraph_node_sets = VEC_alloc (cgraph_node_set, gc, 1);
-
-  /* If the cgraph is empty, create one cgraph node set so that there is still
-     an output file for any variables that need to be exported in a DSO.  */
-  if (!cgraph_nodes)
-    {
-      set = cgraph_node_set_new ();
-      VEC_safe_push (cgraph_node_set, gc, lto_cgraph_node_sets, set);
-      goto finish;
-    }
+  lto_varpool_node_sets = VEC_alloc (varpool_node_set, gc, 1);
 
   pmap = pointer_map_create ();
+  vpmap = pointer_map_create ();
 
   for (node = cgraph_nodes; node; node = node->next)
     {
-      /* We only need to partition the nodes that we read from the
-        gimple bytecode files.  */
-      file_data = node->local.lto_file_data;
-      if (file_data == NULL)
+      /* 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)
        continue;
 
+      file_data = node->local.lto_file_data;
+      gcc_assert (!node->same_body_alias && file_data);
+
       slot = pointer_map_contains (pmap, file_data);
       if (slot)
        set = (cgraph_node_set) *slot;
@@ -561,14 +571,50 @@ lto_1_to_1_map (void)
          slot = pointer_map_insert (pmap, file_data);
          *slot = set;
          VEC_safe_push (cgraph_node_set, gc, lto_cgraph_node_sets, set);
+         vset = varpool_node_set_new ();
+         slot = pointer_map_insert (vpmap, file_data);
+         *slot = vset;
+         VEC_safe_push (varpool_node_set, gc, lto_varpool_node_sets, vset);
        }
 
       cgraph_node_set_add (set, node);
     }
 
+  for (vnode = varpool_nodes; vnode; vnode = vnode->next)
+    {
+      if (vnode->alias || !vnode->needed)
+       continue;
+      slot = pointer_map_contains (vpmap, file_data);
+      if (slot)
+       vset = (varpool_node_set) *slot;
+      else
+       {
+         set = cgraph_node_set_new ();
+         slot = pointer_map_insert (pmap, file_data);
+         *slot = set;
+         VEC_safe_push (cgraph_node_set, gc, lto_cgraph_node_sets, set);
+         vset = varpool_node_set_new ();
+         slot = pointer_map_insert (vpmap, file_data);
+         *slot = vset;
+         VEC_safe_push (varpool_node_set, gc, lto_varpool_node_sets, vset);
+       }
+
+      varpool_node_set_add (vset, vnode);
+    }
+
+  /* If the cgraph is empty, create one cgraph node set so that there is still
+     an output file for any variables that need to be exported in a DSO.  */
+  if (!lto_cgraph_node_sets)
+    {
+      set = cgraph_node_set_new ();
+      VEC_safe_push (cgraph_node_set, gc, lto_cgraph_node_sets, set);
+      vset = varpool_node_set_new ();
+      VEC_safe_push (varpool_node_set, gc, lto_varpool_node_sets, vset);
+    }
+
   pointer_map_destroy (pmap);
+  pointer_map_destroy (vpmap);
 
-finish:
   timevar_pop (TV_WHOPR_WPA);
 
   lto_stats.num_cgraph_partitions += VEC_length (cgraph_node_set, 
@@ -581,22 +627,19 @@ finish:
 
 static void
 lto_add_inline_clones (cgraph_node_set set, struct cgraph_node *node,
-                      bitmap original_decls, bitmap inlined_decls)
+                      bitmap original_decls)
 {
    struct cgraph_node *callee;
    struct cgraph_edge *edge;
 
    cgraph_node_set_add (set, node);
 
-   if (!bitmap_bit_p (original_decls, DECL_UID (node->decl)))
-     bitmap_set_bit (inlined_decls, DECL_UID (node->decl));
-
    /* Check to see if NODE has any inlined callee.  */
    for (edge = node->callees; edge != NULL; edge = edge->next_callee)
      {
        callee = edge->callee;
        if (callee->global.inlined_to != NULL)
-         lto_add_inline_clones (set, callee, original_decls, inlined_decls);
+         lto_add_inline_clones (set, callee, original_decls);
      }
 }
 
@@ -604,14 +647,13 @@ lto_add_inline_clones (cgraph_node_set set, struct cgraph_node *node,
    information in the callgraph.  Returns a bitmap of decls that have
    been inlined into SET indexed by UID.  */
 
-static bitmap
+static void
 lto_add_all_inlinees (cgraph_node_set set)
 {
   cgraph_node_set_iterator csi;
   struct cgraph_node *node;
   bitmap original_nodes = lto_bitmap_alloc ();
   bitmap original_decls = lto_bitmap_alloc ();
-  bitmap inlined_decls = lto_bitmap_alloc ();
   bool changed;
 
   /* We are going to iterate SET while adding to it, mark all original
@@ -651,186 +693,17 @@ lto_add_all_inlinees (cgraph_node_set set)
     }
   while (changed);
 
-  /* Transitively add to SET all the inline clones for every node that
-     has been inlined.  */
-  for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
-    {
-      node = csi_node (csi);
-      if (bitmap_bit_p (original_nodes, node->uid))
-       lto_add_inline_clones (set, node, original_decls, inlined_decls);
-    }
-
-  lto_bitmap_free (original_nodes);
-  lto_bitmap_free (original_decls);
-
-  return inlined_decls;
-}
-
-/* Owing to inlining, we may need to promote a file-scope variable
-   to a global variable.  Consider this case:
-
-   a.c:
-   static int var;
-
-   void
-   foo (void)
-   {
-     var++;
-   }
-
-   b.c:
-
-   extern void foo (void);
-
-   void
-   bar (void)
+ /* Transitively add to SET all the inline clones for every node that
+    has been inlined.  */
+ for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
    {
-     foo ();
+     node = csi_node (csi);
+     if (bitmap_bit_p (original_nodes, node->uid))
+      lto_add_inline_clones (set, node, original_decls);
    }
 
-   If WPA inlines FOO inside BAR, then the static variable VAR needs to
-   be promoted to global because BAR and VAR may be in different LTRANS
-   files. */
-
-/* This struct keeps track of states used in globalization.  */
-
-typedef struct
-{
-  /* Current cgraph node set.  */  
-  cgraph_node_set set;
-
-  /* Function DECLs of cgraph nodes seen.  */
-  bitmap seen_node_decls;
-
-  /* Use in walk_tree to avoid multiple visits of a node.  */
-  struct pointer_set_t *visited;
-
-  /* static vars in this set.  */
-  bitmap static_vars_in_set;
-
-  /* static vars in all previous set.  */
-  bitmap all_static_vars;
-
-  /* all vars in all previous set.  */
-  bitmap all_vars;
-} globalize_context_t;
-
-/* Callback for walk_tree.  Examine the tree pointer to by TP and see if
-   if its a file-scope static variable of function that need to be turned
-   into a global.  */
-
-static tree
-globalize_cross_file_statics (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
-                             void *data)
-{
-  globalize_context_t *context = (globalize_context_t *) data;
-  tree t = *tp;
-
-  if (t == NULL_TREE)
-    return NULL;
-
-  /* The logic for globalization of VAR_DECLs and FUNCTION_DECLs are
-     different.  For functions, we can simply look at the cgraph node sets
-     to tell if there are references to static functions outside the set.
-     The cgraph node sets do not keep track of vars, we need to traverse
-     the trees to determine what vars need to be globalized.  */
-  if (TREE_CODE (t) == VAR_DECL)
-    {
-      if (!TREE_PUBLIC (t))
-       {
-         /* This file-scope static variable is reachable from more
-            that one set.  Make it global but with hidden visibility
-            so that we do not export it in dynamic linking.  */
-         if (bitmap_bit_p (context->all_static_vars, DECL_UID (t)))
-           {
-             TREE_PUBLIC (t) = 1;
-             DECL_VISIBILITY (t) = VISIBILITY_HIDDEN;
-           }
-         bitmap_set_bit (context->static_vars_in_set, DECL_UID (t));
-       }
-      bitmap_set_bit (context->all_vars, DECL_UID (t));
-      walk_tree (&DECL_INITIAL (t), globalize_cross_file_statics, context,
-                context->visited);
-    }
-  else if (TREE_CODE (t) == FUNCTION_DECL && !TREE_PUBLIC (t))
-    {
-      if (!cgraph_node_in_set_p (cgraph_node (t), context->set))
-       {
-         /* This file-scope static function is reachable from a set
-            which does not contain the function DECL.  Make it global
-            but with hidden visibility.  */
-         TREE_PUBLIC (t) = 1;
-         DECL_VISIBILITY (t) = VISIBILITY_HIDDEN;
-       }
-    }
-
-  return NULL; 
-}
-
-/* Helper of lto_scan_statics_in_cgraph_node below.  Scan TABLE for
-   static decls that may be used in more than one LTRANS file.
-   CONTEXT is a globalize_context_t for storing scanning states.  */
-
-static void
-lto_scan_statics_in_ref_table (struct lto_tree_ref_table *table,
-                              globalize_context_t *context)
-{
-  unsigned i;
-
-  for (i = 0; i < table->size; i++)
-    walk_tree (&table->trees[i], globalize_cross_file_statics, context,
-              context->visited);
-}
-
-/* Promote file-scope decl reachable from NODE if necessary to global.
-   CONTEXT is a globalize_context_t storing scanning states.  */
-
-static void
-lto_scan_statics_in_cgraph_node (struct cgraph_node *node,
-                                globalize_context_t *context)
-{
-  struct lto_in_decl_state *state;
-  
-  /* Do nothing if NODE has no function body.  */
-  if (!node->analyzed)
-    return;
-  
-  /* Return if the DECL of nodes has been visited before.  */
-  if (bitmap_bit_p (context->seen_node_decls, DECL_UID (node->decl)))
-    return;
-
-  bitmap_set_bit (context->seen_node_decls, DECL_UID (node->decl));
-
-  state = lto_get_function_in_decl_state (node->local.lto_file_data,
-                                         node->decl);
-  gcc_assert (state);
-
-  lto_scan_statics_in_ref_table (&state->streams[LTO_DECL_STREAM_VAR_DECL],
-                                context);
-  lto_scan_statics_in_ref_table (&state->streams[LTO_DECL_STREAM_FN_DECL],
-                                context);
-}
-
-/* Scan all global variables that we have not yet seen so far.  CONTEXT
-   is a globalize_context_t storing scanning states.  */
-
-static void
-lto_scan_statics_in_remaining_global_vars (globalize_context_t *context)
-{
-  tree var, var_context;
-  struct varpool_node *vnode;
-
-  FOR_EACH_STATIC_VARIABLE (vnode)
-    {
-      var = vnode->decl;
-      var_context = DECL_CONTEXT (var);
-      if (TREE_STATIC (var)
-         && TREE_PUBLIC (var)
-          && (!var_context || TREE_CODE (var_context) != FUNCTION_DECL)
-          && !bitmap_bit_p (context->all_vars, DECL_UID (var)))
-       walk_tree (&var, globalize_cross_file_statics, context,
-                  context->visited);
-    }
+  lto_bitmap_free (original_nodes);
+  lto_bitmap_free (original_decls);
 }
 
 /* Find out all static decls that need to be promoted to global because
@@ -840,39 +713,66 @@ lto_scan_statics_in_remaining_global_vars (globalize_context_t *context)
 static void
 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;
-  globalize_context_t context;
+  varpool_node_set_iterator vsi;
 
-  memset (&context, 0, sizeof (context));
-  context.all_vars = lto_bitmap_alloc ();
-  context.all_static_vars = lto_bitmap_alloc ();
+  gcc_assert (flag_wpa);
 
   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);
-      context.set = set;
-      context.visited = pointer_set_create ();
-      context.static_vars_in_set = lto_bitmap_alloc ();
-      context.seen_node_decls = lto_bitmap_alloc ();
+      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))
-       lto_scan_statics_in_cgraph_node (csi_node (csi), &context);
-
-      if (i == n_sets - 1)
-        lto_scan_statics_in_remaining_global_vars (&context);
-
-      bitmap_ior_into (context.all_static_vars, context.static_vars_in_set);
+       {
+         struct cgraph_node *node = csi_node (csi);
+         if (node->local.externally_visible)
+           continue;
+         if (node->clone_of || 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)))
+            {
+               gcc_assert (flag_wpa);
+               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;
+                     }
+                 }
+            }
+       }
+      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))
+           {
+             gcc_assert (flag_wpa);
+             TREE_PUBLIC (vnode->decl) = 1;
+             DECL_VISIBILITY (vnode->decl) = VISIBILITY_HIDDEN;
+           }
+       }
 
-      pointer_set_destroy (context.visited);
-      lto_bitmap_free (context.static_vars_in_set);
-      lto_bitmap_free (context.seen_node_decls);
     }
-
-  lto_bitmap_free (context.all_vars);
-  lto_bitmap_free (context.all_static_vars);
 }
 
 
@@ -916,57 +816,50 @@ get_filename_for_set (cgraph_node_set set)
   char *fname = NULL;
   static const size_t max_fname_len = 100;
 
-  if (cgraph_node_set_needs_ltrans_p (set))
+  /* 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))
     {
-      /* 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;
+      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);
 
-      /* 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
+  if (!fname)
     {
       /* Since SET does not need to be processed by LTRANS, use
         the original file name and mark it with a '*' prefix so that
@@ -975,6 +868,13 @@ 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;
 }
@@ -992,8 +892,7 @@ lto_wpa_write_files (void)
   unsigned i, n_sets, last_out_file_ix, num_out_files;
   lto_file *file;
   cgraph_node_set set;
-  bitmap decls;
-  VEC(bitmap,heap) *inlined_decls = NULL;
+  varpool_node_set vset;
 
   timevar_push (TV_WHOPR_WPA);
 
@@ -1003,8 +902,7 @@ lto_wpa_write_files (void)
      compiled by LTRANS.  */
   for (i = 0; VEC_iterate (cgraph_node_set, lto_cgraph_node_sets, i, set); i++)
     {
-      decls = lto_add_all_inlinees (set);
-      VEC_safe_push (bitmap, heap, inlined_decls, decls);
+      lto_add_all_inlinees (set);
       lto_stats.num_output_cgraph_nodes += VEC_length (cgraph_node_ptr,
                                                       set->nodes);
     }
@@ -1030,27 +928,26 @@ lto_wpa_write_files (void)
       char *temp_filename;
 
       set = VEC_index (cgraph_node_set, lto_cgraph_node_sets, i);
+      vset = VEC_index (varpool_node_set, lto_varpool_node_sets, i);
       temp_filename = get_filename_for_set (set);
       output_files[i] = temp_filename;
 
-      if (cgraph_node_set_needs_ltrans_p (set))
+      if (cgraph_node_set_nonempty_p (set) || varpool_node_set_nonempty_p (vset))
        {
          /* Write all the nodes in SET to TEMP_FILENAME.  */
-         file = lto_elf_file_open (temp_filename, true);
+         file = lto_obj_file_open (temp_filename, true);
          if (!file)
-           fatal_error ("lto_elf_file_open() failed");
+           fatal_error ("lto_obj_file_open() failed");
 
-         lto_set_current_out_file (file);
-         lto_new_extern_inline_states ();
+         if (!quiet_flag)
+           fprintf (stderr, " %s", temp_filename);
 
-         decls = VEC_index (bitmap, inlined_decls, i);
-         lto_force_functions_extern_inline (decls);
+         lto_set_current_out_file (file);
 
-         ipa_write_summaries_of_cgraph_node_set (set);
-         lto_delete_extern_inline_states ();
+         ipa_write_optimization_summaries (set, vset);
 
          lto_set_current_out_file (NULL);
-         lto_elf_file_close (file);
+         lto_obj_file_close (file);
        }
     }
 
@@ -1060,196 +957,44 @@ lto_wpa_write_files (void)
 
   output_files[last_out_file_ix] = NULL;
 
-  for (i = 0; VEC_iterate (bitmap, inlined_decls, i, decls); i++)
-    lto_bitmap_free (decls);
-  VEC_free (bitmap, heap, inlined_decls);
-
   timevar_pop (TV_WHOPR_WPA_IO);
 
   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_execute_ltrans (char *const *files)
+lto_write_ltrans_list (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;
-  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";
+  unsigned i;
 
   /* Open the 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);
-    }
+  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);
 
   for (i = 0; files[i]; ++i)
     {
       size_t len;
 
-      /* 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);
-       }
+      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);
     }
 
   /* Close the LTRANS output list.  */
-  if (ltrans_output_list_stream && fclose (ltrans_output_list_stream))
+  if (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);
 }
 
 
@@ -1427,7 +1172,13 @@ lto_fixup_type (tree t, void *data)
   /* Accessor is for derived node types only. */
   LTO_FIXUP_SUBTREE (t->type.binfo);
 
-  LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TYPE_CONTEXT (t));
+  if (TYPE_CONTEXT (t))
+    {
+      if (TYPE_P (TYPE_CONTEXT (t)))
+       LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TYPE_CONTEXT (t));
+      else
+       LTO_FIXUP_SUBTREE (TYPE_CONTEXT (t));
+    }
   LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TYPE_CANONICAL (t));
 
   /* The following re-creates proper variant lists while fixing up
@@ -1557,7 +1308,7 @@ lto_fixup_tree (tree *tp, int *walk_subtrees, void *data)
 
   t = *tp;
   *walk_subtrees = 0;
-  if (pointer_set_contains (fixup_data->seen, t))
+  if (!t || pointer_set_contains (fixup_data->seen, t))
     return NULL;
 
   if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == FUNCTION_DECL)
@@ -1566,28 +1317,6 @@ lto_fixup_tree (tree *tp, int *walk_subtrees, void *data)
 
       if (t != prevailing)
        {
-         if (TREE_CODE (t) == FUNCTION_DECL
-             && TREE_NOTHROW (prevailing) != TREE_NOTHROW (t))
-           {
-             /* If the prevailing definition does not throw but the
-                declaration (T) was considered throwing, then we
-                simply add PREVAILING to the list of throwing
-                functions.  However, if the opposite is true, then
-                the call to PREVAILING was generated assuming that
-                the function didn't throw, which means that CFG
-                cleanup may have removed surrounding try/catch
-                regions.
-
-                Note that we currently accept these cases even when
-                they occur within a single file.  It's certainly a
-                user error, but we silently allow the compiler to
-                remove surrounding try/catch regions.  Perhaps we
-                could emit a warning here, instead of silently
-                accepting the conflicting declaration.  */
-             if (TREE_NOTHROW (prevailing))
-               lto_mark_nothrow_fndecl (prevailing);
-           }
-
           /* Also replace t with prevailing defintion.  We don't want to
              insert the other defintion in the seen set as we want to
              replace all instances of it.  */
@@ -1725,23 +1454,11 @@ lto_fixup_decls (struct lto_file_decl_data **files)
        VEC_replace (tree, lto_global_var_decls, i, decl);
     }
 
+  VEC_free (tree, gc, lto_global_var_decls);
+  lto_global_var_decls = NULL;
   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.
@@ -1767,17 +1484,17 @@ lto_read_all_file_options (void)
   for (i = 0; i < num_in_fnames; i++)
     {
       struct lto_file_decl_data *file_data;
-      lto_file *file = lto_elf_file_open (in_fnames[i], false);
+      lto_file *file = lto_obj_file_open (in_fnames[i], false);
       if (!file)
        break;
 
       file_data = XCNEW (struct lto_file_decl_data);
       file_data->file_name = file->filename;
-      file_data->section_hash_table = lto_elf_build_section_table (file);
+      file_data->section_hash_table = lto_obj_build_section_table (file);
 
       lto_read_file_options (file_data);
 
-      lto_elf_file_close (file);
+      lto_obj_file_close (file);
       htab_delete (file_data->section_hash_table);
       free (file_data);
     }
@@ -1786,6 +1503,7 @@ 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
@@ -1796,7 +1514,6 @@ 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;
 
@@ -1805,7 +1522,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 = XNEWVEC (struct lto_file_decl_data *, nfiles + 1);
+  all_file_decl_data = GGC_CNEWVEC (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.  */
@@ -1827,12 +1544,20 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
       gcc_assert (num_objects == nfiles);
     }
 
+  if (!quiet_flag)
+    fprintf (stderr, "Reading object files:");
+
   /* Read all of the object files specified on the command line.  */
   for (i = 0, last_file_ix = 0; i < nfiles; ++i)
     {
       struct lto_file_decl_data *file_data = NULL;
+      if (!quiet_flag)
+       {
+         fprintf (stderr, " %s", fnames[i]);
+         fflush (stderr);
+       }
 
-      current_lto_file = lto_elf_file_open (fnames[i], false);
+      current_lto_file = lto_obj_file_open (fnames[i], false);
       if (!current_lto_file)
        break;
 
@@ -1842,8 +1567,9 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
 
       all_file_decl_data[last_file_ix++] = file_data;
 
-      lto_elf_file_close (current_lto_file);
+      lto_obj_file_close (current_lto_file);
       current_lto_file = NULL;
+      ggc_collect ();
     }
 
   if (resolution_file_name)
@@ -1854,38 +1580,48 @@ 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");
 
   /* Read the IPA summary data.  */
-  ipa_read_summaries ();
+  if (flag_ltrans)
+    ipa_read_optimization_summaries ();
+  else
+    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 ();
 
-  /* Mark cgraph nodes needed in the merged cgraph
-     This normally happens in whole-program pass, but for
-     ltrans the pass was already run at WPA phase.
-     
-     FIXME:  This is not valid way to do so; nodes can be needed
-     for non-obvious reasons.  We should stream the flags from WPA
-     phase. */
   if (flag_ltrans)
     for (node = cgraph_nodes; node; node = node->next)
       {
-        if (!node->global.inlined_to
-           && cgraph_decide_is_function_needed (node, node->decl))
-          cgraph_mark_needed_node (node);
        /* FIXME: ipa_transforms_to_apply holds list of passes that have optimization
           summaries computed and needs to apply changes.  At the moment WHOPR only
           supports inlining, so we can push it here by hand.  In future we need to stream
@@ -1895,8 +1631,11 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
                         node->ipa_transforms_to_apply,
                         (ipa_opt_pass)&pass_ipa_inline);
       }
+  lto_symtab_free ();
 
-  timevar_push (TV_IPA_LTO_DECL_IO);
+  timevar_pop (TV_IPA_LTO_CGRAPH_MERGE);
+
+  timevar_push (TV_IPA_LTO_DECL_INIT_IO);
 
   /* FIXME lto. This loop needs to be changed to use the pass manager to
      call the ipa passes directly.  */
@@ -1910,7 +1649,9 @@ 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_IO);
+  timevar_pop (TV_IPA_LTO_DECL_INIT_IO);
+  ggc_free (all_file_decl_data);
+  all_file_decl_data = NULL;
 }
 
 
@@ -1924,6 +1665,11 @@ materialize_cgraph (void)
   unsigned i;
   timevar_id_t lto_timer;
 
+  if (!quiet_flag)
+    fprintf (stderr,
+            flag_wpa ? "Materializing decls:" : "Reading function bodies:");
+
+
   /* Now that we have input the cgraph, we need to clear all of the aux
      nodes and read the functions if we are not running in WPA mode.  */
   timevar_push (TV_IPA_LTO_GIMPLE_IO);
@@ -1942,6 +1688,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++;
        }
@@ -1963,8 +1710,8 @@ materialize_cgraph (void)
   for (i = 0; VEC_iterate (tree, lto_global_var_decls, i, decl); i++)
     rest_of_decl_compilation (decl, 1, 0);
 
-  /* Fix up any calls to DECLs that have become not exception throwing.  */
-  lto_fixup_nothrow_decls ();
+  if (!quiet_flag)
+    fprintf (stderr, "\n");
 
   timevar_pop (lto_timer);
 }
@@ -1977,10 +1724,6 @@ static void
 do_whole_program_analysis (void)
 {
   char **output_files;
-  size_t i;
-  struct cgraph_node *node; 
-
-  lto_1_to_1_map ();
 
   /* Note that since we are in WPA mode, materialize_cgraph will not
      actually read in all the function bodies.  It only materializes
@@ -1990,20 +1733,18 @@ do_whole_program_analysis (void)
   /* Reading in the cgraph uses different timers, start timing WPA now.  */
   timevar_push (TV_WHOPR_WPA);
 
-  /* FIXME lto. Hack. We should use the IPA passes.  There are a
-     number of issues with this now. 1. There is no convenient way to
-     do this. 2. Some passes may depend on properties that requires
-     the function bodies to compute.  */
+  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 ();
+  cgraph_state = CGRAPH_STATE_IPA_SSA;
 
-  /* Reset inlining information before running IPA inliner.  */
-  for (node = cgraph_nodes; node; node = node->next)
-    reset_inline_failed (node);
-
-  /* FIXME lto.  We should not call this function directly. */
-  pass_ipa_inline.pass.execute ();
+  execute_ipa_pass_list (all_regular_ipa_passes);
 
   verify_cgraph ();
   bitmap_obstack_release (NULL);
@@ -2011,21 +1752,29 @@ do_whole_program_analysis (void)
   /* We are about to launch the final LTRANS phase, stop the WPA timer.  */
   timevar_pop (TV_WHOPR_WPA);
 
+  lto_1_to_1_map ();
+
+  if (!quiet_flag)
+    {
+      fprintf (stderr, "\nStreaming out");
+      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_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]);
-    }
+  lto_write_ltrans_list (output_files);
 
   XDELETEVEC (output_files);
 }