mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-23 21:31:54 +08:00
lto-symtab.c (lto_symtab_compatible): Fold in ...
2009-10-14 Richard Guenther <rguenther@suse.de> * lto-symtab.c (lto_symtab_compatible): Fold in ... (lto_symtab_merge): ... here. Rewrite both to take the prevailing and a to-be-merged entry and to queue diagnostics properly. (lto_symtab_resolve_replaceable_p): New predicate for symbol resolution. (lto_symtab_resolve_can_prevail_p): Likewise. (lto_symtab_resolve_symbols): Rewrite. Fold in code that handles merging commons by choosing the largest decl. Fold in code that gives ODR errors. (lto_symtab_merge_decls_2): Simplify a lot. Emit queued diagnostics here. (lto_symtab_merge_decls_1): Re-structure. Deal with the case of no prevailing decl here. Diagnose mismatches in object types here. Drop all but the prevailing decls. (lto_symtab_prevailing_decl): Return the single prevailing decl. * lto-streamer-in.c (lto_input_tree_ref): Deal with VIEW_CONVERT_EXPRs in decl slots. Unshare the tree in this case. lto/ * lto.c (lto_fixup_tree): In case the prevailing decl is not compatible with the one we replace wrap it around a VIEW_CONVERT_EXPR. From-SVN: r152768
This commit is contained in:
parent
77ce724c6b
commit
200c8750d6
@ -1,3 +1,24 @@
|
||||
2009-10-14 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
* lto-symtab.c (lto_symtab_compatible): Fold in ...
|
||||
(lto_symtab_merge): ... here. Rewrite both to take the
|
||||
prevailing and a to-be-merged entry and to queue diagnostics
|
||||
properly.
|
||||
(lto_symtab_resolve_replaceable_p): New predicate for
|
||||
symbol resolution.
|
||||
(lto_symtab_resolve_can_prevail_p): Likewise.
|
||||
(lto_symtab_resolve_symbols): Rewrite. Fold in code that
|
||||
handles merging commons by choosing the largest decl. Fold
|
||||
in code that gives ODR errors.
|
||||
(lto_symtab_merge_decls_2): Simplify a lot. Emit queued
|
||||
diagnostics here.
|
||||
(lto_symtab_merge_decls_1): Re-structure. Deal with the
|
||||
case of no prevailing decl here. Diagnose mismatches
|
||||
in object types here. Drop all but the prevailing decls.
|
||||
(lto_symtab_prevailing_decl): Return the single prevailing decl.
|
||||
* lto-streamer-in.c (lto_input_tree_ref): Deal with
|
||||
VIEW_CONVERT_EXPRs in decl slots. Unshare the tree in this case.
|
||||
|
||||
2009-10-14 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
PR lto/41521
|
||||
|
@ -353,7 +353,16 @@ lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
|
||||
ix_u = lto_input_uleb128 (ib);
|
||||
result = lto_file_decl_data_get_var_decl (data_in->file_data, ix_u);
|
||||
if (tag == LTO_global_decl_ref)
|
||||
varpool_mark_needed_node (varpool_node (result));
|
||||
{
|
||||
if (TREE_CODE (result) == VIEW_CONVERT_EXPR)
|
||||
{
|
||||
tree decl = TREE_OPERAND (result, 0);
|
||||
varpool_mark_needed_node (varpool_node (decl));
|
||||
result = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (result), decl);
|
||||
}
|
||||
else
|
||||
varpool_mark_needed_node (varpool_node (result));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
764
gcc/lto-symtab.c
764
gcc/lto-symtab.c
@ -109,6 +109,79 @@ lto_symtab_maybe_init_hash_table (void)
|
||||
lto_symtab_entry_eq, NULL);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
static bool maybe_merge_incomplete_and_complete_type (tree, tree);
|
||||
|
||||
/* Try to merge an incomplete type INCOMPLETE with a complete type
|
||||
@ -160,42 +233,75 @@ maybe_merge_incomplete_and_complete_type (tree type1, tree type2)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Check if OLD_DECL and NEW_DECL are compatible. */
|
||||
/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
|
||||
all edges and removing the old node. */
|
||||
|
||||
static bool
|
||||
lto_symtab_compatible (tree old_decl, tree new_decl)
|
||||
static void
|
||||
lto_cgraph_replace_node (struct cgraph_node *node,
|
||||
struct cgraph_node *prevailing_node)
|
||||
{
|
||||
tree old_type, new_type;
|
||||
struct cgraph_edge *e, *next;
|
||||
|
||||
if (TREE_CODE (old_decl) != TREE_CODE (new_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)
|
||||
{
|
||||
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 ();
|
||||
}
|
||||
gcc_assert (!prevailing_node->global.inlined_to);
|
||||
cgraph_mark_address_taken_node (prevailing_node);
|
||||
}
|
||||
|
||||
if (TREE_CODE (new_decl) == FUNCTION_DECL)
|
||||
/* Redirect all incoming edges. */
|
||||
for (e = node->callers; e; e = next)
|
||||
{
|
||||
if (!gimple_types_compatible_p (TREE_TYPE (old_decl),
|
||||
TREE_TYPE (new_decl)))
|
||||
next = e->next_caller;
|
||||
cgraph_redirect_edge_callee (e, prevailing_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 (e = node->callees; e; e = next)
|
||||
{
|
||||
next = e->next_callee;
|
||||
cgraph_remove_edge (e);
|
||||
}
|
||||
|
||||
/* Finally remove the replaced node. */
|
||||
cgraph_remove_node (node);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
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;
|
||||
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 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
|
||||
@ -214,70 +320,27 @@ lto_symtab_compatible (tree old_decl, tree new_decl)
|
||||
??? 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);
|
||||
prevailing_type = TREE_TYPE (prevailing_decl);
|
||||
type = TREE_TYPE (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);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 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));
|
||||
|
||||
/* 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;
|
||||
}
|
||||
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 might want to emit a warning here if type qualification
|
||||
differences were spotted. Do not do this unconditionally though. */
|
||||
@ -290,213 +353,55 @@ lto_symtab_compatible (tree old_decl, tree new_decl)
|
||||
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;
|
||||
}
|
||||
if ((DECL_USER_ALIGN (prevailing_decl) && DECL_USER_ALIGN (decl))
|
||||
&& DECL_ALIGN (prevailing_decl) < DECL_ALIGN (decl))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Registers DECL with the LTO symbol table as having resolution RESOLUTION
|
||||
and read from FILE_DATA. */
|
||||
/* Return true if the symtab entry E can be replaced by another symtab
|
||||
entry. */
|
||||
|
||||
void
|
||||
lto_symtab_register_decl (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_entry_t new_entry;
|
||||
void **slot;
|
||||
if (DECL_EXTERNAL (e->decl)
|
||||
|| DECL_COMDAT (e->decl)
|
||||
|| DECL_WEAK (e->decl))
|
||||
return true;
|
||||
|
||||
/* 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));
|
||||
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_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;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get the lto_symtab_entry_def struct associated with ID
|
||||
if there is one. */
|
||||
/* Return true if the symtab entry E can be the prevailing one. */
|
||||
|
||||
static lto_symtab_entry_t
|
||||
lto_symtab_get (tree id)
|
||||
static bool
|
||||
lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e)
|
||||
{
|
||||
struct lto_symtab_entry_def temp;
|
||||
void **slot;
|
||||
struct cgraph_node *node;
|
||||
|
||||
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;
|
||||
}
|
||||
if (!TREE_STATIC (e->decl))
|
||||
return false;
|
||||
|
||||
/* Get the linker resolution for DECL. */
|
||||
/* For functions we need a non-discarded body. */
|
||||
if (TREE_CODE (e->decl) == FUNCTION_DECL)
|
||||
return ((node = cgraph_get_node (e->decl))
|
||||
&& node->analyzed);
|
||||
|
||||
enum ld_plugin_symbol_resolution
|
||||
lto_symtab_get_resolution (tree decl)
|
||||
{
|
||||
lto_symtab_entry_t e;
|
||||
/* A variable should have a size. */
|
||||
else if (TREE_CODE (e->decl) == VAR_DECL)
|
||||
return (DECL_SIZE (e->decl) != NULL_TREE
|
||||
/* The C++ frontend retains TREE_STATIC on the declaration
|
||||
of foo_ in struct Foo { static Foo *foo_; }; but it is
|
||||
not a definition. g++.dg/lto/20090315_0.C. */
|
||||
&& !DECL_EXTERNAL (e->decl));
|
||||
|
||||
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;
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* Resolve the symbol with the candidates in the chain *SLOT and store
|
||||
@ -506,114 +411,119 @@ static void
|
||||
lto_symtab_resolve_symbols (void **slot)
|
||||
{
|
||||
lto_symtab_entry_t e = (lto_symtab_entry_t) *slot;
|
||||
lto_symtab_entry_t prevailing = NULL;
|
||||
|
||||
/* If the chain is already resolved there is nothing to do. */
|
||||
if (e->resolution != LDPR_UNKNOWN)
|
||||
return;
|
||||
|
||||
/* This is a poor mans resolver. */
|
||||
/* Find the single non-replaceable prevailing symbol and
|
||||
diagnose ODR violations. */
|
||||
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 (!lto_symtab_resolve_can_prevail_p (e))
|
||||
{
|
||||
if (TREE_READONLY (e->decl))
|
||||
e->resolution = LDPR_PREVAILING_DEF_IRONLY;
|
||||
else
|
||||
e->resolution = LDPR_PREVAILING_DEF;
|
||||
e->resolution = LDPR_RESOLVED_IR;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Set a default resolution - the final prevailing one will get
|
||||
adjusted later. */
|
||||
e->resolution = LDPR_PREEMPTED_IR;
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Choose the first function that can prevail as prevailing. */
|
||||
if (TREE_CODE (e->decl) == FUNCTION_DECL)
|
||||
{
|
||||
prevailing = e;
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
found:
|
||||
if (TREE_CODE (prevailing->decl) == VAR_DECL
|
||||
&& TREE_READONLY (prevailing->decl))
|
||||
prevailing->resolution = LDPR_PREVAILING_DEF_IRONLY;
|
||||
else
|
||||
prevailing->resolution = LDPR_PREVAILING_DEF;
|
||||
}
|
||||
|
||||
/* Merge one symbol table chain to a (set of) prevailing decls. */
|
||||
/* 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 e2, e1;
|
||||
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. */
|
||||
e1 = (lto_symtab_entry_t) *slot;
|
||||
if (!e1->next)
|
||||
prevailing = (lto_symtab_entry_t) *slot;
|
||||
if (!prevailing->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;)
|
||||
/* Try to merge each entry with the prevailing one. */
|
||||
for (e = prevailing->next; e; e = 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;
|
||||
if (!lto_symtab_merge (prevailing, e))
|
||||
VEC_safe_push (tree, heap, mismatches, e->decl);
|
||||
}
|
||||
if (VEC_empty (tree, mismatches))
|
||||
return;
|
||||
|
||||
/* 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;
|
||||
/* 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)))
|
||||
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))
|
||||
{
|
||||
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");
|
||||
|
||||
VEC_free (tree, heap, mismatches);
|
||||
}
|
||||
|
||||
/* Helper to process the decl chain for the symbol table entry *SLOT. */
|
||||
@ -621,33 +531,105 @@ lto_symtab_fixup_var_decls (void **slot)
|
||||
static int
|
||||
lto_symtab_merge_decls_1 (void **slot, void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
lto_symtab_entry_t e;
|
||||
lto_symtab_entry_t e, prevailing;
|
||||
bool diagnosed_p = false;
|
||||
|
||||
/* Compute the symbol resolutions. */
|
||||
/* 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)
|
||||
gcc_assert (e->resolution != LDPR_PREVAILING_DEF_IRONLY
|
||||
&& e->resolution != LDPR_PREVAILING_DEF);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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)
|
||||
&& prevailing->next)
|
||||
prevailing = prevailing->next;
|
||||
/* We do not stream varpool nodes, so the first decl has to
|
||||
be good enough for now.
|
||||
??? For QOI choose a variable with readonly initializer
|
||||
if there is one. This matches C++
|
||||
struct Foo { static const int i = 1; }; without a real
|
||||
definition. */
|
||||
if (TREE_CODE (prevailing->decl) == VAR_DECL)
|
||||
while (!(TREE_READONLY (prevailing->decl)
|
||||
&& DECL_INITIAL (prevailing->decl))
|
||||
&& prevailing->next)
|
||||
prevailing = prevailing->next;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Record the prevailing variable. */
|
||||
if (TREE_CODE (prevailing->decl) == VAR_DECL)
|
||||
VEC_safe_push (tree, gc, lto_global_var_decls, prevailing->decl);
|
||||
|
||||
/* Diagnose mismatched objects. */
|
||||
for (e = prevailing->next; e; e = e->next)
|
||||
{
|
||||
if (TREE_CODE (prevailing->decl) == TREE_CODE (e->decl))
|
||||
continue;
|
||||
|
||||
switch (TREE_CODE (prevailing->decl))
|
||||
{
|
||||
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 ();
|
||||
}
|
||||
|
||||
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 a (hopefully) single prevailing decl. */
|
||||
/* Merge the chain to the single prevailing decl and diagnose
|
||||
mismatches. */
|
||||
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);
|
||||
/* Drop all but the prevailing decl from the symtab. */
|
||||
prevailing->next = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -685,21 +667,7 @@ lto_symtab_prevailing_decl (tree 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 ();
|
||||
return ret->decl;
|
||||
}
|
||||
|
||||
/* Remove any storage used to store resolution of DECL. */
|
||||
|
@ -1,3 +1,9 @@
|
||||
2009-10-14 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
* lto.c (lto_fixup_tree): In case the prevailing decl is not
|
||||
compatible with the one we replace wrap it around a
|
||||
VIEW_CONVERT_EXPR.
|
||||
|
||||
2009-10-09 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
PR lto/41635
|
||||
|
@ -1530,10 +1530,18 @@ lto_fixup_tree (tree *tp, int *walk_subtrees, void *data)
|
||||
|
||||
pointer_set_insert (fixup_data->free_list, t);
|
||||
|
||||
/* Replace the decl. If it is a not compatible VAR_DECL wrap
|
||||
it inside a VIEW_CONVERT_EXPR. */
|
||||
if (TREE_CODE (*tp) == VAR_DECL
|
||||
&& !useless_type_conversion_p (TREE_TYPE (*tp),
|
||||
TREE_TYPE (prevailing)))
|
||||
*tp = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*tp), prevailing);
|
||||
else
|
||||
*tp = prevailing;
|
||||
|
||||
/* Also replace t with prevailing defintion. We don't want to
|
||||
insert the other defintion in the seen set as we want to
|
||||
replace all instances of it. */
|
||||
*tp = prevailing;
|
||||
t = prevailing;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user