OSDN Git Service

2010-04-29 Brian Hackett <bhackett1024@gmail.com>
[pf3gnuchains/gcc-fork.git] / gcc / lto-symtab.c
index 642b623..a35d82f 100644 (file)
@@ -44,6 +44,9 @@ struct GTY(()) lto_symtab_entry_def
   /* The cgraph node if decl is a function decl.  Filled in during the
      merging process.  */
   struct cgraph_node *node;
+  /* The varpool node if decl is a variable decl.  Filled in during the
+     merging process.  */
+  struct varpool_node *vnode;
   /* LTO file-data and symbol resolution for this decl.  */
   struct lto_file_decl_data * GTY((skip (""))) file_data;
   enum ld_plugin_symbol_resolution resolution;
@@ -86,7 +89,7 @@ lto_symtab_entry_eq (const void *p1, const void *p2)
 }
 
 /* Returns non-zero if P points to an lto_symtab_entry_def struct that needs
-   to be marked for GC.  */ 
+   to be marked for GC.  */
 
 static int
 lto_symtab_entry_marked_p (const void *p)
@@ -221,10 +224,49 @@ lto_cgraph_replace_node (struct cgraph_node *node,
       cgraph_remove_edge (e);
     }
 
+  if (node->same_body)
+    {
+      struct cgraph_node *alias;
+
+      for (alias = node->same_body; alias; alias = alias->next)
+       if (DECL_ASSEMBLER_NAME_SET_P (alias->decl))
+         {
+           lto_symtab_entry_t se
+             = lto_symtab_get (DECL_ASSEMBLER_NAME (alias->decl));
+
+           for (; se; se = se->next)
+             if (se->node == node)
+               {
+                 se->node = NULL;
+                 break;
+               }
+         }
+    }
+
   /* Finally remove the replaced node.  */
   cgraph_remove_node (node);
 }
 
+/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
+   all edges and removing the old node.  */
+
+static void
+lto_varpool_replace_node (struct varpool_node *vnode,
+                         struct varpool_node *prevailing_node)
+{
+  /* Merge node flags.  */
+  if (vnode->needed)
+    {
+      gcc_assert (prevailing_node->analyzed);
+      varpool_mark_needed_node (prevailing_node);
+    }
+  gcc_assert (!vnode->finalized || prevailing_node->finalized);
+  gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
+
+  /* Finally remove the replaced node.  */
+  varpool_remove_node (vnode);
+}
+
 /* Merge two variable or function symbol table entries PREVAILING and ENTRY.
    Return false if the symbols are not fully compatible and a diagnostic
    should be emitted.  */
@@ -352,7 +394,10 @@ lto_symtab_resolve_replaceable_p (lto_symtab_entry_t e)
 static bool
 lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e)
 {
-  if (!TREE_STATIC (e->decl))
+  /* The C++ frontend ends up neither setting TREE_STATIC nor
+     DECL_EXTERNAL on virtual methods but only TREE_PUBLIC.
+     So do not reject !TREE_STATIC here but only DECL_EXTERNAL.  */
+  if (DECL_EXTERNAL (e->decl))
     return false;
 
   /* For functions we need a non-discarded body.  */
@@ -376,20 +421,28 @@ lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e)
 static void
 lto_symtab_resolve_symbols (void **slot)
 {
-  lto_symtab_entry_t e = (lto_symtab_entry_t) *slot;
+  lto_symtab_entry_t e;
   lto_symtab_entry_t prevailing = NULL;
 
-  /* If the chain is already resolved there is nothing to do.  */
+  /* Always set e->node so that edges are updated to reflect decl merging. */
+  for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
+    {
+      if (TREE_CODE (e->decl) == FUNCTION_DECL)
+       e->node = cgraph_get_node (e->decl);
+      else if (TREE_CODE (e->decl) == VAR_DECL)
+       e->vnode = varpool_get_node (e->decl);
+    }
+
+  e = (lto_symtab_entry_t) *slot;
+
+  /* If the chain is already resolved there is nothing else to do.  */
   if (e->resolution != LDPR_UNKNOWN)
     return;
 
   /* Find the single non-replaceable prevailing symbol and
      diagnose ODR violations.  */
-  for (; e; e = e->next)
+  for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
     {
-      if (TREE_CODE (e->decl) == FUNCTION_DECL)
-       e->node = cgraph_get_node (e->decl);
-
       if (!lto_symtab_resolve_can_prevail_p (e))
        {
          e->resolution = LDPR_RESOLVED_IR;
@@ -531,6 +584,10 @@ lto_symtab_merge_decls_1 (void **slot, void *data ATTRIBUTE_UNUSED)
        while (!prevailing->node
               && prevailing->next)
          prevailing = prevailing->next;
+      if (TREE_CODE (prevailing->decl) == VAR_DECL)
+       while (!prevailing->vnode
+              && prevailing->next)
+         prevailing = prevailing->next;
       /* We do not stream varpool nodes, so the first decl has to
         be good enough for now.
         ???  For QOI choose a variable with readonly initializer
@@ -597,7 +654,8 @@ lto_symtab_merge_decls_1 (void **slot, void *data ATTRIBUTE_UNUSED)
   lto_symtab_merge_decls_2 (slot);
 
   /* Drop all but the prevailing decl from the symtab.  */
-  if (TREE_CODE (prevailing->decl) != FUNCTION_DECL)
+  if (TREE_CODE (prevailing->decl) != FUNCTION_DECL
+      && TREE_CODE (prevailing->decl) != VAR_DECL)
     prevailing->next = NULL;
 
   return 1;
@@ -622,13 +680,28 @@ lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED)
   if (!prevailing->next)
     return 1;
 
-  gcc_assert (TREE_CODE (prevailing->decl) == FUNCTION_DECL);
-
   /* Replace the cgraph node of each entry with the prevailing one.  */
   for (e = prevailing->next; e; e = e->next)
     {
       if (e->node != NULL)
-       lto_cgraph_replace_node (e->node, prevailing->node);
+       {
+         if (e->node->decl != e->decl && e->node->same_body)
+           {
+             struct cgraph_node *alias;
+
+             for (alias = e->node->same_body; alias; alias = alias->next)
+               if (alias->decl == e->decl)
+                 break;
+             if (alias)
+               {
+                 cgraph_remove_same_body_alias (alias);
+                 continue;
+               }
+           }
+         lto_cgraph_replace_node (e->node, prevailing->node);
+       }
+      if (e->vnode != NULL)
+       lto_varpool_replace_node (e->vnode, prevailing->vnode);
     }
 
   /* Drop all but the prevailing decl from the symtab.  */