/* LTO symbol table.
- Copyright 2009 Free Software Foundation, Inc.
+ Copyright 2009, 2010 Free Software Foundation, Inc.
Contributed by CodeSourcery, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
#include "tree.h"
#include "gimple.h"
-#include "ggc.h" /* lambda.h needs this */
-#include "lambda.h" /* gcd */
+#include "ggc.h"
#include "hashtab.h"
#include "plugin-api.h"
#include "lto-streamer.h"
/* 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
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
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 = ggc_alloc_cleared_lto_symtab_entry_def ();
+ new_entry->id = (*targetm.asm_out.mangle_assembler_name)
+ (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
new_entry->decl = decl;
new_entry->resolution = resolution;
new_entry->file_data = file_data;
gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
- e = lto_symtab_get (DECL_ASSEMBLER_NAME (decl));
+ e = lto_symtab_get ((*targetm.asm_out.mangle_assembler_name)
+ (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))));
while (e && e->decl != decl)
e = e->next;
if (!e)
struct cgraph_node *prevailing_node)
{
struct cgraph_edge *e, *next;
+ bool compatible_p;
+
+ 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 ((*targetm.asm_out.mangle_assembler_name)
+ (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl)))));
+ }
/* Merge node flags. */
if (node->needed)
}
/* Redirect all incoming edges. */
+ compatible_p
+ = types_compatible_p (TREE_TYPE (TREE_TYPE (prevailing_node->decl)),
+ TREE_TYPE (TREE_TYPE (node->decl)));
for (e = node->callers; e; e = next)
{
next = e->next_caller;
cgraph_redirect_edge_callee (e, prevailing_node);
+ /* If there is a mismatch between the supposed callee return type and
+ the real one do not attempt to inline this function.
+ ??? We really need a way to match function signatures for ABI
+ compatibility and perform related promotions at inlining time. */
+ if (!compatible_p)
+ e->call_stmt_cannot_inline_p = 1;
}
/* Redirect incomming references. */
ipa_clone_refering (prevailing_node, NULL, &node->ref_list);
- 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);
}
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);
}
if (TREE_CODE (decl) == FUNCTION_DECL)
{
- if (TREE_TYPE (prevailing_decl) != TREE_TYPE (decl))
+ if (!types_compatible_p (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
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 (prevailing_type != type)
+ if (!types_compatible_p (prevailing_type, type))
{
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 (!types_compatible_p (tem1, tem2))
return false;
}
{
if (DECL_EXTERNAL (e->decl)
|| DECL_COMDAT (e->decl)
+ || DECL_ONE_ONLY (e->decl)
|| DECL_WEAK (e->decl))
return true;
if (TREE_CODE (e->decl) == FUNCTION_DECL)
return (e->node && e->node->analyzed);
- /* A variable should have a size. */
else if (TREE_CODE (e->decl) == VAR_DECL)
{
if (!e->vnode)
return false;
- if (e->vnode->finalized)
- return true;
- return e->vnode->alias && e->vnode->extra_name->finalized;
+ return e->vnode->finalized;
}
gcc_unreachable ();
e->node = cgraph_get_node (e->decl);
else if (TREE_CODE (e->decl) == VAR_DECL)
e->vnode = varpool_get_node (e->decl);
+ if (e->resolution == LDPR_PREVAILING_DEF_IRONLY
+ || e->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP
+ || e->resolution == LDPR_PREVAILING_DEF)
+ prevailing = e;
}
- e = (lto_symtab_entry_t) *slot;
-
/* If the chain is already resolved there is nothing else to do. */
- if (e->resolution != LDPR_UNKNOWN)
+ if (prevailing)
return;
/* Find the single non-replaceable prevailing symbol and
if (!lto_symtab_resolve_can_prevail_p (e))
{
e->resolution = LDPR_RESOLVED_IR;
+ e->guessed = true;
continue;
}
/* 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)
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;
+ prevailing->guessed = true;
}
/* Merge all decls in the symbol table chain to the prevailing decl and
- issue diagnostics about type mismatches. */
+ issue diagnostics about type mismatches. If DIAGNOSED_P is true
+ do not issue further diagnostics.*/
static void
-lto_symtab_merge_decls_2 (void **slot)
+lto_symtab_merge_decls_2 (void **slot, bool diagnosed_p)
{
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;
/* Try to merge each entry with the prevailing one. */
for (e = prevailing->next; e; e = e->next)
{
- if (!lto_symtab_merge (prevailing, e))
+ if (!lto_symtab_merge (prevailing, e)
+ && !diagnosed_p)
VEC_safe_push (tree, heap, mismatches, e->decl);
}
if (VEC_empty (tree, mismatches))
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 (!types_compatible_p (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);
for (prevailing = (lto_symtab_entry_t) *slot;
prevailing
&& prevailing->resolution != LDPR_PREVAILING_DEF_IRONLY
+ && prevailing->resolution != LDPR_PREVAILING_DEF_IRONLY_EXP
&& prevailing->resolution != LDPR_PREVAILING_DEF;
prevailing = prevailing->next)
;
/* 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_IRONLY_EXP
+ || 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
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;
-
+ lto_symtab_merge_decls_2 (slot, diagnosed_p);
+
+ /* 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, PREVAILING_DEF_IRONLY, PREVAILING_DEF_IRONLY_EXP.
+ 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;
}
{
if (e->node != NULL)
{
- if (e->node->decl != e->decl && e->node->same_body)
+ /* In case we prevail funcion by an alias, we can run into case
+ that the alias has no cgraph node attached, since it was
+ previously unused. Create the node. */
+ if (!prevailing->node)
{
- 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;
- }
+ prevailing->node = cgraph_create_node (prevailing->decl);
+ prevailing->node->alias = true;
}
lto_cgraph_replace_node (e->node, prevailing->node);
}
if (e->vnode != NULL)
- lto_varpool_replace_node (e->vnode, prevailing->vnode);
+ {
+ if (!prevailing->vnode)
+ {
+ prevailing->vnode = varpool_node (prevailing->decl);
+ prevailing->vnode->alias = true;
+ }
+ lto_varpool_replace_node (e->vnode, prevailing->vnode);
+ }
}
/* Drop all but the prevailing decl from the symtab. */
void
lto_symtab_merge_cgraph_nodes (void)
{
+ struct cgraph_node *node;
+ struct varpool_node *vnode;
lto_symtab_maybe_init_hash_table ();
htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL);
+
+ for (node = cgraph_nodes; node; node = node->next)
+ if ((node->thunk.thunk_p || node->alias)
+ && node->thunk.alias)
+ node->thunk.alias = lto_symtab_prevailing_decl (node->thunk.alias);
+ for (vnode = varpool_nodes; vnode; vnode = vnode->next)
+ if (vnode->alias_of)
+ vnode->alias_of = lto_symtab_prevailing_decl (vnode->alias_of);
}
/* Given the decl DECL, return the prevailing decl with the same 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));
+ ret = lto_symtab_get ((*targetm.asm_out.mangle_assembler_name)
+ (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))));
if (!ret)
return NULL_TREE;