summaryrefslogtreecommitdiff
path: root/gcc/lto-symtab.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/lto-symtab.c')
-rw-r--r--gcc/lto-symtab.c754
1 files changed, 754 insertions, 0 deletions
diff --git a/gcc/lto-symtab.c b/gcc/lto-symtab.c
new file mode 100644
index 00000000000..2a0783a12be
--- /dev/null
+++ b/gcc/lto-symtab.c
@@ -0,0 +1,754 @@
+/* LTO symbol table.
+ Copyright 2009 Free Software Foundation, Inc.
+ Contributed by CodeSourcery, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "toplev.h"
+#include "tree.h"
+#include "gimple.h"
+#include "ggc.h" /* lambda.h needs this */
+#include "lambda.h" /* gcd */
+#include "hashtab.h"
+#include "plugin-api.h"
+#include "lto-streamer.h"
+
+/* Vector to keep track of external variables we've seen so far. */
+VEC(tree,gc) *lto_global_var_decls;
+
+/* Symbol table entry. */
+
+struct GTY(()) lto_symtab_entry_def
+{
+ /* The symbol table entry key, an IDENTIFIER. */
+ tree id;
+ /* The symbol table entry, a DECL. */
+ tree decl;
+ /* LTO file-data and symbol resolution for this decl. */
+ struct lto_file_decl_data * GTY((skip (""))) file_data;
+ enum ld_plugin_symbol_resolution resolution;
+ /* 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_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_entry_marked_p"),
+ param_is (struct lto_symtab_entry_def)))
+ htab_t lto_symtab_identifiers;
+
+/* Return the hash value of an lto_symtab_entry_t object pointed to by P. */
+
+static hashval_t
+lto_symtab_entry_hash (const void *p)
+{
+ const struct lto_symtab_entry_def *base =
+ (const struct lto_symtab_entry_def *) p;
+ return htab_hash_string (IDENTIFIER_POINTER (base->id));
+}
+
+/* Return non-zero if P1 and P2 points to lto_symtab_entry_def structs
+ corresponding to the same symbol. */
+
+static int
+lto_symtab_entry_eq (const void *p1, const void *p2)
+{
+ 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_entry_def struct that needs
+ 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)));
+}
+
+/* Lazily initialize resolution hash tables. */
+
+static void
+lto_symtab_maybe_init_hash_table (void)
+{
+ if (lto_symtab_identifiers)
+ return;
+
+ lto_symtab_identifiers =
+ htab_create_ggc (1021, lto_symtab_entry_hash,
+ lto_symtab_entry_eq, NULL);
+}
+
+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;
+}
+
+/* Check if OLD_DECL and NEW_DECL are compatible. */
+
+static bool
+lto_symtab_compatible (tree old_decl, tree new_decl)
+{
+ tree old_type, new_type;
+
+ if (TREE_CODE (old_decl) != TREE_CODE (new_decl))
+ {
+ 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;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ if (TREE_CODE (new_decl) == FUNCTION_DECL)
+ {
+ if (!gimple_types_compatible_p (TREE_TYPE (old_decl),
+ TREE_TYPE (new_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
+ 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;
+ }
+
+ /* 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. */
+ old_type = TREE_TYPE (old_decl);
+ 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);
+ }
+ }
+ }
+
+ /* We can tolerate differences in type qualification, the
+ qualification of the prevailing definition will prevail. */
+ old_type = TYPE_MAIN_VARIANT (TREE_TYPE (old_decl));
+ new_type = TYPE_MAIN_VARIANT (TREE_TYPE (new_decl));
+ if (!gimple_types_compatible_p (old_type, new_type))
+ {
+ 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;
+ }
+
+ /* ??? We might want to emit a warning here if type qualification
+ differences were spotted. Do not do this unconditionally though. */
+
+ /* 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. */
+
+ /* 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 (old_decl) && DECL_USER_ALIGN (new_decl))
+ && DECL_ALIGN (old_decl) != DECL_ALIGN (new_decl))
+ {
+ warning_at (DECL_SOURCE_LOCATION (new_decl), 0,
+ "alignment of %qD does not match original declaration",
+ new_decl);
+ inform (DECL_SOURCE_LOCATION (old_decl), "previously declared here");
+ return false;
+ }
+
+ return true;
+}
+
+/* Registers DECL with the LTO symbol table as having resolution RESOLUTION
+ and read from FILE_DATA. */
+
+void
+lto_symtab_register_decl (tree decl,
+ ld_plugin_symbol_resolution_t resolution,
+ struct lto_file_decl_data *file_data)
+{
+ lto_symtab_entry_t new_entry;
+ void **slot;
+
+ /* 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_CNEW (struct 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;
+
+ 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;
+}
+
+/* Get the lto_symtab_entry_def struct associated with ID
+ if there is one. */
+
+static lto_symtab_entry_t
+lto_symtab_get (tree id)
+{
+ struct lto_symtab_entry_def temp;
+ void **slot;
+
+ 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;
+}
+
+/* Get the linker resolution for DECL. */
+
+enum ld_plugin_symbol_resolution
+lto_symtab_get_resolution (tree decl)
+{
+ lto_symtab_entry_t e;
+
+ gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
+
+ e = lto_symtab_get (DECL_ASSEMBLER_NAME (decl));
+ while (e && e->decl != decl)
+ e = e->next;
+ if (!e)
+ return LDPR_UNKNOWN;
+
+ return e->resolution;
+}
+
+/* Replace the cgraph node OLD_NODE with NEW_NODE in the cgraph, merging
+ all edges and removing the old node. */
+
+static void
+lto_cgraph_replace_node (struct cgraph_node *old_node,
+ struct cgraph_node *new_node)
+{
+ struct cgraph_edge *e, *next;
+
+ /* Merge node flags. */
+ if (old_node->needed)
+ cgraph_mark_needed_node (new_node);
+ if (old_node->reachable)
+ cgraph_mark_reachable_node (new_node);
+ if (old_node->address_taken)
+ {
+ gcc_assert (!new_node->global.inlined_to);
+ cgraph_mark_address_taken_node (new_node);
+ }
+
+ /* Redirect all incoming edges. */
+ for (e = old_node->callers; e; e = next)
+ {
+ next = e->next_caller;
+ cgraph_redirect_edge_callee (e, new_node);
+ }
+
+ /* 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 now do what the old code did. Do not create edges for them. */
+ for (e = old_node->callees; e; e = next)
+ {
+ next = e->next_callee;
+ cgraph_remove_edge (e);
+ }
+
+ /* Finally remove the replaced node. */
+ cgraph_remove_node (old_node);
+}
+
+/* Merge two variable or function symbol table entries ENTRY1 and ENTRY2.
+ Return the prevailing one or NULL if a merge is not possible. */
+
+static lto_symtab_entry_t
+lto_symtab_merge (lto_symtab_entry_t entry1, lto_symtab_entry_t entry2)
+{
+ tree old_decl = entry1->decl;
+ tree new_decl = entry2->decl;
+ ld_plugin_symbol_resolution_t old_resolution = entry1->resolution;
+ ld_plugin_symbol_resolution_t new_resolution = entry2->resolution;
+ struct cgraph_node *old_node = NULL;
+ struct cgraph_node *new_node = NULL;
+
+ /* Give ODR violation errors. */
+ if (new_resolution == LDPR_PREVAILING_DEF
+ || new_resolution == LDPR_PREVAILING_DEF_IRONLY)
+ {
+ if ((old_resolution == LDPR_PREVAILING_DEF
+ || old_resolution == LDPR_PREVAILING_DEF_IRONLY)
+ && (old_resolution != new_resolution || flag_no_common))
+ {
+ error_at (DECL_SOURCE_LOCATION (new_decl),
+ "%qD has already been defined", new_decl);
+ inform (DECL_SOURCE_LOCATION (old_decl),
+ "previously defined here");
+ return NULL;
+ }
+ }
+
+ /* The linker may ask us to combine two incompatible symbols. */
+ if (!lto_symtab_compatible (old_decl, new_decl))
+ return NULL;
+
+ if (TREE_CODE (old_decl) == FUNCTION_DECL)
+ old_node = cgraph_get_node (old_decl);
+ if (TREE_CODE (new_decl) == FUNCTION_DECL)
+ new_node = cgraph_get_node (new_decl);
+
+ /* 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);
+
+ gcc_assert (new_resolution != LDPR_UNKNOWN
+ && new_resolution != LDPR_UNDEF
+ && old_resolution != LDPR_UNKNOWN
+ && old_resolution != LDPR_UNDEF);
+
+ if (new_resolution == LDPR_PREVAILING_DEF
+ || new_resolution == LDPR_PREVAILING_DEF_IRONLY
+ || (!old_node && new_node))
+ {
+ gcc_assert ((!old_node && new_node)
+ || old_resolution == LDPR_PREEMPTED_IR
+ || old_resolution == LDPR_RESOLVED_IR
+ || (old_resolution == new_resolution && !flag_no_common));
+ if (old_node)
+ lto_cgraph_replace_node (old_node, new_node);
+ /* Choose new_decl, entry2. */
+ return entry2;
+ }
+
+ if (new_resolution == LDPR_PREEMPTED_REG
+ || new_resolution == LDPR_RESOLVED_EXEC
+ || new_resolution == LDPR_RESOLVED_DYN)
+ gcc_assert (old_resolution == LDPR_PREEMPTED_REG
+ || old_resolution == LDPR_RESOLVED_EXEC
+ || old_resolution == LDPR_RESOLVED_DYN);
+
+ if (new_resolution == LDPR_PREEMPTED_IR
+ || new_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);
+
+ if (new_node)
+ lto_cgraph_replace_node (new_node, old_node);
+
+ /* Choose old_decl, entry1. */
+ return entry1;
+}
+
+/* Resolve the symbol with the candidates in the chain *SLOT and store
+ their resolutions. */
+
+static void
+lto_symtab_resolve_symbols (void **slot)
+{
+ lto_symtab_entry_t e = (lto_symtab_entry_t) *slot;
+
+ /* If the chain is already resolved there is nothing to do. */
+ if (e->resolution != LDPR_UNKNOWN)
+ return;
+
+ /* This is a poor mans resolver. */
+ for (; e; e = e->next)
+ {
+ gcc_assert (e->resolution == LDPR_UNKNOWN);
+ if (DECL_EXTERNAL (e->decl)
+ || (TREE_CODE (e->decl) == FUNCTION_DECL
+ && !cgraph_get_node (e->decl)))
+ e->resolution = LDPR_RESOLVED_IR;
+ else
+ {
+ if (TREE_READONLY (e->decl))
+ e->resolution = LDPR_PREVAILING_DEF_IRONLY;
+ else
+ e->resolution = LDPR_PREVAILING_DEF;
+ }
+ }
+}
+
+/* Merge one symbol table chain to a (set of) prevailing decls. */
+
+static void
+lto_symtab_merge_decls_2 (void **slot)
+{
+ lto_symtab_entry_t e2, e1;
+
+ /* Nothing to do for a single entry. */
+ e1 = (lto_symtab_entry_t) *slot;
+ if (!e1->next)
+ return;
+
+ /* Try to merge each entry with each other entry. In case of a
+ single prevailing decl this is linear. */
+restart:
+ for (; e1; e1 = e1->next)
+ for (e2 = e1->next; e2; e2 = e2->next)
+ {
+ lto_symtab_entry_t prevailing = lto_symtab_merge (e1, e2);
+ if (prevailing == e1)
+ {
+ lto_symtab_entry_t tmp = prevailing;
+ while (tmp->next != e2)
+ tmp = tmp->next;
+ tmp->next = e2->next;
+ e2->next = NULL;
+ e2 = tmp;
+ }
+ else if (prevailing == e2)
+ {
+ lto_symtab_entry_t tmp = (lto_symtab_entry_t) *slot;
+ if (tmp == e1)
+ {
+ *slot = e1->next;
+ tmp = e1->next;
+ }
+ else
+ {
+ while (tmp->next != e1)
+ tmp = tmp->next;
+ tmp->next = e1->next;
+ }
+ e1->next = NULL;
+ e1 = tmp;
+ goto restart;
+ }
+ }
+}
+
+/* Fixup the chain of prevailing variable decls *SLOT that are commonized
+ during link-time. */
+
+static void
+lto_symtab_fixup_var_decls (void **slot)
+{
+ lto_symtab_entry_t e = (lto_symtab_entry_t) *slot;
+ tree size = bitsize_zero_node;
+
+ /* Find the largest prevailing decl and move it to the front of the chain.
+ This is the decl we will output as representative for the common
+ section. */
+ size = bitsize_zero_node;
+ if (e->resolution == LDPR_PREVAILING_DEF_IRONLY
+ || e->resolution == LDPR_PREVAILING_DEF)
+ size = DECL_SIZE (e->decl);
+ for (; e->next;)
+ {
+ lto_symtab_entry_t next = e->next;
+ if ((next->resolution == LDPR_PREVAILING_DEF_IRONLY
+ || next->resolution == LDPR_PREVAILING_DEF)
+ && tree_int_cst_lt (size, DECL_SIZE (next->decl)))
+ {
+ size = DECL_SIZE (next->decl);
+ e->next = next->next;
+ next->next = (lto_symtab_entry_t) *slot;
+ *slot = next;
+ }
+ else
+ e = next;
+ }
+
+ /* Mark everything apart from the first var as written out. */
+ e = (lto_symtab_entry_t) *slot;
+ for (e = e->next; e; e = e->next)
+ TREE_ASM_WRITTEN (e->decl) = true;
+}
+
+/* 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;
+
+ /* Compute the symbol resolutions. */
+ lto_symtab_resolve_symbols (slot);
+
+ /* 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 a (hopefully) single prevailing decl. */
+ lto_symtab_merge_decls_2 (slot);
+
+ /* ??? Ideally we should delay all diagnostics until this point to
+ avoid duplicates. */
+
+ /* All done for FUNCTION_DECLs. */
+ e = (lto_symtab_entry_t) *slot;
+ if (TREE_CODE (e->decl) == FUNCTION_DECL)
+ return 1;
+
+ /* Fixup variables in case there are multiple prevailing ones. */
+ if (e->next)
+ lto_symtab_fixup_var_decls (slot);
+
+ /* Insert all variable decls into the global variable decl vector. */
+ for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
+ VEC_safe_push (tree, gc, lto_global_var_decls, e->decl);
+
+ return 1;
+}
+
+/* Resolve and merge all symbol table chains to a prevailing decl. */
+
+void
+lto_symtab_merge_decls (void)
+{
+ lto_symtab_maybe_init_hash_table ();
+ htab_traverse (lto_symtab_identifiers, lto_symtab_merge_decls_1, NULL);
+}
+
+
+/* Given the decl DECL, return the prevailing decl with the same name. */
+
+tree
+lto_symtab_prevailing_decl (tree decl)
+{
+ lto_symtab_entry_t ret;
+
+ /* Builtins and local symbols are their own prevailing decl. */
+ if (!TREE_PUBLIC (decl) || is_builtin_fn (decl))
+ return decl;
+
+ /* DECL_ABSTRACTs are their own prevailng decl. */
+ if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
+ return decl;
+
+ /* Ensure DECL_ASSEMBLER_NAME will not set assembler name. */
+ 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 (DECL_ASSEMBLER_NAME (decl));
+ if (!ret)
+ return NULL_TREE;
+
+ /* If there is only one candidate return it. */
+ if (ret->next == NULL)
+ return ret->decl;
+
+ /* 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->decl)))
+ return ret->decl;
+
+ ret = ret->next;
+ }
+
+ gcc_unreachable ();
+}
+
+/* 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"