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;
/* 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)
}
-static bool maybe_merge_incomplete_and_complete_type (tree, tree);
-
-/* Try to merge an incomplete type INCOMPLETE with a complete type
- COMPLETE of same kinds.
- Return true if they were merged, false otherwise. */
-
-static bool
-merge_incomplete_and_complete_type (tree incomplete, tree complete)
-{
- /* For merging array types do some extra sanity checking. */
- if (TREE_CODE (incomplete) == ARRAY_TYPE
- && !maybe_merge_incomplete_and_complete_type (TREE_TYPE (incomplete),
- TREE_TYPE (complete))
- && !gimple_types_compatible_p (TREE_TYPE (incomplete),
- TREE_TYPE (complete)))
- return false;
-
- /* ??? Ideally we would do this by means of a common canonical type, but
- that's difficult as we do not have links from the canonical type
- back to all its children. */
- gimple_force_type_merge (incomplete, complete);
-
- return true;
-}
-
-/* Try to merge a maybe complete / incomplete type pair TYPE1 and TYPE2.
- Return true if they were merged, false otherwise. */
-
-static bool
-maybe_merge_incomplete_and_complete_type (tree type1, tree type2)
-{
- bool res = false;
-
- if (TREE_CODE (type1) != TREE_CODE (type2))
- return false;
-
- if (!COMPLETE_TYPE_P (type1) && COMPLETE_TYPE_P (type2))
- res = merge_incomplete_and_complete_type (type1, type2);
- else if (COMPLETE_TYPE_P (type1) && !COMPLETE_TYPE_P (type2))
- res = merge_incomplete_and_complete_type (type2, type1);
-
- /* Recurse on pointer targets. */
- if (!res
- && POINTER_TYPE_P (type1)
- && POINTER_TYPE_P (type2))
- res = maybe_merge_incomplete_and_complete_type (TREE_TYPE (type1),
- TREE_TYPE (type2));
-
- return res;
-}
-
/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
all edges and removing the old 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);
}
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 (!gimple_types_compatible_p (TREE_TYPE (prevailing_decl),
- TREE_TYPE (decl)))
+ if (TREE_TYPE (prevailing_decl) != TREE_TYPE (decl))
/* 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
/* Now we exclusively deal with VAR_DECLs. */
- /* Handle external declarations with incomplete type or pointed-to
- incomplete types by forcefully merging the types.
- ??? In principle all types involved in the two decls should
- be merged forcefully, for example without considering type or
- field names. */
- prevailing_type = TREE_TYPE (prevailing_decl);
- type = TREE_TYPE (decl);
-
- /* If the types are structurally equivalent we can use the knowledge
- that both bind to the same symbol to complete incomplete types
- of external declarations or of pointer targets.
- ??? We should apply this recursively to aggregate members here
- and get rid of the completion in gimple_types_compatible_p. */
- if (DECL_EXTERNAL (prevailing_decl) || DECL_EXTERNAL (decl))
- maybe_merge_incomplete_and_complete_type (prevailing_type, type);
- else if (POINTER_TYPE_P (prevailing_type)
- && POINTER_TYPE_P (type))
- maybe_merge_incomplete_and_complete_type (TREE_TYPE (prevailing_type),
- TREE_TYPE (type));
+ /* Sharing a global symbol is a strong hint that two types are
+ compatible. We could use this information to complete
+ incomplete pointed-to types more aggressively here, ignoring
+ mismatches in both field and tag names. It's difficult though
+ to guarantee that this does not have side-effects on merging
+ more compatible types from other translation units though. */
/* We can tolerate differences in type qualification, the
- qualification of the prevailing definition will prevail. */
+ qualification of the prevailing definition will prevail.
+ ??? In principle we might want to only warn for structurally
+ incompatible types here, but unless we have protective measures
+ for TBAA in place that would hide useful information. */
prevailing_type = TYPE_MAIN_VARIANT (TREE_TYPE (prevailing_decl));
type = TYPE_MAIN_VARIANT (TREE_TYPE (decl));
- if (!gimple_types_compatible_p (prevailing_type, type))
- return false;
+
+ /* We have to register and fetch canonical types here as the global
+ fixup process didn't yet run. */
+ prevailing_type = gimple_register_type (prevailing_type);
+ type = gimple_register_type (type);
+ if (prevailing_type != type)
+ {
+ if (COMPLETE_TYPE_P (type))
+ return false;
+
+ /* If type is incomplete then avoid warnings in the cases
+ that TBAA handles just fine. */
+
+ if (TREE_CODE (prevailing_type) != TREE_CODE (type))
+ return false;
+
+ if (TREE_CODE (prevailing_type) == ARRAY_TYPE)
+ {
+ tree tem1 = TREE_TYPE (prevailing_type);
+ tree tem2 = TREE_TYPE (type);
+ while (TREE_CODE (tem1) == ARRAY_TYPE
+ && TREE_CODE (tem2) == ARRAY_TYPE)
+ {
+ tem1 = TREE_TYPE (tem1);
+ tem2 = TREE_TYPE (tem2);
+ }
+
+ if (TREE_CODE (tem1) != TREE_CODE (tem2))
+ return false;
+
+ if (gimple_register_type (tem1) != gimple_register_type (tem2))
+ return false;
+ }
+
+ /* Fallthru. Compatible enough. */
+ }
/* ??? We might want to emit a warning here if type qualification
differences were spotted. Do not do this unconditionally though. */
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);
+ }
+
+ 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))
{
/* Diagnose all mismatched re-declarations. */
for (i = 0; VEC_iterate (tree, mismatches, i, decl); ++i)
{
- if (!gimple_types_compatible_p (TREE_TYPE (prevailing->decl),
- TREE_TYPE (decl)))
+ if (TREE_TYPE (prevailing->decl) != TREE_TYPE (decl))
diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0,
"type of %qD does not match original "
"declaration", decl);
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
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)
+ 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;
+
+ 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)
+ {
+ 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);
+ }
+ }
+
+ /* 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"