#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"
/* Vector to keep track of external variables we've seen so far. */
VEC(tree,gc) *lto_global_var_decls;
-/* Base type for resolution map. It maps NODE to resolution. */
+/* Symbol table entry. */
-struct GTY(()) lto_symtab_base_def
+struct GTY(()) lto_symtab_entry_def
{
- /* Key is either an IDENTIFIER or a DECL. */
- tree node;
-};
-typedef struct lto_symtab_base_def *lto_symtab_base_t;
-
-struct GTY(()) lto_symtab_identifier_def
-{
- struct lto_symtab_base_def base;
+ /* The symbol table entry key, an IDENTIFIER. */
+ tree id;
+ /* The symbol table entry, a DECL. */
tree decl;
-};
-typedef struct lto_symtab_identifier_def *lto_symtab_identifier_t;
-
-struct GTY(()) lto_symtab_decl_def
-{
- struct lto_symtab_base_def base;
- enum ld_plugin_symbol_resolution resolution;
+ /* 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;
+ /* True when resolution was guessed and not read from the file. */
+ bool guessed;
+ /* Pointer to the next entry with the same key. Before decl merging
+ this links all symbols from the different TUs. After decl merging
+ this links merged but incompatible decls, thus all prevailing ones
+ remaining. */
+ struct lto_symtab_entry_def *next;
};
-typedef struct lto_symtab_decl_def *lto_symtab_decl_t;
+typedef struct lto_symtab_entry_def *lto_symtab_entry_t;
/* A poor man's symbol table. This hashes identifier to prevailing DECL
if there is one. */
-static GTY ((if_marked ("lto_symtab_identifier_marked_p"),
- param_is (struct lto_symtab_identifier_def)))
+static GTY ((if_marked ("lto_symtab_entry_marked_p"),
+ param_is (struct lto_symtab_entry_def)))
htab_t lto_symtab_identifiers;
-static GTY ((if_marked ("lto_symtab_decl_marked_p"),
- param_is (struct lto_symtab_decl_def)))
- htab_t lto_symtab_decls;
+/* Free symtab hashtable. */
-/* Return the hash value of an lto_symtab_base_t object pointed to by P. */
-
-static hashval_t
-lto_symtab_base_hash (const void *p)
+void
+lto_symtab_free (void)
{
- const struct lto_symtab_base_def *base =
- (const struct lto_symtab_base_def*) p;
- return htab_hash_pointer (base->node);
+ htab_delete (lto_symtab_identifiers);
+ lto_symtab_identifiers = NULL;
}
-/* Return non-zero if P1 and P2 points to lto_symtab_base_def structs
- corresponding to the same tree node. */
+/* Return the hash value of an lto_symtab_entry_t object pointed to by P. */
-static int
-lto_symtab_base_eq (const void *p1, const void *p2)
+static hashval_t
+lto_symtab_entry_hash (const void *p)
{
- const struct lto_symtab_base_def *base1 =
- (const struct lto_symtab_base_def *) p1;
- const struct lto_symtab_base_def *base2 =
- (const struct lto_symtab_base_def *) p2;
- return (base1->node == base2->node);
+ const struct lto_symtab_entry_def *base =
+ (const struct lto_symtab_entry_def *) p;
+ return IDENTIFIER_HASH_VALUE (base->id);
}
-/* Returns non-zero if P points to an lto_symtab_base_def struct that needs
- to be marked for GC. */
+/* Return non-zero if P1 and P2 points to lto_symtab_entry_def structs
+ corresponding to the same symbol. */
static int
-lto_symtab_base_marked_p (const void *p)
+lto_symtab_entry_eq (const void *p1, const void *p2)
{
- const struct lto_symtab_base_def *base =
- (const struct lto_symtab_base_def *) p;
-
- /* Keep this only if the key node is marked. */
- return ggc_marked_p (base->node);
+ const struct lto_symtab_entry_def *base1 =
+ (const struct lto_symtab_entry_def *) p1;
+ const struct lto_symtab_entry_def *base2 =
+ (const struct lto_symtab_entry_def *) p2;
+ return (base1->id == base2->id);
}
-/* Returns non-zero if P points to an lto_symtab_identifier_def struct that
- needs to be marked for GC. */
+/* Returns non-zero if P points to an lto_symtab_entry_def struct that needs
+ to be marked for GC. */
static int
-lto_symtab_identifier_marked_p (const void *p)
+lto_symtab_entry_marked_p (const void *p)
{
- return lto_symtab_base_marked_p (p);
-}
+ const struct lto_symtab_entry_def *base =
+ (const struct lto_symtab_entry_def *) p;
-/* Returns non-zero if P points to an lto_symtab_decl_def struct that needs
- to be marked for GC. */
-
-static int
-lto_symtab_decl_marked_p (const void *p)
-{
- return lto_symtab_base_marked_p (p);
+ /* 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);
}
-#define lto_symtab_identifier_eq lto_symtab_base_eq
-#define lto_symtab_identifier_hash lto_symtab_base_hash
-#define lto_symtab_decl_eq lto_symtab_base_eq
-#define lto_symtab_decl_hash lto_symtab_base_hash
-
/* Lazily initialize resolution hash tables. */
static void
-lto_symtab_maybe_init_hash_tables (void)
+lto_symtab_maybe_init_hash_table (void)
{
- if (!lto_symtab_identifiers)
- {
- lto_symtab_identifiers =
- htab_create_ggc (1021, lto_symtab_identifier_hash,
- lto_symtab_identifier_eq, NULL);
- lto_symtab_decls =
- htab_create_ggc (1021, lto_symtab_decl_hash,
- lto_symtab_decl_eq, NULL);
- }
-}
+ if (lto_symtab_identifiers)
+ return;
-/* Returns true iff the union of ATTRIBUTES_1 and ATTRIBUTES_2 can be
- applied to DECL. */
-static bool
-lto_compatible_attributes_p (tree decl ATTRIBUTE_UNUSED,
- tree attributes_1,
- tree attributes_2)
-{
-#if 0
- /* ??? For now, assume two attribute sets are compatible only if they
- are both empty. */
- return !attributes_1 && !attributes_2;
-#else
- /* FIXME. For the moment, live dangerously, and assume the user knows
- what he's doing. I don't think the linker would distinguish these cases. */
- return true || (!attributes_1 && !attributes_2);
-#endif
+ lto_symtab_identifiers =
+ htab_create_ggc (1021, lto_symtab_entry_hash,
+ lto_symtab_entry_eq, NULL);
}
-/* Helper for lto_symtab_compatible. Return TRUE if DECL is an external
- variable declaration of an aggregate type. */
+/* Registers DECL with the LTO symbol table as having resolution RESOLUTION
+ and read from FILE_DATA. */
-static bool
-external_aggregate_decl_p (tree decl)
+void
+lto_symtab_register_decl (tree decl,
+ ld_plugin_symbol_resolution_t resolution,
+ struct lto_file_decl_data *file_data)
{
- return (TREE_CODE (decl) == VAR_DECL
- && DECL_EXTERNAL (decl)
- && AGGREGATE_TYPE_P (TREE_TYPE (decl)));
-}
+ lto_symtab_entry_t new_entry;
+ void **slot;
-static bool maybe_merge_incomplete_and_complete_type (tree, tree);
+ /* Check that declarations reaching this function do not have
+ properties inconsistent with having external linkage. If any of
+ these asertions fail, then the object file reader has failed to
+ detect these cases and issue appropriate error messages. */
+ gcc_assert (decl
+ && TREE_PUBLIC (decl)
+ && (TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL)
+ && DECL_ASSEMBLER_NAME_SET_P (decl));
+ if (TREE_CODE (decl) == VAR_DECL
+ && DECL_INITIAL (decl))
+ gcc_assert (!DECL_EXTERNAL (decl)
+ || (TREE_STATIC (decl) && TREE_READONLY (decl)));
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ gcc_assert (!DECL_ABSTRACT (decl));
+
+ new_entry = ggc_alloc_cleared_lto_symtab_entry_def ();
+ new_entry->id = DECL_ASSEMBLER_NAME (decl);
+ new_entry->decl = decl;
+ new_entry->resolution = resolution;
+ new_entry->file_data = file_data;
-/* Try to merge an incomplete type INCOMPLETE with a complete type
- COMPLETE of same kinds.
- Return true if they were merged, false otherwise. */
+ lto_symtab_maybe_init_hash_table ();
+ slot = htab_find_slot (lto_symtab_identifiers, new_entry, INSERT);
+ new_entry->next = (lto_symtab_entry_t) *slot;
+ *slot = new_entry;
+}
-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;
+/* Get the lto_symtab_entry_def struct associated with ID
+ if there is one. */
- /* ??? 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);
+static lto_symtab_entry_t
+lto_symtab_get (tree id)
+{
+ struct lto_symtab_entry_def temp;
+ void **slot;
- return true;
+ lto_symtab_maybe_init_hash_table ();
+ temp.id = id;
+ slot = htab_find_slot (lto_symtab_identifiers, &temp, NO_INSERT);
+ return slot ? (lto_symtab_entry_t) *slot : NULL;
}
-/* Try to merge a maybe complete / incomplete type pair TYPE1 and TYPE2.
- Return true if they were merged, false otherwise. */
+/* Get the linker resolution for DECL. */
-static bool
-maybe_merge_incomplete_and_complete_type (tree type1, tree type2)
+enum ld_plugin_symbol_resolution
+lto_symtab_get_resolution (tree decl)
{
- bool res = false;
-
- if (TREE_CODE (type1) != TREE_CODE (type2))
- return false;
+ lto_symtab_entry_t e;
- 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);
+ gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
- /* 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));
+ e = lto_symtab_get (DECL_ASSEMBLER_NAME (decl));
+ while (e && e->decl != decl)
+ e = e->next;
+ if (!e)
+ return LDPR_UNKNOWN;
- return res;
+ return e->resolution;
}
-/* Check if OLD_DECL and NEW_DECL are compatible. */
-static bool
-lto_symtab_compatible (tree old_decl, tree new_decl)
+/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
+ all edges and removing the old node. */
+
+static void
+lto_cgraph_replace_node (struct cgraph_node *node,
+ struct cgraph_node *prevailing_node)
{
- tree merged_type = NULL_TREE;
+ struct cgraph_edge *e, *next;
+ bool no_aliases_please = false;
- if (TREE_CODE (old_decl) != TREE_CODE (new_decl))
+ if (cgraph_dump_file)
{
- switch (TREE_CODE (new_decl))
- {
- case VAR_DECL:
- gcc_assert (TREE_CODE (old_decl) == FUNCTION_DECL);
- error_at (DECL_SOURCE_LOCATION (new_decl),
- "function %qD redeclared as variable", new_decl);
- inform (DECL_SOURCE_LOCATION (old_decl),
- "previously declared here");
- return false;
-
- case FUNCTION_DECL:
- gcc_assert (TREE_CODE (old_decl) == VAR_DECL);
- error_at (DECL_SOURCE_LOCATION (new_decl),
- "variable %qD redeclared as function", new_decl);
- inform (DECL_SOURCE_LOCATION (old_decl),
- "previously declared here");
- return false;
+ 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)));
+ }
- default:
- gcc_unreachable ();
- }
+ if (prevailing_node->same_body_alias)
+ {
+ if (prevailing_node->thunk.thunk_p)
+ no_aliases_please = true;
+ prevailing_node = prevailing_node->same_body;
}
- /* 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. */
- if (TREE_CODE (old_decl) == VAR_DECL)
+ /* Merge node flags. */
+ if (node->needed)
+ cgraph_mark_needed_node (prevailing_node);
+ if (node->reachable)
+ cgraph_mark_reachable_node (prevailing_node);
+ if (node->address_taken)
{
- tree old_type = TREE_TYPE (old_decl);
- tree new_type = TREE_TYPE (new_decl);
-
- if (DECL_EXTERNAL (old_decl) || DECL_EXTERNAL (new_decl))
- maybe_merge_incomplete_and_complete_type (old_type, new_type);
- else if (POINTER_TYPE_P (old_type)
- && POINTER_TYPE_P (new_type))
- maybe_merge_incomplete_and_complete_type (TREE_TYPE (old_type),
- TREE_TYPE (new_type));
-
- /* For array types we have to accept external declarations with
- different sizes than the actual definition (164.gzip).
- ??? We could emit a warning here. */
- if (TREE_CODE (old_type) == TREE_CODE (new_type)
- && TREE_CODE (old_type) == ARRAY_TYPE
- && COMPLETE_TYPE_P (old_type)
- && COMPLETE_TYPE_P (new_type)
- && tree_int_cst_compare (TYPE_SIZE (old_type),
- TYPE_SIZE (new_type)) != 0
- && gimple_types_compatible_p (TREE_TYPE (old_type),
- TREE_TYPE (new_type)))
- {
- /* If only one is external use the type of the non-external decl.
- Else use the larger one and also adjust the decl size.
- ??? Directional merging would allow us to simply pick the
- larger one instead of rewriting it. */
- if (DECL_EXTERNAL (old_decl) ^ DECL_EXTERNAL (new_decl))
- {
- if (DECL_EXTERNAL (old_decl))
- TREE_TYPE (old_decl) = new_type;
- else if (DECL_EXTERNAL (new_decl))
- TREE_TYPE (new_decl) = old_type;
- }
- else
- {
- if (tree_int_cst_compare (TYPE_SIZE (old_type),
- TYPE_SIZE (new_type)) < 0)
- {
- TREE_TYPE (old_decl) = new_type;
- DECL_SIZE (old_decl) = DECL_SIZE (new_decl);
- DECL_SIZE_UNIT (old_decl) = DECL_SIZE_UNIT (new_decl);
- }
- else
- {
- TREE_TYPE (new_decl) = old_type;
- DECL_SIZE (new_decl) = DECL_SIZE (old_decl);
- DECL_SIZE_UNIT (new_decl) = DECL_SIZE_UNIT (old_decl);
- }
- }
- }
+ gcc_assert (!prevailing_node->global.inlined_to);
+ cgraph_mark_address_taken_node (prevailing_node);
}
- if (!gimple_types_compatible_p (TREE_TYPE (old_decl), TREE_TYPE (new_decl)))
+ /* Redirect all incoming edges. */
+ for (e = node->callers; e; e = next)
{
- if (TREE_CODE (new_decl) == FUNCTION_DECL)
- {
- if (!merged_type
- /* We want either of the types to have argument types,
- but not both. */
- && ((TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != NULL)
- ^ (TYPE_ARG_TYPES (TREE_TYPE (new_decl)) != NULL)))
- {
- /* The situation here is that (in C) somebody was smart
- enough to use proper declarations in a header file, but
- the actual definition of the function uses
- non-ANSI-style argument lists. Or we have a situation
- where declarations weren't used anywhere and we're
- merging the actual definition with a use. One of the
- decls will then have a complete function type, whereas
- the other will only have a result type. Assume that
- the more complete type is the right one and don't
- complain. */
- if (TYPE_ARG_TYPES (TREE_TYPE (old_decl)))
- {
- merged_type = TREE_TYPE (old_decl);
- }
- else
- {
- merged_type = TREE_TYPE (new_decl);
- }
- }
+ next = e->next_caller;
+ cgraph_redirect_edge_callee (e, prevailing_node);
+ }
+ /* Redirect incomming references. */
+ ipa_clone_refering (prevailing_node, NULL, &node->ref_list);
- /* 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
- whichever decl appears to be associated with the
- definition. If for some odd reason neither decl is, the
- older one wins. */
- if (!merged_type)
- {
- if (!DECL_EXTERNAL (new_decl))
- {
- merged_type = TREE_TYPE (new_decl);
- }
- else
- {
- merged_type = TREE_TYPE (old_decl);
- }
- }
- }
+ /* If we have aliases, redirect them to the prevailing node. */
+ if (!node->same_body_alias && node->same_body)
+ {
+ 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);
- if (!merged_type)
+ for (alias = node->same_body; alias; alias = alias->next)
{
- if (warning_at (DECL_SOURCE_LOCATION (new_decl), 0,
- "type of %qD does not match original declaration",
- new_decl))
- inform (DECL_SOURCE_LOCATION (old_decl),
- "previously declared here");
- return false;
+ 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;
}
- if (DECL_UNSIGNED (old_decl) != DECL_UNSIGNED (new_decl))
+ /* Finally remove the replaced 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)
{
- error_at (DECL_SOURCE_LOCATION (new_decl),
- "signedness of %qD does not match original declaration",
- new_decl);
- inform (DECL_SOURCE_LOCATION (old_decl), "previously declared here");
- return false;
+ gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
+ varpool_mark_needed_node (prevailing_node);
}
-
- if (!tree_int_cst_equal (DECL_SIZE (old_decl),
- DECL_SIZE (new_decl))
- || !tree_int_cst_equal (DECL_SIZE_UNIT (old_decl),
- DECL_SIZE_UNIT (new_decl)))
+ /* Relink aliases. */
+ if (vnode->extra_name && !vnode->alias)
{
- /* Permit cases where we are declaring aggregates and at least one
- of the decls is external and one of the decls has a size whereas
- the other one does not. This is perfectly legal in C:
-
- struct s;
- extern struct s x;
-
- void*
- f (void)
- {
- return &x;
- }
-
- There is no way a compiler can tell the size of x. So we cannot
- assume that external aggreates have complete types. */
-
- if (!((TREE_CODE (TREE_TYPE (old_decl))
- == TREE_CODE (TREE_TYPE (new_decl)))
- && ((external_aggregate_decl_p (old_decl)
- && DECL_SIZE (old_decl) == NULL_TREE)
- || (external_aggregate_decl_p (new_decl)
- && DECL_SIZE (new_decl) == NULL_TREE))))
+ struct varpool_node *alias, *last;
+ for (alias = vnode->extra_name;
+ alias; alias = alias->next)
{
- error_at (DECL_SOURCE_LOCATION (new_decl),
- "size of %qD does not match original declaration",
- new_decl);
- inform (DECL_SOURCE_LOCATION (old_decl),
- "previously declared here");
- return false;
+ last = alias;
+ alias->extra_name = prevailing_node;
}
- }
- /* Report an error if user-specified alignments do not match. */
- if ((DECL_USER_ALIGN (old_decl) && DECL_USER_ALIGN (new_decl))
- && DECL_ALIGN (old_decl) != DECL_ALIGN (new_decl))
- {
- error_at (DECL_SOURCE_LOCATION (new_decl),
- "alignment of %qD does not match original declaration",
- new_decl);
- inform (DECL_SOURCE_LOCATION (old_decl), "previously declared here");
- return false;
+ 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);
+}
- /* Do not compare the modes of the decls. The type compatibility
- checks or the completing of types has properly dealt with all issues. */
+/* 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. */
- if (!lto_compatible_attributes_p (old_decl,
- DECL_ATTRIBUTES (old_decl),
- DECL_ATTRIBUTES (new_decl)))
+static bool
+lto_symtab_merge (lto_symtab_entry_t prevailing, lto_symtab_entry_t entry)
+{
+ tree prevailing_decl = prevailing->decl;
+ tree decl = entry->decl;
+ tree prevailing_type, type;
+
+ /* 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);
+
+ /* 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)
{
- error_at (DECL_SOURCE_LOCATION (new_decl),
- "attributes applied to %qD are incompatible with original "
- "declaration", new_decl);
- inform (DECL_SOURCE_LOCATION (old_decl), "previously declared here");
- return false;
+ 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
+ whichever decl appears to be associated with the
+ definition. If for some odd reason neither decl is, the
+ older one wins. */
+ (void) 0;
+
+ return true;
}
- /* We do not require matches for:
+ /* Now we exclusively deal with VAR_DECLs. */
+
+ /* 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.
+ ??? 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));
+
+ /* 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 (!gimple_types_compatible_p (prevailing_type, type, GTC_DIAG))
+ {
+ 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;
- - DECL_NAME
+ if (!gimple_types_compatible_p (gimple_register_type (tem1),
+ gimple_register_type (tem2),
+ GTC_DIAG))
+ return false;
+ }
- Only the name used in object files matters.
+ /* Fallthru. Compatible enough. */
+ }
- - DECL_CONTEXT
+ /* ??? We might want to emit a warning here if type qualification
+ differences were spotted. Do not do this unconditionally though. */
- An entity might be declared in a C++ namespace in one file and
- with a C identifier in another file.
+ /* There is no point in comparing too many details of the decls here.
+ The type compatibility checks or the completing of types has properly
+ dealt with most issues. */
- - TREE_PRIVATE, TREE_PROTECTED
+ /* The following should all not invoke fatal errors as in non-LTO
+ mode the linker wouldn't complain either. Just emit warnings. */
+
+ /* Report a warning if user-specified alignments do not match. */
+ if ((DECL_USER_ALIGN (prevailing_decl) && DECL_USER_ALIGN (decl))
+ && DECL_ALIGN (prevailing_decl) < DECL_ALIGN (decl))
+ return false;
- Access control is the problem of the front end that created the
- object file.
-
- Therefore, at this point we have decided to merge the declarations. */
return true;
}
+/* Return true if the symtab entry E can be replaced by another symtab
+ entry. */
-/* Marks decl DECL as having resolution RESOLUTION. */
-
-static void
-lto_symtab_set_resolution_and_file_data (tree decl,
- ld_plugin_symbol_resolution_t
- resolution,
- struct lto_file_decl_data *file_data)
+static bool
+lto_symtab_resolve_replaceable_p (lto_symtab_entry_t e)
{
- lto_symtab_decl_t new_entry;
- void **slot;
-
- gcc_assert (decl);
+ if (DECL_EXTERNAL (e->decl)
+ || DECL_COMDAT (e->decl)
+ || DECL_ONE_ONLY (e->decl)
+ || DECL_WEAK (e->decl))
+ return true;
- gcc_assert (TREE_PUBLIC (decl));
- gcc_assert (TREE_CODE (decl) != FUNCTION_DECL || !DECL_ABSTRACT (decl));
+ if (TREE_CODE (e->decl) == VAR_DECL)
+ return (DECL_COMMON (e->decl)
+ || (!flag_no_common && !DECL_INITIAL (e->decl)));
- new_entry = GGC_CNEW (struct lto_symtab_decl_def);
- new_entry->base.node = decl;
- new_entry->resolution = resolution;
- new_entry->file_data = file_data;
-
- lto_symtab_maybe_init_hash_tables ();
- slot = htab_find_slot (lto_symtab_decls, new_entry, INSERT);
- gcc_assert (!*slot);
- *slot = new_entry;
+ return false;
}
-/* Get the lto_symtab_identifier_def struct associated with ID
- if there is one. If there is none and INSERT_P is true, create
- a new one. */
+/* Return true if the symtab entry E can be the prevailing one. */
-static lto_symtab_identifier_t
-lto_symtab_get_identifier (tree id, bool insert_p)
+static bool
+lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e)
{
- struct lto_symtab_identifier_def temp;
- lto_symtab_identifier_t symtab_id;
- void **slot;
+ /* 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 (e->node
+ && (e->node->analyzed
+ || (e->node->same_body_alias && e->node->same_body->analyzed)));
- lto_symtab_maybe_init_hash_tables ();
- temp.base.node = id;
- slot = htab_find_slot (lto_symtab_identifiers, &temp,
- insert_p ? INSERT : NO_INSERT);
- if (insert_p)
+ /* A variable should have a size. */
+ else if (TREE_CODE (e->decl) == VAR_DECL)
{
- if (*slot)
- return (lto_symtab_identifier_t) *slot;
- else
- {
- symtab_id = GGC_CNEW (struct lto_symtab_identifier_def);
- symtab_id->base.node = id;
- *slot = symtab_id;
- return symtab_id;
- }
+ if (!e->vnode)
+ return false;
+ if (e->vnode->finalized)
+ return true;
+ return e->vnode->alias && e->vnode->extra_name->finalized;
}
- else
- return slot ? (lto_symtab_identifier_t) *slot : NULL;
-}
-/* Return the DECL associated with an IDENTIFIER ID or return NULL_TREE
- if there is none. */
-
-static tree
-lto_symtab_get_identifier_decl (tree id)
-{
- lto_symtab_identifier_t symtab_id = lto_symtab_get_identifier (id, false);
- return symtab_id ? symtab_id->decl : NULL_TREE;
+ gcc_unreachable ();
}
-/* SET the associated DECL of an IDENTIFIER ID to be DECL. */
+/* Resolve the symbol with the candidates in the chain *SLOT and store
+ their resolutions. */
static void
-lto_symtab_set_identifier_decl (tree id, tree decl)
+lto_symtab_resolve_symbols (void **slot)
{
- lto_symtab_identifier_t symtab_id = lto_symtab_get_identifier (id, true);
- symtab_id->decl = decl;
-}
+ lto_symtab_entry_t e;
+ lto_symtab_entry_t prevailing = NULL;
-/* Common helper function for merging variable and function declarations.
- NEW_DECL is the newly found decl. RESOLUTION is the decl's resolution
- provided by the linker. */
+ /* 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);
+ }
-static void
-lto_symtab_merge_decl (tree new_decl,
- enum ld_plugin_symbol_resolution resolution,
- struct lto_file_decl_data *file_data)
-{
- tree old_decl;
- tree name;
- ld_plugin_symbol_resolution_t old_resolution;
+ e = (lto_symtab_entry_t) *slot;
- gcc_assert (TREE_CODE (new_decl) == VAR_DECL
- || TREE_CODE (new_decl) == FUNCTION_DECL);
+ /* If the chain is already resolved there is nothing else to do. */
+ if (e->resolution != LDPR_UNKNOWN)
+ return;
- gcc_assert (TREE_PUBLIC (new_decl));
+ /* Find the single non-replaceable prevailing symbol and
+ diagnose ODR violations. */
+ for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
+ {
+ if (!lto_symtab_resolve_can_prevail_p (e))
+ {
+ e->resolution = LDPR_RESOLVED_IR;
+ e->guessed = true;
+ continue;
+ }
- gcc_assert (DECL_LANG_SPECIFIC (new_decl) == NULL);
+ /* Set a default resolution - the final prevailing one will get
+ adjusted later. */
+ e->resolution = LDPR_PREEMPTED_IR;
+ e->guessed = true;
+ if (!lto_symtab_resolve_replaceable_p (e))
+ {
+ if (prevailing)
+ {
+ error_at (DECL_SOURCE_LOCATION (e->decl),
+ "%qD has already been defined", e->decl);
+ inform (DECL_SOURCE_LOCATION (prevailing->decl),
+ "previously defined here");
+ }
+ prevailing = e;
+ }
+ }
+ if (prevailing)
+ goto found;
- /* Check that declarations reaching this function do not have
- properties inconsistent with having external linkage. If any of
- these asertions fail, then the object file reader has failed to
- detect these cases and issue appropriate error messages. */
- if (TREE_CODE (new_decl) == VAR_DECL)
- gcc_assert (!(DECL_EXTERNAL (new_decl) && DECL_INITIAL (new_decl)));
+ /* Do a second round choosing one from the replaceable prevailing decls. */
+ for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
+ {
+ if (e->resolution != LDPR_PREEMPTED_IR)
+ continue;
- /* Remember the resolution of this symbol. */
- lto_symtab_set_resolution_and_file_data (new_decl, resolution, file_data);
+ /* Choose the first function that can prevail as prevailing. */
+ if (TREE_CODE (e->decl) == FUNCTION_DECL)
+ {
+ prevailing = e;
+ break;
+ }
- /* Ensure DECL_ASSEMBLER_NAME will not set assembler name. */
- gcc_assert (DECL_ASSEMBLER_NAME_SET_P (new_decl));
+ /* From variables that can prevail choose the largest one. */
+ if (!prevailing
+ || tree_int_cst_lt (DECL_SIZE (prevailing->decl),
+ DECL_SIZE (e->decl)))
+ prevailing = e;
+ }
+
+ if (!prevailing)
+ return;
- /* Retrieve the previous declaration. */
- name = DECL_ASSEMBLER_NAME (new_decl);
- old_decl = lto_symtab_get_identifier_decl (name);
+found:
+ /* 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;
+ prevailing->guessed = true;
+}
+
+/* Merge all decls in the symbol table chain to the prevailing decl and
+ issue diagnostics about type mismatches. */
+
+static void
+lto_symtab_merge_decls_2 (void **slot)
+{
+ lto_symtab_entry_t prevailing, e;
+ VEC(tree, heap) *mismatches = NULL;
+ unsigned i;
+ tree decl;
+ bool diagnosed_p = false;
+
+ /* Nothing to do for a single entry. */
+ prevailing = (lto_symtab_entry_t) *slot;
+ if (!prevailing->next)
+ return;
- /* If there was no previous declaration, then there is nothing to
- merge. */
- if (!old_decl)
+ /* Try to merge each entry with the prevailing one. */
+ for (e = prevailing->next; e; e = e->next)
{
- lto_symtab_set_identifier_decl (name, new_decl);
- VEC_safe_push (tree, gc, lto_global_var_decls, new_decl);
- return;
+ if (!lto_symtab_merge (prevailing, e))
+ VEC_safe_push (tree, heap, mismatches, e->decl);
}
+ if (VEC_empty (tree, mismatches))
+ return;
- /* Give ODR violation errors. */
- old_resolution = lto_symtab_get_resolution (old_decl);
- if (resolution == LDPR_PREVAILING_DEF
- || resolution == LDPR_PREVAILING_DEF_IRONLY)
+ /* Diagnose all mismatched re-declarations. */
+ FOR_EACH_VEC_ELT (tree, mismatches, i, decl)
{
- if ((old_resolution == LDPR_PREVAILING_DEF
- || old_resolution == LDPR_PREVAILING_DEF_IRONLY)
- && (old_resolution != resolution || flag_no_common))
+ 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);
+
+ else if ((DECL_USER_ALIGN (prevailing->decl) && DECL_USER_ALIGN (decl))
+ && DECL_ALIGN (prevailing->decl) < DECL_ALIGN (decl))
{
- error_at (DECL_SOURCE_LOCATION (new_decl),
- "%qD has already been defined", new_decl);
- inform (DECL_SOURCE_LOCATION (old_decl),
- "previously defined here");
- return;
+ diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0,
+ "alignment of %qD is bigger than "
+ "original declaration", decl);
}
}
+ if (diagnosed_p)
+ inform (DECL_SOURCE_LOCATION (prevailing->decl),
+ "previously declared here");
- /* The linker may ask us to combine two incompatible symbols.
- Find a decl we can merge with or chain it in the list of decls
- for that symbol. */
- while (old_decl
- && !lto_symtab_compatible (old_decl, new_decl))
- old_decl = (tree) DECL_LANG_SPECIFIC (old_decl);
- if (!old_decl)
+ VEC_free (tree, heap, mismatches);
+}
+
+/* Helper to process the decl chain for the symbol table entry *SLOT. */
+
+static int
+lto_symtab_merge_decls_1 (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+ lto_symtab_entry_t e, prevailing;
+ bool diagnosed_p = false;
+
+ /* Compute the symbol resolutions. This is a no-op when using the
+ linker plugin. */
+ lto_symtab_resolve_symbols (slot);
+
+ /* Find the prevailing decl. */
+ for (prevailing = (lto_symtab_entry_t) *slot;
+ prevailing
+ && prevailing->resolution != LDPR_PREVAILING_DEF_IRONLY
+ && prevailing->resolution != LDPR_PREVAILING_DEF;
+ prevailing = prevailing->next)
+ ;
+
+ /* Assert it's the only one. */
+ if (prevailing)
+ for (e = prevailing->next; e; e = e->next)
+ {
+ 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
+ cgraph or a varpool node. */
+ if (!prevailing)
{
- old_decl = lto_symtab_get_identifier_decl (name);
- while (DECL_LANG_SPECIFIC (old_decl) != NULL)
- old_decl = (tree) DECL_LANG_SPECIFIC (old_decl);
- DECL_LANG_SPECIFIC (old_decl) = (struct lang_decl *) new_decl;
- return;
+ prevailing = (lto_symtab_entry_t) *slot;
+ /* For functions choose one with a cgraph node. */
+ if (TREE_CODE (prevailing->decl) == FUNCTION_DECL)
+ while (!prevailing->node
+ && prevailing->next)
+ prevailing = prevailing->next;
+ /* 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)
+ {
+ 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;
+ }
}
- /* Merge decl state in both directions, we may still end up using
- the new decl. */
- TREE_ADDRESSABLE (old_decl) |= TREE_ADDRESSABLE (new_decl);
- TREE_ADDRESSABLE (new_decl) |= TREE_ADDRESSABLE (old_decl);
+ /* Move it first in the list. */
+ if ((lto_symtab_entry_t) *slot != prevailing)
+ {
+ for (e = (lto_symtab_entry_t) *slot; e->next != prevailing; e = e->next)
+ ;
+ e->next = prevailing->next;
+ prevailing->next = (lto_symtab_entry_t) *slot;
+ *slot = (void *) prevailing;
+ }
- gcc_assert (resolution != LDPR_UNKNOWN
- && resolution != LDPR_UNDEF
- && old_resolution != LDPR_UNKNOWN
- && old_resolution != LDPR_UNDEF);
+ /* Record the prevailing variable. */
+ if (TREE_CODE (prevailing->decl) == VAR_DECL)
+ VEC_safe_push (tree, gc, lto_global_var_decls, prevailing->decl);
- if (resolution == LDPR_PREVAILING_DEF
- || resolution == LDPR_PREVAILING_DEF_IRONLY)
+ /* Diagnose mismatched objects. */
+ for (e = prevailing->next; e; e = e->next)
{
- tree decl;
- gcc_assert (old_resolution == LDPR_PREEMPTED_IR
- || old_resolution == LDPR_RESOLVED_IR
- || (old_resolution == resolution && !flag_no_common));
- DECL_LANG_SPECIFIC (new_decl) = DECL_LANG_SPECIFIC (old_decl);
- DECL_LANG_SPECIFIC (old_decl) = NULL;
- decl = lto_symtab_get_identifier_decl (name);
- if (decl == old_decl)
+ if (TREE_CODE (prevailing->decl) == TREE_CODE (e->decl))
+ continue;
+
+ switch (TREE_CODE (prevailing->decl))
{
- lto_symtab_set_identifier_decl (name, new_decl);
- return;
+ case VAR_DECL:
+ gcc_assert (TREE_CODE (e->decl) == FUNCTION_DECL);
+ error_at (DECL_SOURCE_LOCATION (e->decl),
+ "variable %qD redeclared as function", prevailing->decl);
+ break;
+
+ case FUNCTION_DECL:
+ gcc_assert (TREE_CODE (e->decl) == VAR_DECL);
+ error_at (DECL_SOURCE_LOCATION (e->decl),
+ "function %qD redeclared as variable", prevailing->decl);
+ break;
+
+ default:
+ gcc_unreachable ();
}
- while ((tree) DECL_LANG_SPECIFIC (decl) != old_decl)
- decl = (tree) DECL_LANG_SPECIFIC (decl);
- DECL_LANG_SPECIFIC (decl) = (struct lang_decl *) new_decl;
- return;
- }
- if (resolution == LDPR_PREEMPTED_REG
- || resolution == LDPR_RESOLVED_EXEC
- || resolution == LDPR_RESOLVED_DYN)
- gcc_assert (old_resolution == LDPR_PREEMPTED_REG
- || old_resolution == LDPR_RESOLVED_EXEC
- || old_resolution == LDPR_RESOLVED_DYN);
-
- if (resolution == LDPR_PREEMPTED_IR
- || resolution == LDPR_RESOLVED_IR)
- gcc_assert (old_resolution == LDPR_PREVAILING_DEF
- || old_resolution == LDPR_PREVAILING_DEF_IRONLY
- || old_resolution == LDPR_PREEMPTED_IR
- || old_resolution == LDPR_RESOLVED_IR);
-
- return;
+ diagnosed_p = true;
+ }
+ if (diagnosed_p)
+ inform (DECL_SOURCE_LOCATION (prevailing->decl),
+ "previously declared here");
+
+ /* Register and adjust types of the entries. */
+ for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
+ TREE_TYPE (e->decl) = gimple_register_type (TREE_TYPE (e->decl));
+
+ /* Merge the chain to the single prevailing decl and diagnose
+ mismatches. */
+ lto_symtab_merge_decls_2 (slot);
+
+ /* Drop all but the prevailing decl from the symtab. */
+ if (TREE_CODE (prevailing->decl) != FUNCTION_DECL
+ && TREE_CODE (prevailing->decl) != VAR_DECL)
+ prevailing->next = NULL;
+
+ /* Store resolution decision into the callgraph.
+ In LTRANS don't overwrite information we stored into callgraph at
+ WPA stage.
+
+ Do not bother to store guessed decisions. Generic code knows how
+ to handle UNKNOWN relocation well.
+
+ The problem with storing guessed decision is whether to use
+ PREVAILING_DEF or PREVAILING_DEF_IRONLY. First one would disable
+ some whole program optimizations, while ther second would imply
+ to many whole program assumptions. */
+ if (prevailing->node && !flag_ltrans && !prevailing->guessed)
+ prevailing->node->resolution = prevailing->resolution;
+ else if (prevailing->vnode && !flag_ltrans && !prevailing->guessed)
+ prevailing->vnode->resolution = prevailing->resolution;
+ return 1;
}
-
-/* Merge the VAR_DECL NEW_VAR with resolution RESOLUTION with any previous
- declaration with the same name. */
+/* Resolve and merge all symbol table chains to a prevailing decl. */
void
-lto_symtab_merge_var (tree new_var, enum ld_plugin_symbol_resolution resolution)
+lto_symtab_merge_decls (void)
{
- lto_symtab_merge_decl (new_var, resolution, NULL);
+ lto_symtab_maybe_init_hash_table ();
+ htab_traverse (lto_symtab_identifiers, lto_symtab_merge_decls_1, NULL);
}
-/* Merge the FUNCTION_DECL NEW_FN with resolution RESOLUTION with any previous
- declaration with the same name. */
+/* 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_fn (tree new_fn, enum ld_plugin_symbol_resolution resolution,
- struct lto_file_decl_data *file_data)
+lto_symtab_merge_cgraph_nodes (void)
{
- lto_symtab_merge_decl (new_fn, resolution, file_data);
+ 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. */
tree
lto_symtab_prevailing_decl (tree decl)
{
- tree ret;
- gcc_assert (decl);
+ lto_symtab_entry_t ret;
/* Builtins and local symbols are their own prevailing decl. */
if (!TREE_PUBLIC (decl) || is_builtin_fn (decl))
gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
/* Walk through the list of candidates and return the one we merged to. */
- ret = lto_symtab_get_identifier_decl (DECL_ASSEMBLER_NAME (decl));
- if (!ret
- || DECL_LANG_SPECIFIC (ret) == NULL)
- return ret;
-
- /* If there are multiple decls to choose from find the one we merged
- with and return that. */
- while (ret)
- {
- if (gimple_types_compatible_p (TREE_TYPE (decl), TREE_TYPE (ret)))
- return ret;
-
- ret = (tree) DECL_LANG_SPECIFIC (ret);
- }
-
- gcc_unreachable ();
-}
-
-/* Return the hash table entry of DECL. */
-
-static struct lto_symtab_decl_def *
-lto_symtab_get_symtab_def (tree decl)
-{
- struct lto_symtab_decl_def temp, *symtab_decl;
- void **slot;
-
- gcc_assert (decl);
-
- lto_symtab_maybe_init_hash_tables ();
- temp.base.node = decl;
- slot = htab_find_slot (lto_symtab_decls, &temp, NO_INSERT);
- gcc_assert (slot && *slot);
- symtab_decl = (struct lto_symtab_decl_def*) *slot;
- return symtab_decl;
-}
-
-/* Return the resolution of DECL. */
-
-enum ld_plugin_symbol_resolution
-lto_symtab_get_resolution (tree decl)
-{
- gcc_assert (decl);
-
- if (!TREE_PUBLIC (decl) || is_builtin_fn (decl))
- return LDPR_PREVAILING_DEF_IRONLY;
-
- /* FIXME lto: There should be no DECL_ABSTRACT in the middle end. */
- if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
- return LDPR_PREVAILING_DEF_IRONLY;
-
- return lto_symtab_get_symtab_def (decl)->resolution;
-}
-
-/* Return the file of DECL. */
-
-struct lto_file_decl_data *
-lto_symtab_get_file_data (tree decl)
-{
- return lto_symtab_get_symtab_def (decl)->file_data;
-}
-
-/* Remove any storage used to store resolution of DECL. */
-
-void
-lto_symtab_clear_resolution (tree decl)
-{
- struct lto_symtab_decl_def temp;
- gcc_assert (decl);
-
- 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;
+ ret = lto_symtab_get (DECL_ASSEMBLER_NAME (decl));
+ if (!ret)
+ return NULL_TREE;
- lto_symtab_maybe_init_hash_tables ();
- temp.base.node = decl;
- htab_remove_elt (lto_symtab_decls, &temp);
+ return ret->decl;
}
#include "gt-lto-symtab.h"