#include "config.h"
#include "system.h"
#include "coretypes.h"
+#include "diagnostic-core.h"
#include "toplev.h"
#include "tree.h"
#include "gimple.h"
-#include "ggc.h" /* lambda.h needs this */
+#include "ggc.h"
#include "lambda.h" /* gcd */
#include "hashtab.h"
#include "plugin-api.h"
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;
param_is (struct lto_symtab_entry_def)))
htab_t lto_symtab_identifiers;
+/* Free symtab hashtable. */
+
+void
+lto_symtab_free (void)
+{
+ htab_delete (lto_symtab_identifiers);
+ lto_symtab_identifiers = NULL;
+}
+
/* Return the hash value of an lto_symtab_entry_t object pointed to by P. */
static hashval_t
{
const struct lto_symtab_entry_def *base =
(const struct lto_symtab_entry_def *) p;
- return htab_hash_string (IDENTIFIER_POINTER (base->id));
+ return IDENTIFIER_HASH_VALUE (base->id);
}
/* Return non-zero if P1 and P2 points to lto_symtab_entry_def structs
}
/* 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)
const struct lto_symtab_entry_def *base =
(const struct lto_symtab_entry_def *) p;
- /* Keep this only if the decl or the chain is marked. */
- return (ggc_marked_p (base->decl)
- || (base->next && ggc_marked_p (base->next)));
+ /* Keep this only if the common IDENTIFIER_NODE of the symtab chain
+ is marked which it will be if at least one of the DECLs in the
+ chain is marked. */
+ return ggc_marked_p (base->id);
}
/* Lazily initialize resolution hash tables. */
if (TREE_CODE (decl) == FUNCTION_DECL)
gcc_assert (!DECL_ABSTRACT (decl));
- new_entry = GGC_CNEW (struct lto_symtab_entry_def);
+ new_entry = ggc_alloc_cleared_lto_symtab_entry_def ();
new_entry->id = DECL_ASSEMBLER_NAME (decl);
new_entry->decl = decl;
new_entry->resolution = resolution;
struct cgraph_node *prevailing_node)
{
struct cgraph_edge *e, *next;
+ bool no_aliases_please = false;
+
+ if (cgraph_dump_file)
+ {
+ fprintf (cgraph_dump_file, "Replacing cgraph node %s/%i by %s/%i"
+ " for symbol %s\n",
+ cgraph_node_name (node), node->uid,
+ cgraph_node_name (prevailing_node),
+ prevailing_node->uid,
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl)));
+ }
+
+ if (prevailing_node->same_body_alias)
+ {
+ if (prevailing_node->thunk.thunk_p)
+ no_aliases_please = true;
+ prevailing_node = prevailing_node->same_body;
+ }
/* Merge node flags. */
if (node->needed)
next = e->next_caller;
cgraph_redirect_edge_callee (e, prevailing_node);
}
+ /* Redirect incomming references. */
+ ipa_clone_refering (prevailing_node, NULL, &node->ref_list);
- /* There are not supposed to be any outgoing edges from a node we
- replace. Still this can happen for multiple instances of weak
- functions. */
- for (e = node->callees; e; e = next)
+ /* If we have aliases, redirect them to the prevailing node. */
+ if (!node->same_body_alias && node->same_body)
{
- next = e->next_callee;
- cgraph_remove_edge (e);
+ struct cgraph_node *alias, *last;
+ /* We prevail aliases/tunks by a thunk. This is doable but
+ would need thunk combination. Hopefully no ABI changes will
+ every be crazy enough. */
+ gcc_assert (!no_aliases_please);
+
+ for (alias = node->same_body; alias; alias = alias->next)
+ {
+ last = alias;
+ gcc_assert (alias->same_body_alias);
+ alias->same_body = prevailing_node;
+ alias->thunk.alias = prevailing_node->decl;
+ }
+ last->next = prevailing_node->same_body;
+ /* Node with aliases is prevailed by alias.
+ We could handle this, but combining thunks together will be tricky.
+ Hopefully this does not happen. */
+ if (prevailing_node->same_body)
+ prevailing_node->same_body->previous = last;
+ prevailing_node->same_body = node->same_body;
+ node->same_body = NULL;
}
/* Finally remove the replaced node. */
- cgraph_remove_node (node);
+ if (node->same_body_alias)
+ cgraph_remove_same_body_alias (node);
+ else
+ 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 (!vnode->analyzed || prevailing_node->analyzed);
+ varpool_mark_needed_node (prevailing_node);
+ }
+ /* Relink aliases. */
+ if (vnode->extra_name && !vnode->alias)
+ {
+ struct varpool_node *alias, *last;
+ for (alias = vnode->extra_name;
+ alias; alias = alias->next)
+ {
+ last = alias;
+ alias->extra_name = prevailing_node;
+ }
+
+ if (prevailing_node->extra_name)
+ {
+ last->next = prevailing_node->extra_name;
+ prevailing_node->extra_name->prev = last;
+ }
+ prevailing_node->extra_name = vnode->extra_name;
+ vnode->extra_name = NULL;
+ }
+ gcc_assert (!vnode->finalized || prevailing_node->finalized);
+ gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
+
+ /* When replacing by an alias, the references goes to the original
+ variable. */
+ if (prevailing_node->alias && prevailing_node->extra_name)
+ prevailing_node = prevailing_node->extra_name;
+ ipa_clone_refering (NULL, prevailing_node, &vnode->ref_list);
+
+ /* Be sure we can garbage collect the initializer. */
+ if (DECL_INITIAL (vnode->decl))
+ DECL_INITIAL (vnode->decl) = error_mark_node;
+ /* Finally remove the replaced node. */
+ varpool_remove_node (vnode);
}
/* Merge two variable or function symbol table entries PREVAILING and ENTRY.
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. */
if (TREE_CODE (decl) == FUNCTION_DECL)
{
- if (TREE_TYPE (prevailing_decl) != TREE_TYPE (decl))
+ if (!gimple_types_compatible_p (TREE_TYPE (prevailing_decl),
+ TREE_TYPE (decl), GTC_DIAG))
/* If we don't have a merged type yet...sigh. The linker
wouldn't complain if the types were mismatched, so we
probably shouldn't either. Just use the type from
fixup process didn't yet run. */
prevailing_type = gimple_register_type (prevailing_type);
type = gimple_register_type (type);
- if (prevailing_type != type)
+ if (!gimple_types_compatible_p (prevailing_type, type, GTC_DIAG))
{
if (COMPLETE_TYPE_P (type))
return false;
if (TREE_CODE (tem1) != TREE_CODE (tem2))
return false;
- if (gimple_register_type (tem1) != gimple_register_type (tem2))
+ if (!gimple_types_compatible_p (gimple_register_type (tem1),
+ gimple_register_type (tem2),
+ GTC_DIAG))
return false;
}
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
+ || (e->node->same_body_alias && e->node->same_body->analyzed)));
/* A variable should have a size. */
else if (TREE_CODE (e->decl) == VAR_DECL)
- return (DECL_SIZE (e->decl) != NULL_TREE
- /* The C++ frontend retains TREE_STATIC on the declaration
- of foo_ in struct Foo { static Foo *foo_; }; but it is
- not a definition. g++.dg/lto/20090315_0.C. */
- && !DECL_EXTERNAL (e->decl));
+ {
+ if (!e->vnode)
+ return false;
+ if (e->vnode->finalized)
+ return true;
+ return e->vnode->alias && e->vnode->extra_name->finalized;
+ }
gcc_unreachable ();
}
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_or_alias (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))
{
return;
found:
- if (TREE_CODE (prevailing->decl) == VAR_DECL
- && TREE_READONLY (prevailing->decl))
+ /* If current lto files represent the whole program,
+ it is correct to use LDPR_PREVALING_DEF_IRONLY.
+ If current lto files are part of whole program, internal
+ resolver doesn't know if it is LDPR_PREVAILING_DEF
+ or LDPR_PREVAILING_DEF_IRONLY. Use IRONLY conforms to
+ using -fwhole-program. Otherwise, it doesn't
+ matter using either LDPR_PREVAILING_DEF or
+ LDPR_PREVAILING_DEF_IRONLY
+
+ FIXME: above workaround due to gold plugin makes some
+ variables IRONLY, which are indeed PREVAILING_DEF in
+ resolution file. These variables still need manual
+ externally_visible attribute. */
prevailing->resolution = LDPR_PREVAILING_DEF_IRONLY;
- else
- prevailing->resolution = LDPR_PREVAILING_DEF;
}
/* Merge all decls in the symbol table chain to the prevailing decl and
return;
/* Diagnose all mismatched re-declarations. */
- for (i = 0; VEC_iterate (tree, mismatches, i, decl); ++i)
+ FOR_EACH_VEC_ELT (tree, mismatches, i, decl)
{
- if (TREE_TYPE (prevailing->decl) != TREE_TYPE (decl))
+ if (!gimple_types_compatible_p (TREE_TYPE (prevailing->decl),
+ TREE_TYPE (decl), GTC_DIAG))
diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0,
"type of %qD does not match original "
"declaration", decl);
/* Assert it's the only one. */
if (prevailing)
for (e = prevailing->next; e; e = e->next)
- gcc_assert (e->resolution != LDPR_PREVAILING_DEF_IRONLY
- && e->resolution != LDPR_PREVAILING_DEF);
+ {
+ if (e->resolution == LDPR_PREVAILING_DEF_IRONLY
+ || e->resolution == LDPR_PREVAILING_DEF)
+ fatal_error ("multiple prevailing defs for %qE",
+ DECL_NAME (prevailing->decl));
+ }
/* If there's not a prevailing symbol yet it's an external reference.
Happens a lot during ltrans. Choose the first symbol with a
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;
- /* 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
- if there is one. This matches C++
- struct Foo { static const int i = 1; }; without a real
- definition. */
+ /* For variables chose with a priority variant with vnode
+ attached (i.e. from unit where external declaration of
+ variable is actually used).
+ When there are multiple variants, chose one with size.
+ This is needed for C++ typeinfos, for example in
+ lto/20081204-1 there are typeifos in both units, just
+ one of them do have size. */
if (TREE_CODE (prevailing->decl) == VAR_DECL)
- while (!(TREE_READONLY (prevailing->decl)
- && DECL_INITIAL (prevailing->decl))
- && prevailing->next)
- prevailing = prevailing->next;
+ {
+ for (e = prevailing->next; e; e = e->next)
+ if ((!prevailing->vnode && e->vnode)
+ || ((prevailing->vnode != NULL) == (e->vnode != NULL)
+ && !COMPLETE_TYPE_P (TREE_TYPE (prevailing->decl))
+ && COMPLETE_TYPE_P (TREE_TYPE (e->decl))))
+ prevailing = e;
+ }
}
/* Move it first in the list. */
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;
+
+ /* Set used_from_object_file flags. */
+ if (prevailing->resolution == LDPR_PREVAILING_DEF
+ || prevailing->resolution == LDPR_PREEMPTED_REG
+ || prevailing->resolution == LDPR_RESOLVED_EXEC
+ || prevailing->resolution == LDPR_RESOLVED_DYN)
+ {
+ if (TREE_CODE (prevailing->decl) == FUNCTION_DECL)
+ {
+ if (prevailing->node->same_body_alias)
+ prevailing->node->same_body->local.used_from_object_file = true;
+ else
+ prevailing->node->local.used_from_object_file = true;
+ }
+ else
+ {
+ if (prevailing->vnode->alias)
+ prevailing->vnode->extra_name->used_from_object_file = true;
+ else
+ prevailing->vnode->used_from_object_file = true;
+ }
+ }
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)
+ 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"