/* LTO symbol table.
- Copyright 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2009-2013 Free Software Foundation, Inc.
Contributed by CodeSourcery, Inc.
This file is part of GCC.
#include "lto-streamer.h"
/* Vector to keep track of external variables we've seen so far. */
-VEC(tree,gc) *lto_global_var_decls;
-
-/* 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)
-{
- symtab_node node;
-
- /* 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));
-
- node = symtab_get_node (decl);
- if (node)
- {
- node->symbol.resolution = resolution;
- gcc_assert (node->symbol.lto_file_data == file_data);
- }
-}
+vec<tree, va_gc> *lto_global_var_decls;
/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
all edges and removing the old node. */
{
fprintf (cgraph_dump_file, "Replacing cgraph node %s/%i by %s/%i"
" for symbol %s\n",
- xstrdup (cgraph_node_name (node)), node->uid,
- xstrdup (cgraph_node_name (prevailing_node)),
- prevailing_node->uid,
+ cgraph_node_name (node), node->symbol.order,
+ cgraph_node_name (prevailing_node),
+ prevailing_node->symbol.order,
IDENTIFIER_POINTER ((*targetm.asm_out.mangle_assembler_name)
(IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->symbol.decl)))));
}
lto_varpool_replace_node (struct varpool_node *vnode,
struct varpool_node *prevailing_node)
{
- gcc_assert (!vnode->finalized || prevailing_node->finalized);
- gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
+ gcc_assert (!vnode->symbol.definition || prevailing_node->symbol.definition);
+ gcc_assert (!vnode->symbol.analyzed || prevailing_node->symbol.analyzed);
ipa_clone_referring ((symtab_node)prevailing_node, &vnode->symbol.ref_list);
/* Be sure we can garbage collect the initializer. */
- if (DECL_INITIAL (vnode->symbol.decl))
+ if (DECL_INITIAL (vnode->symbol.decl)
+ && vnode->symbol.decl != prevailing_node->symbol.decl)
DECL_INITIAL (vnode->symbol.decl) = error_mark_node;
/* Finally remove the replaced node. */
varpool_remove_node (vnode);
return false;
}
+/* Return true, if the symbol E should be resolved by lto-symtab.
+ Those are all external symbols and all real symbols that are not static (we
+ handle renaming of static later in partitioning). */
+
+static bool
+lto_symtab_symbol_p (symtab_node e)
+{
+ if (!TREE_PUBLIC (e->symbol.decl) && !DECL_EXTERNAL (e->symbol.decl))
+ return false;
+ return symtab_real_symbol_p (e);
+}
+
/* Return true if the symtab entry E can be the prevailing one. */
static bool
lto_symtab_resolve_can_prevail_p (symtab_node e)
{
- if (!symtab_real_symbol_p (e))
+ if (!lto_symtab_symbol_p (e))
return false;
/* The C++ frontend ends up neither setting TREE_STATIC nor
if (DECL_EXTERNAL (e->symbol.decl))
return false;
- /* For functions we need a non-discarded body. */
- if (TREE_CODE (e->symbol.decl) == FUNCTION_DECL)
- return (cgraph (e)->analyzed);
-
- else if (TREE_CODE (e->symbol.decl) == VAR_DECL)
- return varpool (e)->finalized;
-
- gcc_unreachable ();
+ return e->symbol.definition;
}
/* Resolve the symbol with the candidates in the chain *SLOT and store
/* Always set e->node so that edges are updated to reflect decl merging. */
for (e = first; e; e = e->symbol.next_sharing_asm_name)
- if (symtab_real_symbol_p (e)
+ if (lto_symtab_symbol_p (e)
&& (e->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY
|| e->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY_EXP
|| e->symbol.resolution == LDPR_PREVAILING_DEF))
{
/* Assert it's the only one. */
for (e = prevailing->symbol.next_sharing_asm_name; e; e = e->symbol.next_sharing_asm_name)
- if (symtab_real_symbol_p (e)
+ if (lto_symtab_symbol_p (e)
&& (e->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY
|| e->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY_EXP
|| e->symbol.resolution == LDPR_PREVAILING_DEF))
/* Do a second round choosing one from the replaceable prevailing decls. */
for (e = first; e; e = e->symbol.next_sharing_asm_name)
{
- if (!lto_symtab_resolve_can_prevail_p (e)
- || !symtab_real_symbol_p (e))
+ if (!lto_symtab_resolve_can_prevail_p (e))
continue;
/* Choose the first function that can prevail as prevailing. */
lto_symtab_merge_decls_2 (symtab_node first, bool diagnosed_p)
{
symtab_node prevailing, e;
- VEC(tree, heap) *mismatches = NULL;
+ vec<tree> mismatches = vNULL;
unsigned i;
tree decl;
/* Try to merge each entry with the prevailing one. */
for (e = prevailing->symbol.next_sharing_asm_name;
e; e = e->symbol.next_sharing_asm_name)
- {
- if (!lto_symtab_merge (prevailing, e)
- && !diagnosed_p)
- VEC_safe_push (tree, heap, mismatches, e->symbol.decl);
- }
- if (VEC_empty (tree, mismatches))
+ if (TREE_PUBLIC (e->symbol.decl))
+ {
+ if (!lto_symtab_merge (prevailing, e)
+ && !diagnosed_p)
+ mismatches.safe_push (e->symbol.decl);
+ }
+ if (mismatches.is_empty ())
return;
/* Diagnose all mismatched re-declarations. */
- FOR_EACH_VEC_ELT (tree, mismatches, i, decl)
+ FOR_EACH_VEC_ELT (mismatches, i, decl)
{
if (!types_compatible_p (TREE_TYPE (prevailing->symbol.decl),
TREE_TYPE (decl)))
inform (DECL_SOURCE_LOCATION (prevailing->symbol.decl),
"previously declared here");
- VEC_free (tree, heap, mismatches);
+ mismatches.release ();
}
/* Helper to process the decl chain for the symbol table entry *SLOT. */
fprintf (cgraph_dump_file, "Merging nodes for %s. Candidates:\n",
symtab_node_asm_name (first));
for (e = first; e; e = e->symbol.next_sharing_asm_name)
- dump_symtab_node (cgraph_dump_file, e);
+ if (TREE_PUBLIC (e->symbol.decl))
+ dump_symtab_node (cgraph_dump_file, e);
}
/* Compute the symbol resolutions. This is a no-op when using the
for (e = prevailing->symbol.next_sharing_asm_name;
e; e = e->symbol.next_sharing_asm_name)
if (!COMPLETE_TYPE_P (TREE_TYPE (prevailing->symbol.decl))
- && COMPLETE_TYPE_P (TREE_TYPE (e->symbol.decl)))
+ && COMPLETE_TYPE_P (TREE_TYPE (e->symbol.decl))
+ && lto_symtab_symbol_p (e))
prevailing = e;
}
+ /* For variables prefer the non-builtin if one is available. */
+ else if (TREE_CODE (prevailing->symbol.decl) == FUNCTION_DECL)
+ {
+ for (e = first; e; e = e->symbol.next_sharing_asm_name)
+ if (TREE_CODE (e->symbol.decl) == FUNCTION_DECL
+ && !DECL_BUILT_IN (e->symbol.decl)
+ && lto_symtab_symbol_p (e))
+ {
+ prevailing = e;
+ break;
+ }
+ }
}
symtab_prevail_in_asm_name_hash (prevailing);
- /* Record the prevailing variable. */
- if (TREE_CODE (prevailing->symbol.decl) == VAR_DECL)
- VEC_safe_push (tree, gc, lto_global_var_decls,
- prevailing->symbol.decl);
-
/* Diagnose mismatched objects. */
for (e = prevailing->symbol.next_sharing_asm_name;
e; e = e->symbol.next_sharing_asm_name)
if (TREE_CODE (prevailing->symbol.decl)
== TREE_CODE (e->symbol.decl))
continue;
+ if (!lto_symtab_symbol_p (e))
+ continue;
switch (TREE_CODE (prevailing->symbol.decl))
{
{
symtab_node node;
- /* In ltrans mode we read merged cgraph, we do not really need to care
- about resolving symbols again, we only need to replace duplicated declarations
- read from the callgraph and from function sections. */
- if (flag_ltrans)
- return;
-
/* Populate assembler name hash. */
symtab_initialize_asm_name_hash ();
FOR_EACH_SYMBOL (node)
- if (TREE_PUBLIC (node->symbol.decl)
- && node->symbol.next_sharing_asm_name
- && !node->symbol.previous_sharing_asm_name)
- lto_symtab_merge_decls_1 (node);
+ if (!node->symbol.previous_sharing_asm_name
+ && node->symbol.next_sharing_asm_name)
+ lto_symtab_merge_decls_1 (node);
}
/* Helper to process the decl chain for the symbol table entry *SLOT. */
static void
-lto_symtab_merge_cgraph_nodes_1 (symtab_node prevailing)
+lto_symtab_merge_symbols_1 (symtab_node prevailing)
{
symtab_node e, next;
{
next = e->symbol.next_sharing_asm_name;
- if (!symtab_real_symbol_p (e))
+ if (!lto_symtab_symbol_p (e))
continue;
- if (symtab_function_p (e)
- && !DECL_BUILT_IN (e->symbol.decl))
- lto_cgraph_replace_node (cgraph (e), cgraph (prevailing));
- if (symtab_variable_p (e))
- lto_varpool_replace_node (varpool (e), varpool (prevailing));
+ cgraph_node *ce = dyn_cast <cgraph_node> (e);
+ if (ce && !DECL_BUILT_IN (e->symbol.decl))
+ lto_cgraph_replace_node (ce, cgraph (prevailing));
+ if (varpool_node *ve = dyn_cast <varpool_node> (e))
+ lto_varpool_replace_node (ve, varpool (prevailing));
}
return;
lto_symtab_merge_decls. */
void
-lto_symtab_merge_cgraph_nodes (void)
+lto_symtab_merge_symbols (void)
{
- struct cgraph_node *cnode;
- struct varpool_node *vnode;
symtab_node node;
- /* Populate assembler name hash. */
- symtab_initialize_asm_name_hash ();
-
if (!flag_ltrans)
- FOR_EACH_SYMBOL (node)
- if (TREE_PUBLIC (node->symbol.decl)
- && node->symbol.next_sharing_asm_name
- && !node->symbol.previous_sharing_asm_name)
- lto_symtab_merge_cgraph_nodes_1 (node);
-
- FOR_EACH_FUNCTION (cnode)
- {
- if ((cnode->thunk.thunk_p || cnode->alias)
- && cnode->thunk.alias)
- cnode->thunk.alias = lto_symtab_prevailing_decl (cnode->thunk.alias);
- cnode->symbol.aux = NULL;
- }
- FOR_EACH_VARIABLE (vnode)
{
- if (vnode->alias_of)
- vnode->alias_of = lto_symtab_prevailing_decl (vnode->alias_of);
- vnode->symbol.aux = NULL;
+ symtab_initialize_asm_name_hash ();
+
+ /* Do the actual merging.
+ At this point we invalidate hash translating decls into symtab nodes
+ because after removing one of duplicate decls the hash is not correcly
+ updated to the ohter dupliate. */
+ FOR_EACH_SYMBOL (node)
+ if (lto_symtab_symbol_p (node)
+ && node->symbol.next_sharing_asm_name
+ && !node->symbol.previous_sharing_asm_name)
+ lto_symtab_merge_symbols_1 (node);
+
+ /* Resolve weakref aliases whose target are now in the compilation unit.
+ also re-populate the hash translating decls into symtab nodes*/
+ FOR_EACH_SYMBOL (node)
+ {
+ cgraph_node *cnode, *cnode2;
+ if (!node->symbol.analyzed && node->symbol.alias_target)
+ {
+ symtab_node tgt = symtab_node_for_asm (node->symbol.alias_target);
+ gcc_assert (node->symbol.weakref);
+ if (tgt)
+ symtab_resolve_alias (node, tgt);
+ }
+ node->symbol.aux = NULL;
+
+ if (!(cnode = dyn_cast <cgraph_node> (node))
+ || !cnode->clone_of
+ || cnode->clone_of->symbol.decl != cnode->symbol.decl)
+ {
+ if (cnode && DECL_BUILT_IN (node->symbol.decl)
+ && (cnode2 = cgraph_get_node (node->symbol.decl))
+ && cnode2 != cnode)
+ lto_cgraph_replace_node (cnode2, cnode);
+ symtab_insert_node_to_hashtable ((symtab_node)node);
+ }
+ }
}
}
symtab_node ret;
/* Builtins and local symbols are their own prevailing decl. */
- if (!TREE_PUBLIC (decl) || is_builtin_fn (decl))
+ if ((!TREE_PUBLIC (decl) && !DECL_EXTERNAL (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;
+ /* Likewise builtins are their own prevailing decl. This preserves
+ non-builtin vs. builtin uses from compile-time. */
+ if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl))
+ return decl;
+
/* Ensure DECL_ASSEMBLER_NAME will not set assembler name. */
gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));