]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
* lto-symtab.c (lto_cgraph_replace_node): Assert that inline clones has
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 7 Oct 2009 09:01:16 +0000 (09:01 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 7 Oct 2009 09:01:16 +0000 (09:01 +0000)
no address taken.
* cgraph.c (cgraph_mark_needed_node): Assert that inline clones are
never needed.
(cgraph_clone_node): Clear externally_visible flag for clones.
* cgraph.h (cgraph_only_called_directly_p,
cgraph_can_remove_if_no_direct_calls_p): New predicates.
* tree-pass.h (pass_ipa_whole_program_visibility): Declare.
* ipa-cp.c (ipcp_cloning_candidate_p): Use new predicate.
(ipcp_initialize_node_lattices, ipcp_estimate_growth,
ipcp_insert_stage): Likwise.
* cgraphunit.c (cgraph_decide_is_function_needed): Do not compute
externally_visible flag.
(verify_cgraph_node): Verify that inline clones look right.
(process_function_and_variable_attributes): Do not set
externally_visible flags.
(ipa_passes): Avoid executing small_ipa_passes at LTO stage; they've
been already run.
* lto-cgraph.c (lto_output_node): Assert that inline clones are not
boundaries.
* ipa-inline.c (cgraph_clone_inlined_nodes): Use new predicates;
clear externally_visible when turning into inline clones
(cgraph_mark_inline_edge): Use new predicates.
(cgraph_estimate_growth): Likewise.
(cgraph_decide_inlining): Likewise.
* ipa.c (cgraph_postorder): Likewise.
(cgraph_remove_unreachable_nodes): Likewise; sanity check
that inline clones are not needed.
(cgraph_externally_visible_p): New predicate.
(function_and_variable_visibility): Add whole_program parameter;
always set externally_visible flag; handle COMDAT function
privatization.
(local_function_and_variable_visibility): New function.
(gate_whole_program_function_and_variable_visibility): New function.
(whole_program_function_and_variable_visibility): New function.
(pass_ipa_whole_program_visibility): New function.
* passes.c  (init_optimization_passes): Add whole program visibility
pass.
(do_per_function_toporder, function_called_by_processed_nodes_p): Do
not care about needed/reachable flags.
* varpool.c: Include flags.h
(decide_is_variable_needed): When doing LTO assume whole-program mode.
(varpool_finalize_decl): When we are in LTO read-back, all variables
are analyzed.
(varpool_analyze_pending_decls): Skip analyzis of analyzed vars.

* lto/lto.c (read_cgraph_and_symbols): Mark functions neccesary only at
ltrans stage; explain why this is needed and should not.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@152520 138bc75d-0d04-0410-961f-82ee72b054a4

14 files changed:
gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/cgraphunit.c
gcc/ipa-cp.c
gcc/ipa-inline.c
gcc/ipa.c
gcc/lto-cgraph.c
gcc/lto-symtab.c
gcc/lto/ChangeLog
gcc/lto/lto.c
gcc/passes.c
gcc/tree-pass.h
gcc/varpool.c

index 8015be9133e8d4d53d4010ee58b71173c22c1942..3a8ac5440a8dc079a1bd5a0b2d363af18b426bef 100644 (file)
@@ -1,3 +1,51 @@
+2009-10-07  Jan Hubicka  <jh@suse.cz>
+
+       * lto-symtab.c (lto_cgraph_replace_node): Assert that inline clones has
+       no address taken.
+       * cgraph.c (cgraph_mark_needed_node): Assert that inline clones are
+       never needed.
+       (cgraph_clone_node): Clear externally_visible flag for clones.
+       * cgraph.h (cgraph_only_called_directly_p,
+       cgraph_can_remove_if_no_direct_calls_p): New predicates.
+       * tree-pass.h (pass_ipa_whole_program_visibility): Declare.
+       * ipa-cp.c (ipcp_cloning_candidate_p): Use new predicate.
+       (ipcp_initialize_node_lattices, ipcp_estimate_growth,
+       ipcp_insert_stage): Likwise.
+       * cgraphunit.c (cgraph_decide_is_function_needed): Do not compute
+       externally_visible flag.
+       (verify_cgraph_node): Verify that inline clones look right.
+       (process_function_and_variable_attributes): Do not set
+       externally_visible flags.
+       (ipa_passes): Avoid executing small_ipa_passes at LTO stage; they've
+       been already run.
+       * lto-cgraph.c (lto_output_node): Assert that inline clones are not
+       boundaries.
+       * ipa-inline.c (cgraph_clone_inlined_nodes): Use new predicates;
+       clear externally_visible when turning into inline clones
+       (cgraph_mark_inline_edge): Use new predicates.
+       (cgraph_estimate_growth): Likewise.
+       (cgraph_decide_inlining): Likewise.
+       * ipa.c (cgraph_postorder): Likewise.
+       (cgraph_remove_unreachable_nodes): Likewise; sanity check
+       that inline clones are not needed.
+       (cgraph_externally_visible_p): New predicate.
+       (function_and_variable_visibility): Add whole_program parameter;
+       always set externally_visible flag; handle COMDAT function
+       privatization.
+       (local_function_and_variable_visibility): New function.
+       (gate_whole_program_function_and_variable_visibility): New function.
+       (whole_program_function_and_variable_visibility): New function.
+       (pass_ipa_whole_program_visibility): New function.
+       * passes.c  (init_optimization_passes): Add whole program visibility
+       pass.
+       (do_per_function_toporder, function_called_by_processed_nodes_p): Do
+       not care about needed/reachable flags.
+       * varpool.c: Include flags.h
+       (decide_is_variable_needed): When doing LTO assume whole-program mode.
+       (varpool_finalize_decl): When we are in LTO read-back, all variables
+       are analyzed.
+       (varpool_analyze_pending_decls): Skip analyzis of analyzed vars.
+
 2009-10-07  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>
 
        * config/s390/tpf.h (TARGET_DEFAULT): Remove MASK_HARD_FLOAT and
index 8dcf4e43edb543af0b72e13f1d0b9befb82d0ae9..bc8f1015e62f954c0bb3dc1c0f48336856d55e12 100644 (file)
@@ -1359,6 +1359,7 @@ void
 cgraph_mark_needed_node (struct cgraph_node *node)
 {
   node->needed = 1;
+  gcc_assert (!node->global.inlined_to);
   cgraph_mark_reachable_node (node);
 }
 
@@ -1682,6 +1683,7 @@ cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq,
     }
   new_node->analyzed = n->analyzed;
   new_node->local = n->local;
+  new_node->local.externally_visible = false;
   new_node->global = n->global;
   new_node->rtl = n->rtl;
   new_node->count = count;
index 845897b2841d46a46d4a136c2d1dc91892a8d32f..438cd1e6fae0f6ba7a6ef01244d67118072926ce 100644 (file)
@@ -658,6 +658,26 @@ struct GTY(()) constant_descriptor_tree {
   hashval_t hash;
 };
 
+/* Return true when function NODE is only called directly.
+   i.e. it is not externally visible, address was not taken and
+   it is not used in any other non-standard way.  */
+
+static inline bool
+cgraph_only_called_directly_p (struct cgraph_node *node)
+{
+  return !node->needed && !node->local.externally_visible;
+}
+
+/* Return true when function NODE can be removed from callgraph
+   if all direct calls are eliminated.  */
+
+static inline bool
+cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node)
+{
+  return (!node->needed
+         && (DECL_COMDAT (node->decl) || !node->local.externally_visible));
+}
+
 /* Constant pool accessor function.  */
 htab_t constant_pool_htab (void);
 
index 9a4f63d3acac60215d0d51f6db00b5ffe4624602..9a97bef296252ee0a5ea42ef5777a59381be63a7 100644 (file)
@@ -316,13 +316,6 @@ cgraph_build_cdtor_fns (void)
 bool
 cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl)
 {
-  if (MAIN_NAME_P (DECL_NAME (decl))
-      && TREE_PUBLIC (decl))
-    {
-      node->local.externally_visible = true;
-      return true;
-    }
-
   /* If the user told us it is used, then it must be so.  */
   if (node->local.externally_visible)
     return true;
@@ -360,7 +353,9 @@ cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl)
        || (!optimize && !node->local.disregard_inline_limits
            && !DECL_DECLARED_INLINE_P (decl)
            && !node->origin))
-      && !flag_whole_program)
+       && !flag_whole_program
+       && !flag_lto
+       && !flag_whopr)
       && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
     return true;
 
@@ -593,6 +588,21 @@ verify_cgraph_node (struct cgraph_node *node)
       error ("Execution count is negative");
       error_found = true;
     }
+  if (node->global.inlined_to && node->local.externally_visible)
+    {
+      error ("Externally visible inline clone");
+      error_found = true;
+    }
+  if (node->global.inlined_to && node->address_taken)
+    {
+      error ("Inline clone with address taken");
+      error_found = true;
+    }
+  if (node->global.inlined_to && node->needed)
+    {
+      error ("Inline clone is needed");
+      error_found = true;
+    }
   for (e = node->callers; e; e = e->next_caller)
     {
       if (e->count < 0)
@@ -864,12 +874,8 @@ process_function_and_variable_attributes (struct cgraph_node *first,
            warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wattributes,
                        "%<externally_visible%>"
                        " attribute have effect only on public objects");
-         else
-           {
-             if (node->local.finalized)
-               cgraph_mark_needed_node (node);
-             node->local.externally_visible = true;
-           }
+         else if (node->local.finalized)
+            cgraph_mark_needed_node (node);
        }
     }
   for (vnode = varpool_nodes; vnode != first_var; vnode = vnode->next)
@@ -887,12 +893,8 @@ process_function_and_variable_attributes (struct cgraph_node *first,
            warning_at (DECL_SOURCE_LOCATION (vnode->decl), OPT_Wattributes,
                        "%<externally_visible%>"
                        " attribute have effect only on public objects");
-         else
-           {
-             if (vnode->finalized)
-               varpool_mark_needed_node (vnode);
-             vnode->externally_visible = true;
-           }
+         else if (vnode->finalized)
+           varpool_mark_needed_node (vnode);
        }
     }
 }
@@ -1355,7 +1357,9 @@ ipa_passes (void)
   current_function_decl = NULL;
   gimple_register_cfg_hooks ();
   bitmap_obstack_initialize (NULL);
-  execute_ipa_pass_list (all_small_ipa_passes);
+
+  if (!in_lto_p)
+    execute_ipa_pass_list (all_small_ipa_passes);
 
   /* If pass_all_early_optimizations was not scheduled, the state of
      the cgraph will not be properly updated.  Update it now.  */
index a974dd0aab3f9f237d91ac9dfed91e042b34a11f..59a051915f6d1391e72bb644e2679616733121c2 100644 (file)
@@ -442,7 +442,7 @@ ipcp_cloning_candidate_p (struct cgraph_node *node)
      FIXME: in future we should clone such functions when they are called with
      different constants, but current ipcp implementation is not good on this.
      */
-  if (!node->needed || !node->analyzed)
+  if (cgraph_only_called_directly_p (node) || !node->analyzed)
     return false;
 
   if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
@@ -536,7 +536,7 @@ ipcp_initialize_node_lattices (struct cgraph_node *node)
 
   if (ipa_is_called_with_var_arguments (info))
     type = IPA_BOTTOM;
-  else if (!node->needed)
+  else if (cgraph_only_called_directly_p (node))
     type = IPA_TOP;
   /* When cloning is allowed, we can assume that externally visible functions
      are not called.  We will compensate this by cloning later.  */
@@ -954,7 +954,7 @@ ipcp_estimate_growth (struct cgraph_node *node)
   struct cgraph_edge *cs;
   int redirectable_node_callers = 0;
   int removable_args = 0;
-  bool need_original = node->needed;
+  bool need_original = !cgraph_only_called_directly_p (node);
   struct ipa_node_params *info;
   int i, count;
   int growth;
@@ -1143,7 +1143,7 @@ ipcp_insert_stage (void)
       for (cs = node->callers; cs != NULL; cs = cs->next_caller)
        if (cs->caller == node || ipcp_need_redirect_p (cs))
          break;
-      if (!cs && !node->needed)
+      if (!cs && cgraph_only_called_directly_p (node))
        bitmap_set_bit (dead_nodes, node->uid);
 
       info = IPA_NODE_REF (node);
index 0a02ae1770a39d146717b4e2d929b1c685d931c0..18e440a60fe73467d32255fd676b32c5228b184f 100644 (file)
@@ -223,7 +223,7 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
       /* We may eliminate the need for out-of-line copy to be output.
         In that case just go ahead and re-use it.  */
       if (!e->callee->callers->next_caller
-         && !e->callee->needed
+         && cgraph_can_remove_if_no_direct_calls_p (e->callee)
          && !cgraph_new_nodes)
        {
          gcc_assert (!e->callee->global.inlined_to);
@@ -233,6 +233,7 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
              nfunctions_inlined++;
            }
          duplicate = false;
+         e->callee->local.externally_visible = false;
        }
       else
        {
@@ -286,7 +287,7 @@ cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original,
   e->callee->global.inlined = true;
 
   if (e->callee->callers->next_caller
-      || e->callee->needed)
+      || !cgraph_can_remove_if_no_direct_calls_p (e->callee))
     duplicate = true;
   cgraph_clone_inlined_nodes (e, true, update_original);
 
@@ -368,7 +369,8 @@ cgraph_estimate_growth (struct cgraph_node *node)
      we decide to not inline for different reasons, but it is not big deal
      as in that case we will keep the body around, but we will also avoid
      some inlining.  */
-  if (!node->needed && !DECL_EXTERNAL (node->decl) && !self_recursive)
+  if (cgraph_only_called_directly_p (node)
+      && !DECL_EXTERNAL (node->decl) && !self_recursive)
     growth -= node->global.size;
 
   node->global.estimated_growth = growth;
@@ -1226,7 +1228,7 @@ cgraph_decide_inlining (void)
 
          if (node->callers
              && !node->callers->next_caller
-             && !node->needed
+             && cgraph_only_called_directly_p (node)
              && node->local.inlinable
              && node->callers->inline_failed
              && node->callers->caller != node
index 9204caae77bc3b5fa7a646754f4fb189d5c2338d..50eade08cdd586e5ba37382f6cd21f34260b4796 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -52,7 +52,9 @@ cgraph_postorder (struct cgraph_node **order)
   for (pass = 0; pass < 2; pass++)
     for (node = cgraph_nodes; node; node = node->next)
       if (!node->aux
-         && (pass || (node->needed && !node->address_taken)))
+         && (pass
+             || (!cgraph_only_called_directly_p (node)
+                 && !node->address_taken)))
        {
          node2 = node;
          if (!node->callers)
@@ -132,11 +134,12 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
     gcc_assert (!node->aux);
 #endif
   for (node = cgraph_nodes; node; node = node->next)
-    if (node->needed && !node->global.inlined_to
+    if (!cgraph_can_remove_if_no_direct_calls_p (node)
        && ((!DECL_EXTERNAL (node->decl)) 
             || !node->analyzed
             || before_inlining_p))
       {
+        gcc_assert (!node->global.inlined_to);
        node->aux = first;
        first = node;
       }
@@ -248,6 +251,26 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
   return changed;
 }
 
+static bool
+cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program)
+{
+  if (!DECL_COMDAT (node->decl)
+      && (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl)))
+    return false;
+  if (!whole_program)
+    return true;
+  /* COMDAT functions must be shared only if they have address taken,
+     otherwise we can produce our own private implementation with
+     -fwhole-program.  */
+  if (DECL_COMDAT (node->decl) && (node->address_taken || !node->analyzed))
+    return true;
+  if (MAIN_NAME_P (DECL_NAME (node->decl)))
+    return true;
+  if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
+    return true;
+  return false;
+}
+
 /* Mark visibility of all functions.
 
    A local function is one whose calls can occur only in the current
@@ -260,25 +283,29 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
    via visibilities for the backend point of view.  */
 
 static unsigned int
-function_and_variable_visibility (void)
+function_and_variable_visibility (bool whole_program)
 {
   struct cgraph_node *node;
   struct varpool_node *vnode;
 
   for (node = cgraph_nodes; node; node = node->next)
     {
-      if (node->reachable
-         && (DECL_COMDAT (node->decl)
-             || (!flag_whole_program
-                 && TREE_PUBLIC (node->decl) && !DECL_EXTERNAL (node->decl))))
-       node->local.externally_visible = true;
+      if (cgraph_externally_visible_p (node, whole_program))
+        {
+         gcc_assert (!node->global.inlined_to);
+         node->local.externally_visible = true;
+       }
+      else
+       node->local.externally_visible = false;
       if (!node->local.externally_visible && node->analyzed
          && !DECL_EXTERNAL (node->decl))
        {
-         gcc_assert (flag_whole_program || !TREE_PUBLIC (node->decl));
+         gcc_assert (whole_program || !TREE_PUBLIC (node->decl));
          TREE_PUBLIC (node->decl) = 0;
+         DECL_COMDAT (node->decl) = 0;
+         DECL_WEAK (node->decl) = 0;
        }
-      node->local.local = (!node->needed
+      node->local.local = (cgraph_only_called_directly_p (node)
                           && node->analyzed
                           && !DECL_EXTERNAL (node->decl)
                           && !node->local.externally_visible);
@@ -286,12 +313,16 @@ function_and_variable_visibility (void)
   for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
     {
       if (vnode->needed
-         && !flag_whole_program
-         && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl)))
-       vnode->externally_visible = 1;
+         && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl))
+         && (!whole_program
+             || lookup_attribute ("externally_visible",
+                                  DECL_ATTRIBUTES (vnode->decl))))
+       vnode->externally_visible = true;
+      else
+        vnode->externally_visible = false;
       if (!vnode->externally_visible)
        {
-         gcc_assert (flag_whole_program || !TREE_PUBLIC (vnode->decl));
+         gcc_assert (whole_program || !TREE_PUBLIC (vnode->decl));
          TREE_PUBLIC (vnode->decl) = 0;
        }
      gcc_assert (TREE_STATIC (vnode->decl));
@@ -314,13 +345,22 @@ function_and_variable_visibility (void)
   return 0;
 }
 
+/* Local function pass handling visibilities.  This happens before LTO streaming
+   so in particular -fwhole-program should be ignored at this level.  */
+
+static unsigned int
+local_function_and_variable_visibility (void)
+{
+  return function_and_variable_visibility (flag_whole_program && !flag_lto && !flag_whopr);
+}
+
 struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility = 
 {
  {
   SIMPLE_IPA_PASS,
   "visibility",                                /* name */
   NULL,                                        /* gate */
-  function_and_variable_visibility,    /* execute */
+  local_function_and_variable_visibility,/* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
@@ -333,6 +373,58 @@ struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility =
  }
 };
 
+/* Do not re-run on ltrans stage.  */
+
+static bool
+gate_whole_program_function_and_variable_visibility (void)
+{
+  return !flag_ltrans;
+}
+
+/* Bring functionss local at LTO time whith -fwhole-program.  */
+
+static unsigned int
+whole_program_function_and_variable_visibility (void)
+{
+  struct cgraph_node *node;
+  struct varpool_node *vnode;
+
+  function_and_variable_visibility (flag_whole_program);
+
+  for (node = cgraph_nodes; node; node = node->next)
+    if (node->local.externally_visible)
+      cgraph_mark_needed_node (node);
+  for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
+    if (vnode->externally_visible)
+      varpool_mark_needed_node (vnode);
+  return 0;
+}
+
+struct ipa_opt_pass_d pass_ipa_whole_program_visibility =
+{
+ {
+  IPA_PASS,
+  "whole-program",                     /* name */
+  gate_whole_program_function_and_variable_visibility,/* gate */
+  whole_program_function_and_variable_visibility,/* execute */
+  NULL,                                        /* sub */
+  NULL,                                        /* next */
+  0,                                   /* static_pass_number */
+  TV_CGRAPHOPT,                                /* tv_id */
+  0,                                   /* properties_required */
+  0,                                   /* properties_provided */
+  0,                                   /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  TODO_dump_cgraph | TODO_remove_functions/* todo_flags_finish */
+ },
+ NULL,                                 /* generate_summary */
+ NULL,                                 /* write_summary */
+ NULL,                                 /* read_summary */
+ NULL,                                 /* function_read_summary */
+ 0,                                    /* TODOs */
+ NULL,                                 /* function_transform */
+ NULL,                                 /* variable_transform */
+};
 
 /* Hash a cgraph node set element.  */
 
index 14916473640c7a99bdbeb83871850e103300f774..fbf0df21c24ff4b714da294c8ed714741b44246a 100644 (file)
@@ -227,6 +227,8 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
      local static nodes to prevent clashes with other local statics.  */
   if (boundary_p)
     {
+      /* Inline clones can not be part of boundary.  */
+      gcc_assert (!node->global.inlined_to);
       local = 0;
       externally_visible = 1;
       inlinable = 0;
index 600f75b41e763219b10401b06b9bd8d6c59d9f9a..7d30448447aaaa2c5c6494c1a9d4038a790a8e15 100644 (file)
@@ -388,7 +388,10 @@ lto_cgraph_replace_node (struct cgraph_node *old_node,
   if (old_node->reachable)
     cgraph_mark_reachable_node (new_node);
   if (old_node->address_taken)
-    cgraph_mark_address_taken_node (new_node);
+    {
+      gcc_assert (!new_node->global.inlined_to);
+      cgraph_mark_address_taken_node (new_node);
+    }
 
   /* Redirect all incoming edges.  */
   for (e = old_node->callers; e; e = next)
index c4ee42ae6a241bd61c0591753f4b2bb655b643a4..dae0367d5da56497e1181a8e43384b7ce09ab0d3 100644 (file)
@@ -1,3 +1,8 @@
+2009-10-07  Jan Hubicka  <jh@suse.cz>
+
+       * lto.c (read_cgraph_and_symbols): Mark functions neccesary only at
+       ltrans stage; explain why this is needed and should not.
+
 2009-10-05  Richard Guenther  <rguenther@suse.de>
 
        PR lto/41552
index daefa823db38fb9b6d401b8256b25c8bc36ce5e4..ab4c208670d95acdf1639c5ec1b9e0ca34d83c75 100644 (file)
@@ -1824,11 +1824,18 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
   /* Merge global decls.  */
   lto_symtab_merge_decls ();
 
-  /* Mark cgraph nodes needed in the merged cgraph.
-     ???  Is this really necessary?  */
-  for (node = cgraph_nodes; node; node = node->next)
-    if (cgraph_decide_is_function_needed (node, node->decl))
-      cgraph_mark_needed_node (node);
+  /* 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);
 
   timevar_push (TV_IPA_LTO_DECL_IO);
 
index e3fd7a8454d1074b32a23e48d9b716d45e3178a8..60a850969c25c798e6bf397c36ac355ad73b5732 100644 (file)
@@ -759,6 +759,7 @@ init_optimization_passes (void)
   *p = NULL;
 
   p = &all_regular_ipa_passes;
+  NEXT_PASS (pass_ipa_whole_program_visibility);
   NEXT_PASS (pass_ipa_cp);
   NEXT_PASS (pass_ipa_inline);
   NEXT_PASS (pass_ipa_reference);
@@ -1099,7 +1100,7 @@ do_per_function_toporder (void (*callback) (void *data), void *data)
          /* Allow possibly removed nodes to be garbage collected.  */
          order[i] = NULL;
          node->process = 0;
-         if (node->analyzed && (node->needed || node->reachable))
+         if (node->analyzed)
            {
              push_cfun (DECL_STRUCT_FUNCTION (node->decl));
              current_function_decl = node->decl;
@@ -1783,7 +1784,7 @@ function_called_by_processed_nodes_p (void)
     {
       if (e->caller->decl == current_function_decl)
         continue;
-      if (!e->caller->analyzed || (!e->caller->needed && !e->caller->reachable))
+      if (!e->caller->analyzed)
         continue;
       if (TREE_ASM_WRITTEN (e->caller->decl))
         continue;
index ae510494c86af7a7d2633429934b144817b734a0..2cbe3e4b44878b83b8ad910c7fd5335d9d1f4463 100644 (file)
@@ -437,6 +437,7 @@ extern struct simple_ipa_opt_pass pass_ipa_early_inline;
 
 extern struct simple_ipa_opt_pass pass_early_local_passes;
 
+extern struct ipa_opt_pass_d pass_ipa_whole_program_visibility;
 extern struct ipa_opt_pass_d pass_ipa_lto_gimple_out;
 extern struct simple_ipa_opt_pass pass_ipa_increase_alignment;
 extern struct simple_ipa_opt_pass pass_ipa_matrix_reorg;
index 12cdad90e28006ed2d1cff1bb5f70d405b28d961..f7b338ff44b0486e0a2a62846494122476c49399 100644 (file)
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "gimple.h"
 #include "tree-flow.h"
+#include "flags.h"
 
 /*  This file contains basic routines manipulating variable pool.
 
@@ -245,7 +246,11 @@ decide_is_variable_needed (struct varpool_node *node, tree decl)
 
   /* Externally visible variables must be output.  The exception is
      COMDAT variables that must be output only when they are needed.  */
-  if (TREE_PUBLIC (decl) && !flag_whole_program && !DECL_COMDAT (decl)
+  if (TREE_PUBLIC (decl)
+      && !flag_whole_program
+      && !flag_lto
+      && !flag_whopr
+      && !DECL_COMDAT (decl)
       && !DECL_EXTERNAL (decl))
     return true;
 
@@ -279,6 +284,17 @@ varpool_finalize_decl (tree decl)
 {
   struct varpool_node *node = varpool_node (decl);
 
+  /* FIXME: We don't really stream varpool datastructure and instead rebuild it
+     by varpool_finalize_decl.  This is not quite correct since this way we can't
+     attach any info to varpool.  Eventually we will want to stream varpool nodes
+     and the flags.
+
+     For the moment just prevent analysis of varpool nodes to happen again, so
+     we will re-try to compute "address_taken" flag of varpool that breaks
+     in presence of clones.  */
+  if (in_lto_p)
+    node->analyzed = true;
+
   /* The first declaration of a variable that comes through this function
      decides whether it is global (in C, has external linkage)
      or local (in C, has internal linkage).  So do nothing more
@@ -333,17 +349,25 @@ varpool_analyze_pending_decls (void)
   while (varpool_first_unanalyzed_node)
     {
       tree decl = varpool_first_unanalyzed_node->decl;
+      bool analyzed = varpool_first_unanalyzed_node->analyzed;
 
       varpool_first_unanalyzed_node->analyzed = true;
 
       varpool_first_unanalyzed_node = varpool_first_unanalyzed_node->next_needed;
 
-      /* Compute the alignment early so function body expanders are
-        already informed about increased alignment.  */
-      align_variable (decl, 0);
+      /* When reading back varpool at LTO time, we re-construct the queue in order
+         to have "needed" list right by inserting all needed nodes into varpool.
+        We however don't want to re-analyze already analyzed nodes.  */
+      if (!analyzed)
+       {
+         gcc_assert (!in_lto_p);
+          /* Compute the alignment early so function body expanders are
+            already informed about increased alignment.  */
+          align_variable (decl, 0);
 
-      if (DECL_INITIAL (decl))
-       record_references_in_initializer (decl);
+          if (DECL_INITIAL (decl))
+           record_references_in_initializer (decl);
+       }
       changed = true;
     }
   timevar_pop (TV_CGRAPH);