cgraph.c (ld_plugin_symbol_resolution_names): New.
authorJan Hubicka <hubicka@gcc.gnu.org>
Sat, 20 Nov 2010 21:10:46 +0000 (21:10 +0000)
committerJan Hubicka <hubicka@gcc.gnu.org>
Sat, 20 Nov 2010 21:10:46 +0000 (21:10 +0000)
* cgraph.c (ld_plugin_symbol_resolution_names): New.
(dump_cgraph_node): Dump resolution.
* cgraph.h (ld_plugin_symbol_resolution_names): Declare.
(cgraph_comdat_can_be_unshared_p): Dclare.
* lto-streamer-out.c (produce_symtab): Use
cgraph_comdat_can_be_unshared_p.
* ipa.c (cgraph_address_taken_from_non_vtable_p): New function.
(cgraph_comdat_can_be_unshared_p): New function based on logic
in cgraph_externally_visible_p.
(cgraph_externally_visible_p): Use it.
(varpool_externally_visible_p): Virtual tables can be unshared.
* varpool.c (dump_varpool_node): Dump resolution.

From-SVN: r166985

gcc/cgraph.h
gcc/ipa.c
gcc/lto-streamer-out.c
gcc/varpool.c

index 0334a154824c5dff2944049a13f7080fbb5fe320..99e4ee3eac63be8a19a72f6cb523daf941a8d9ec 100644 (file)
@@ -56,6 +56,7 @@ enum availability
 struct lto_file_decl_data;
 
 extern const char * const cgraph_availability_names[];
+extern const char * const ld_plugin_symbol_resolution_names[];
 
 /* Function inlining information.  */
 
@@ -695,6 +696,7 @@ void varpool_node_set_remove (varpool_node_set, struct varpool_node *);
 void dump_varpool_node_set (FILE *, varpool_node_set);
 void debug_varpool_node_set (varpool_node_set);
 void ipa_discover_readonly_nonaddressable_vars (void);
+bool cgraph_comdat_can_be_unshared_p (struct cgraph_node *);
 
 /* In predict.c  */
 bool cgraph_maybe_hot_edge_p (struct cgraph_edge *e);
index 3742f84e53b26dc7b07d6ffb9fb49a4aa4795054..28e6872ef7ffe2a47e1ee88e92e8b1c90799e5b4 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -588,6 +588,56 @@ ipa_discover_readonly_nonaddressable_vars (void)
     fprintf (dump_file, "\n");
 }
 
+/* Return true when there is a reference to node and it is not vtable.  */
+static bool
+cgraph_address_taken_from_non_vtable_p (struct cgraph_node *node)
+{
+  int i;
+  struct ipa_ref *ref;
+  for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++)
+    {
+      struct varpool_node *node;
+      if (ref->refered_type == IPA_REF_CGRAPH)
+       return true;
+      node = ipa_ref_varpool_node (ref);
+      if (!DECL_VIRTUAL_P (node->decl))
+       return true;
+    }
+  return false;
+}
+
+/* COMDAT functions must be shared only if they have address taken,
+   otherwise we can produce our own private implementation with
+   -fwhole-program.  
+   Return true when turning COMDAT functoin static can not lead to wrong
+   code when the resulting object links with a library defining same COMDAT.
+
+   Virtual functions do have their addresses taken from the vtables,
+   but in C++ there is no way to compare their addresses for equality.  */
+
+bool
+cgraph_comdat_can_be_unshared_p (struct cgraph_node *node)
+{
+  if ((cgraph_address_taken_from_non_vtable_p (node)
+       && !DECL_VIRTUAL_P (node->decl))
+      || !node->analyzed)
+    return false;
+  if (node->same_comdat_group)
+    {
+      struct cgraph_node *next;
+
+      /* If more than one function is in the same COMDAT group, it must
+         be shared even if just one function in the comdat group has
+         address taken.  */
+      for (next = node->same_comdat_group;
+          next != node; next = next->same_comdat_group)
+       if (cgraph_address_taken_from_non_vtable_p (node)
+           && !DECL_VIRTUAL_P (next->decl))
+         return false;
+    }
+  return true;
+}
+
 /* Return true when function NODE should be considered externally visible.  */
 
 static bool
@@ -613,6 +663,15 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool
   if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
     return true;
 
+  /* When doing LTO or whole program, we can bring COMDAT functoins static.
+     This improves code quality and we know we will duplicate them at most twice
+     (in the case that we are not using plugin and link with object file
+      implementing same COMDAT)  */
+  if ((in_lto_p || whole_program)
+      && DECL_COMDAT (node->decl)
+      && cgraph_comdat_can_be_unshared_p (node))
+    return false;
+
   /* See if we have linker information about symbol not being used or
      if we need to make guess based on the declaration.
 
@@ -635,27 +694,6 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool
     ;
   else 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.  */
-  else if (DECL_COMDAT (node->decl))
-    {
-      if (node->address_taken || !node->analyzed)
-       return true;
-      if (node->same_comdat_group)
-       {
-         struct cgraph_node *next;
-
-         /* If more than one function is in the same COMDAT group, it must
-            be shared even if just one function in the comdat group has
-            address taken.  */
-         for (next = node->same_comdat_group;
-              next != node;
-              next = next->same_comdat_group)
-           if (next->address_taken || !next->analyzed)
-             return true;
-       }
-    }
 
   if (MAIN_NAME_P (DECL_NAME (node->decl)))
     return true;
@@ -701,6 +739,16 @@ varpool_externally_visible_p (struct varpool_node *vnode, bool aliased)
   if (!alias && vnode->resolution == LDPR_PREVAILING_DEF_IRONLY)
     return false;
 
+  /* As a special case, the COMDAT virutal tables can be unshared.
+     In LTO mode turn vtables into static variables.  The variable is readonly,
+     so this does not enable more optimization, but referring static var
+     is faster for dynamic linking.  Also this match logic hidding vtables
+     from LTO symbol tables.  */
+  if ((in_lto_p || flag_whole_program)
+      && !vnode->force_output
+      && DECL_COMDAT (vnode->decl) && DECL_VIRTUAL_P (vnode->decl))
+    return false;
+
   /* When doing link time optimizations, hidden symbols become local.  */
   if (in_lto_p
       && (DECL_VISIBILITY (vnode->decl) == VISIBILITY_HIDDEN
index 20e39913044a24423d4531e77bbedcae05c7525b..b6414b69ac21d10c8be30901d5e757d14d4f37c7 100644 (file)
@@ -2492,7 +2492,7 @@ produce_symtab (struct output_block *ob,
       if (DECL_EXTERNAL (node->decl))
        continue;
       if (DECL_COMDAT (node->decl)
-         && cgraph_can_remove_if_no_direct_calls_p (node))
+         && cgraph_comdat_can_be_unshared_p (node))
        continue;
       if (node->alias || node->global.inlined_to)
        continue;
@@ -2506,7 +2506,7 @@ produce_symtab (struct output_block *ob,
       if (!DECL_EXTERNAL (node->decl))
        continue;
       if (DECL_COMDAT (node->decl)
-         && cgraph_can_remove_if_no_direct_calls_p (node))
+         && cgraph_comdat_can_be_unshared_p (node))
        continue;
       if (node->alias || node->global.inlined_to)
        continue;
@@ -2521,6 +2521,14 @@ produce_symtab (struct output_block *ob,
       vnode = lto_varpool_encoder_deref (varpool_encoder, i);
       if (DECL_EXTERNAL (vnode->decl))
        continue;
+      /* COMDAT virtual tables can be unshared.  Do not declare them
+        in the LTO symbol table to prevent linker from forcing them
+        into the output. */
+      if (DECL_COMDAT (vnode->decl)
+         && !vnode->force_output
+         && vnode->finalized 
+         && DECL_VIRTUAL_P (vnode->decl))
+       continue;
       if (vnode->alias)
        continue;
       write_symbol (cache, &stream, vnode->decl, seen, false);
@@ -2532,6 +2540,11 @@ produce_symtab (struct output_block *ob,
       vnode = lto_varpool_encoder_deref (varpool_encoder, i);
       if (!DECL_EXTERNAL (vnode->decl))
        continue;
+      if (DECL_COMDAT (vnode->decl)
+         && !vnode->force_output
+         && vnode->finalized 
+         && DECL_VIRTUAL_P (vnode->decl))
+       continue;
       if (vnode->alias)
        continue;
       write_symbol (cache, &stream, vnode->decl, seen, false);
index 88226601302fd4ffb6de026020ce0e27d83f0801..d266ce9a8cf1fb10bbbb57e055463aada15e90c1 100644 (file)
@@ -241,6 +241,9 @@ dump_varpool_node (FILE *f, struct varpool_node *node)
     fprintf (f, " output");
   if (node->externally_visible)
     fprintf (f, " externally_visible");
+  if (node->resolution != LDPR_UNKNOWN)
+    fprintf (f, " %s",
+            ld_plugin_symbol_resolution_names[(int)node->resolution]);
   if (node->in_other_partition)
     fprintf (f, " in_other_partition");
   else if (node->used_from_other_partition)