cgraph.c (cgraph_node::can_remove_if_no_direct_calls_p): Rewrite for correct comdat...
authorJan Hubicka <hubicka@ucw.cz>
Wed, 4 Mar 2015 20:28:08 +0000 (21:28 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Wed, 4 Mar 2015 20:28:08 +0000 (20:28 +0000)
* cgraph.c (cgraph_node::can_remove_if_no_direct_calls_p): Rewrite
for correct comdat handling.
(cgraph_node::will_be_removed_from_program_if_no_direct_calls_p):
Likewise.
* cgraph.h (call_for_symbol_and_aliases): Fix formating.
(used_from_object_file_p_worker): Remove.
(cgraph_node::only_called_directly_or_alised): Add
used_from_object_file_p.
* ipa-inline-analysis.c (growth_likely_positive): Optimie.
* ipa-inline-transform.c (can_remove_node_now_p_1): Use
can_remove_if_no_direct_calls_and_refs_p.

From-SVN: r221193

gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/ipa-inline-analysis.c
gcc/ipa-inline-transform.c

index 27c712b14533560753e48f029249527625f680f5..db131ee786805fc697aeeed021faabe070e25156 100644 (file)
@@ -1,3 +1,17 @@
+2015-03-03  Jan Hubicka  <hubicka@ucw.cz>
+
+       * cgraph.c (cgraph_node::can_remove_if_no_direct_calls_p): Rewrite
+       for correct comdat handling.
+       (cgraph_node::will_be_removed_from_program_if_no_direct_calls_p):
+       Likewise.
+       * cgraph.h (call_for_symbol_and_aliases): Fix formating.
+       (used_from_object_file_p_worker): Remove.
+       (cgraph_node::only_called_directly_or_alised): Add
+       used_from_object_file_p.
+       * ipa-inline-analysis.c (growth_likely_positive): Optimie.
+       * ipa-inline-transform.c (can_remove_node_now_p_1): Use
+       can_remove_if_no_direct_calls_and_refs_p.
+
 2015-03-04  Nick Clifton  <nickc@redhat.com>
 
        * config/rl78/rl78.h (enum reg_class): Remove real registers from
index 9bae35ebbeef7dffdaeda3fb15da477336fec0ce..b2109bd5172abfda49593da6a8739550e9292fe9 100644 (file)
@@ -2411,18 +2411,57 @@ nonremovable_p (cgraph_node *node, void *)
   return !node->can_remove_if_no_direct_calls_and_refs_p ();
 }
 
-/* Return true when function cgraph_node and its aliases can be removed from
-   callgraph if all direct calls are eliminated.  */
+/* Return true if whole comdat group can be removed if there are no direct
+   calls to THIS.  */
 
 bool
 cgraph_node::can_remove_if_no_direct_calls_p (void)
 {
-  /* Extern inlines can always go, we will use the external definition.  */
-  if (DECL_EXTERNAL (decl))
-    return true;
-  if (address_taken)
+  struct ipa_ref *ref;
+
+  /* For local symbols or non-comdat group it is the same as 
+     can_remove_if_no_direct_calls_p.  */
+  if (!externally_visible || !same_comdat_group)
+    {
+      if (DECL_EXTERNAL (decl))
+       return true;
+      if (address_taken)
+       return false;
+      return !call_for_symbol_and_aliases (nonremovable_p, NULL, true);
+    }
+
+  /* Otheriwse check if we can remove the symbol itself and then verify
+     that only uses of the comdat groups are direct call to THIS
+     or its aliases.   */
+  if (!can_remove_if_no_direct_calls_and_refs_p ())
     return false;
-  return !call_for_symbol_and_aliases (nonremovable_p, NULL, true);
+
+  /* Check that all refs come from within the comdat group.  */
+  for (int i = 0; iterate_referring (i, ref); i++)
+    if (ref->referring->get_comdat_group () != get_comdat_group ())
+      return false;
+
+  struct cgraph_node *target = ultimate_alias_target ();
+  for (cgraph_node *next = dyn_cast<cgraph_node *> (same_comdat_group);
+       next != this; next = dyn_cast<cgraph_node *> (next->same_comdat_group))
+    {
+      if (!externally_visible)
+       continue;
+      if (!next->alias
+         && !next->can_remove_if_no_direct_calls_and_refs_p ())
+       return false;
+
+      /* If we see different symbol than THIS, be sure to check calls.  */
+      if (next->ultimate_alias_target () != target)
+       for (cgraph_edge *e = next->callers; e; e = e->next_caller)
+         if (e->caller->get_comdat_group () != get_comdat_group ())
+           return false;
+
+      for (int i = 0; next->iterate_referring (i, ref); i++)
+       if (ref->referring->get_comdat_group () != get_comdat_group ())
+         return false;
+    }
+  return true;
 }
 
 /* Return true when function cgraph_node can be expected to be removed
@@ -2442,19 +2481,47 @@ cgraph_node::can_remove_if_no_direct_calls_p (void)
 bool
 cgraph_node::will_be_removed_from_program_if_no_direct_calls_p (void)
 {
+  struct ipa_ref *ref;
   gcc_assert (!global.inlined_to);
+  if (DECL_EXTERNAL (decl))
+    return true;
 
-  if (call_for_symbol_and_aliases (used_from_object_file_p_worker,
-                                  NULL, true))
-    return false;
   if (!in_lto_p && !flag_whole_program)
-    return only_called_directly_p ();
-  else
     {
-       if (DECL_EXTERNAL (decl))
-         return true;
-      return can_remove_if_no_direct_calls_p ();
+      /* If the symbol is in comdat group, we need to verify that whole comdat
+        group becomes unreachable.  Technically we could skip references from
+        within the group, too.  */
+      if (!only_called_directly_p ())
+       return false;
+      if (same_comdat_group && externally_visible)
+       {
+         struct cgraph_node *target = ultimate_alias_target ();
+         for (cgraph_node *next = dyn_cast<cgraph_node *> (same_comdat_group);
+              next != this;
+              next = dyn_cast<cgraph_node *> (next->same_comdat_group))
+           {
+             if (!externally_visible)
+               continue;
+             if (!next->alias
+                 && !next->only_called_directly_p ())
+               return false;
+
+             /* If we see different symbol than THIS,
+                be sure to check calls.  */
+             if (next->ultimate_alias_target () != target)
+               for (cgraph_edge *e = next->callers; e; e = e->next_caller)
+                 if (e->caller->get_comdat_group () != get_comdat_group ())
+                   return false;
+
+             for (int i = 0; next->iterate_referring (i, ref); i++)
+               if (ref->referring->get_comdat_group () != get_comdat_group ())
+                 return false;
+           }
+       }
+      return true;
     }
+  else
+    return can_remove_if_no_direct_calls_p ();
 }
 
 
index 82519fa8a3e8e9191c3dd8df86fdc5d4eb858472..c4f39bab4e1347c2f51d47c3434b69d0e75a6e7b 100644 (file)
@@ -258,8 +258,8 @@ public:
      When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
      skipped.  */
   bool call_for_symbol_and_aliases (bool (*callback) (symtab_node *, void *),
-                                 void *data,
-                                 bool include_overwrite);
+                                   void *data,
+                                   bool include_overwrite);
 
   /* If node can not be interposable by static or dynamic linker to point to
      different definition, return this symbol. Otherwise look for alias with
@@ -1187,12 +1187,6 @@ public:
      returns cgraph_node::get (DECL).  */
   static cgraph_node * create_same_body_alias (tree alias, tree decl);
 
-  /* Worker for cgraph_can_remove_if_no_direct_calls_p.  */
-  static bool used_from_object_file_p_worker (cgraph_node *node, void *)
-  {
-    return node->used_from_object_file_p ();
-  }
-
   /* Verify whole cgraph structure.  */
   static void DEBUG_FUNCTION verify_cgraph_nodes (void);
 
@@ -2736,6 +2730,7 @@ cgraph_node::only_called_directly_or_aliased_p (void)
          && !DECL_VIRTUAL_P (decl)
          && !DECL_STATIC_CONSTRUCTOR (decl)
          && !DECL_STATIC_DESTRUCTOR (decl)
+         && !used_from_object_file_p ()
          && !externally_visible);
 }
 
index 7a9c99cc512c0cb5bc4355e6927e58ff2a471a46..d74716306170fc91dbe290edf6a1761ccbc15869 100644 (file)
@@ -4007,6 +4007,8 @@ growth_likely_positive (struct cgraph_node *node,
   struct cgraph_edge *e;
   gcc_checking_assert (edge_growth > 0);
 
+  if (DECL_EXTERNAL (node->decl))
+    return true;
   /* Unlike for functions called once, we play unsafe with
      COMDATs.  We can allow that since we know functions
      in consideration are small (and thus risk is small) and
@@ -4014,18 +4016,13 @@ growth_likely_positive (struct cgraph_node *node,
      functions may or may not disappear when eliminated from
      current unit. With good probability making aggressive
      choice in all units is going to make overall program
-     smaller.
-
-     Consequently we ask cgraph_can_remove_if_no_direct_calls_p
-     instead of
-     cgraph_will_be_removed_from_program_if_no_direct_calls  */
-  if (DECL_EXTERNAL (node->decl)
-      || !node->can_remove_if_no_direct_calls_p ())
-    return true;
-
-  if (!node->will_be_removed_from_program_if_no_direct_calls_p ()
-      && (!DECL_COMDAT (node->decl)
-         || !node->can_remove_if_no_direct_calls_p ()))
+     smaller.  */
+  if (DECL_COMDAT (node->decl))
+    {
+      if (!node->can_remove_if_no_direct_calls_p ())
+       return true;
+    }
+  else if (!node->will_be_removed_from_program_if_no_direct_calls_p ())
     return true;
   max_callers = inline_summaries->get (node)->size * 4 / edge_growth + 2;
 
index 38a98dbe43cbb5d081ef20deab7ba902e9f34de3..43bb41fa8fa960a88b5c88cee0a6125512e7b256 100644 (file)
@@ -112,9 +112,12 @@ can_remove_node_now_p_1 (struct cgraph_node *node, struct cgraph_edge *e)
     }
   /* FIXME: When address is taken of DECL_EXTERNAL function we still
      can remove its offline copy, but we would need to keep unanalyzed node in
-     the callgraph so references can point to it.  */
+     the callgraph so references can point to it.
+
+     Also for comdat group we can ignore references inside a group as we
+     want to prove the group as a whole to be dead.  */
   return (!node->address_taken
-         && node->can_remove_if_no_direct_calls_p ()
+         && node->can_remove_if_no_direct_calls_and_refs_p ()
          /* Inlining might enable more devirtualizing, so we want to remove
             those only after all devirtualizable virtual calls are processed.
             Lacking may edges in callgraph we just preserve them post