tree id;
/* The symbol table entry, a DECL. */
tree decl;
+ /* 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;
}
/* 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)
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. */
tree prevailing_decl = prevailing->decl;
tree decl = entry->decl;
tree prevailing_type, type;
- struct cgraph_node *node;
/* Merge decl state in both directions, we may still end up using
the new decl. */
TREE_ADDRESSABLE (prevailing_decl) |= TREE_ADDRESSABLE (decl);
TREE_ADDRESSABLE (decl) |= TREE_ADDRESSABLE (prevailing_decl);
- /* Replace a cgraph node of entry with the prevailing one. */
- if (TREE_CODE (decl) == FUNCTION_DECL
- && (node = cgraph_get_node (decl)) != NULL)
- lto_cgraph_replace_node (node, cgraph_get_node (prevailing_decl));
-
/* The linker may ask us to combine two incompatible symbols.
Detect this case and notify the caller of required diagnostics. */
static bool
lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e)
{
- struct cgraph_node *node;
-
- 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. */
if (TREE_CODE (e->decl) == FUNCTION_DECL)
- return ((node = cgraph_get_node (e->decl))
- && node->analyzed);
+ return (e->node && e->node->analyzed);
/* A variable should have a size. */
else if (TREE_CODE (e->decl) == VAR_DECL)
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 (!lto_symtab_resolve_can_prevail_p (e))
{
prevailing = (lto_symtab_entry_t) *slot;
/* For functions choose one with a cgraph node. */
if (TREE_CODE (prevailing->decl) == FUNCTION_DECL)
- while (!cgraph_get_node (prevailing->decl)
+ 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
lto_symtab_merge_decls_2 (slot);
/* Drop all but the prevailing decl from the symtab. */
- prevailing->next = NULL;
+ if (TREE_CODE (prevailing->decl) != FUNCTION_DECL
+ && TREE_CODE (prevailing->decl) != VAR_DECL)
+ prevailing->next = NULL;
return 1;
}
htab_traverse (lto_symtab_identifiers, lto_symtab_merge_decls_1, NULL);
}
+/* Helper to process the decl chain for the symbol table entry *SLOT. */
+
+static int
+lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+ lto_symtab_entry_t e, prevailing = (lto_symtab_entry_t) *slot;
+
+ if (!prevailing->next)
+ return 1;
+
+ /* Replace the cgraph node of each entry with the prevailing one. */
+ for (e = prevailing->next; e; e = e->next)
+ {
+ if (e->node != NULL)
+ {
+ 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. */
+ prevailing->next = NULL;
+
+ return 1;
+}
+
+/* Merge cgraph nodes according to the symbol merging done by
+ lto_symtab_merge_decls. */
+
+void
+lto_symtab_merge_cgraph_nodes (void)
+{
+ lto_symtab_maybe_init_hash_table ();
+ htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL);
+}
/* Given the decl DECL, return the prevailing decl with the same name. */
return ret->decl;
}
-/* Remove any storage used to store resolution of DECL. */
-
-void
-lto_symtab_clear_resolution (tree decl)
-{
- struct lto_symtab_entry_def temp;
- lto_symtab_entry_t head;
- void **slot;
-
- if (!TREE_PUBLIC (decl))
- return;
-
- /* LTO FIXME: There should be no DECL_ABSTRACT in the middle end. */
- if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
- return;
-
- gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
-
- lto_symtab_maybe_init_hash_table ();
- temp.id = DECL_ASSEMBLER_NAME (decl);
- slot = htab_find_slot (lto_symtab_identifiers, &temp, NO_INSERT);
- if (!*slot)
- return;
-
- head = (lto_symtab_entry_t) *slot;
- if (head->decl == decl)
- {
- if (head->next)
- {
- *slot = head->next;
- head->next = NULL;
- }
- else
- htab_remove_elt (lto_symtab_identifiers, &temp);
- }
- else
- {
- lto_symtab_entry_t e;
- while (head->next && head->next->decl != decl)
- head = head->next;
- if (head->next)
- {
- e = head->next;
- head->next = e->next;
- e->next = NULL;
- }
- }
-}
-
#include "gt-lto-symtab.h"