66379195d6
PR middle-end/53161 * symtab.c (symtab_register_node): Fix ordering issue. From-SVN: r187798
754 lines
20 KiB
C
754 lines
20 KiB
C
/* Symbol table.
|
|
Copyright (C) 2012 Free Software Foundation, Inc.
|
|
Contributed by Jan Hubicka
|
|
|
|
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 "tm.h"
|
|
#include "tree.h"
|
|
#include "tree-inline.h"
|
|
#include "langhooks.h"
|
|
#include "hashtab.h"
|
|
#include "ggc.h"
|
|
#include "cgraph.h"
|
|
#include "diagnostic.h"
|
|
#include "timevar.h"
|
|
#include "lto-streamer.h"
|
|
#include "rtl.h"
|
|
|
|
const char * const ld_plugin_symbol_resolution_names[]=
|
|
{
|
|
"",
|
|
"undef",
|
|
"prevailing_def",
|
|
"prevailing_def_ironly",
|
|
"preempted_reg",
|
|
"preempted_ir",
|
|
"resolved_ir",
|
|
"resolved_exec",
|
|
"resolved_dyn",
|
|
"prevailing_def_ironly_exp"
|
|
};
|
|
|
|
/* Hash table used to convert declarations into nodes. */
|
|
static GTY((param_is (union symtab_node_def))) htab_t symtab_hash;
|
|
/* Hash table used to convert assembler names into nodes. */
|
|
static GTY((param_is (union symtab_node_def))) htab_t assembler_name_hash;
|
|
|
|
/* Linked list of symbol table nodes. */
|
|
symtab_node symtab_nodes;
|
|
|
|
/* The order index of the next symtab node to be created. This is
|
|
used so that we can sort the cgraph nodes in order by when we saw
|
|
them, to support -fno-toplevel-reorder. */
|
|
int symtab_order;
|
|
|
|
/* Returns a hash code for P. */
|
|
|
|
static hashval_t
|
|
hash_node (const void *p)
|
|
{
|
|
const_symtab_node n = (const_symtab_node ) p;
|
|
return (hashval_t) DECL_UID (n->symbol.decl);
|
|
}
|
|
|
|
|
|
/* Returns nonzero if P1 and P2 are equal. */
|
|
|
|
static int
|
|
eq_node (const void *p1, const void *p2)
|
|
{
|
|
const_symtab_node n1 = (const_symtab_node) p1;
|
|
const_symtab_node n2 = (const_symtab_node) p2;
|
|
return DECL_UID (n1->symbol.decl) == DECL_UID (n2->symbol.decl);
|
|
}
|
|
|
|
/* Returns a hash code for P. */
|
|
|
|
static hashval_t
|
|
hash_node_by_assembler_name (const void *p)
|
|
{
|
|
const_symtab_node n = (const_symtab_node) p;
|
|
return (hashval_t) decl_assembler_name_hash (DECL_ASSEMBLER_NAME (n->symbol.decl));
|
|
}
|
|
|
|
/* Returns nonzero if P1 and P2 are equal. */
|
|
|
|
static int
|
|
eq_assembler_name (const void *p1, const void *p2)
|
|
{
|
|
const_symtab_node n1 = (const_symtab_node) p1;
|
|
const_tree name = (const_tree)p2;
|
|
return (decl_assembler_name_equal (n1->symbol.decl, name));
|
|
}
|
|
|
|
/* Insert NODE to assembler name hash. */
|
|
|
|
static void
|
|
insert_to_assembler_name_hash (symtab_node node)
|
|
{
|
|
gcc_checking_assert (!node->symbol.previous_sharing_asm_name
|
|
&& !node->symbol.next_sharing_asm_name);
|
|
if (assembler_name_hash)
|
|
{
|
|
void **aslot;
|
|
tree name = DECL_ASSEMBLER_NAME (node->symbol.decl);
|
|
|
|
aslot = htab_find_slot_with_hash (assembler_name_hash, name,
|
|
decl_assembler_name_hash (name),
|
|
INSERT);
|
|
gcc_assert (*aslot != node);
|
|
node->symbol.next_sharing_asm_name = (symtab_node)*aslot;
|
|
if (*aslot != NULL)
|
|
((symtab_node)*aslot)->symbol.previous_sharing_asm_name = node;
|
|
*aslot = node;
|
|
}
|
|
|
|
}
|
|
|
|
/* Remove NODE from assembler name hash. */
|
|
|
|
static void
|
|
unlink_from_assembler_name_hash (symtab_node node)
|
|
{
|
|
if (assembler_name_hash)
|
|
{
|
|
if (node->symbol.next_sharing_asm_name)
|
|
node->symbol.next_sharing_asm_name->symbol.previous_sharing_asm_name
|
|
= node->symbol.previous_sharing_asm_name;
|
|
if (node->symbol.previous_sharing_asm_name)
|
|
{
|
|
node->symbol.previous_sharing_asm_name->symbol.next_sharing_asm_name
|
|
= node->symbol.next_sharing_asm_name;
|
|
}
|
|
else
|
|
{
|
|
tree name = DECL_ASSEMBLER_NAME (node->symbol.decl);
|
|
void **slot;
|
|
slot = htab_find_slot_with_hash (assembler_name_hash, name,
|
|
decl_assembler_name_hash (name),
|
|
NO_INSERT);
|
|
gcc_assert (*slot == node);
|
|
if (!node->symbol.next_sharing_asm_name)
|
|
htab_clear_slot (assembler_name_hash, slot);
|
|
else
|
|
*slot = node->symbol.next_sharing_asm_name;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Add node into symbol table. This function is not used directly, but via
|
|
cgraph/varpool node creation routines. */
|
|
|
|
void
|
|
symtab_register_node (symtab_node node)
|
|
{
|
|
struct symtab_node_base key;
|
|
symtab_node *slot;
|
|
|
|
node->symbol.next = symtab_nodes;
|
|
node->symbol.previous = NULL;
|
|
if (symtab_nodes)
|
|
symtab_nodes->symbol.previous = node;
|
|
symtab_nodes = node;
|
|
|
|
if (!symtab_hash)
|
|
symtab_hash = htab_create_ggc (10, hash_node, eq_node, NULL);
|
|
key.decl = node->symbol.decl;
|
|
slot = (symtab_node *) htab_find_slot (symtab_hash, &key, INSERT);
|
|
if (*slot == NULL)
|
|
*slot = node;
|
|
|
|
ipa_empty_ref_list (&node->symbol.ref_list);
|
|
|
|
node->symbol.order = symtab_order++;
|
|
|
|
/* Be sure to do this last; C++ FE might create new nodes via
|
|
DECL_ASSEMBLER_NAME langhook! */
|
|
insert_to_assembler_name_hash (node);
|
|
}
|
|
|
|
/* Make NODE to be the one symtab hash is pointing to. Used when reshaping tree
|
|
of inline clones. */
|
|
|
|
void
|
|
symtab_insert_node_to_hashtable (symtab_node node)
|
|
{
|
|
struct symtab_node_base key;
|
|
symtab_node *slot;
|
|
|
|
if (!symtab_hash)
|
|
symtab_hash = htab_create_ggc (10, hash_node, eq_node, NULL);
|
|
key.decl = node->symbol.decl;
|
|
slot = (symtab_node *) htab_find_slot (symtab_hash, &key, INSERT);
|
|
*slot = node;
|
|
}
|
|
|
|
/* Remove node from symbol table. This function is not used directly, but via
|
|
cgraph/varpool node removal routines. */
|
|
|
|
void
|
|
symtab_unregister_node (symtab_node node)
|
|
{
|
|
void **slot;
|
|
ipa_remove_all_references (&node->symbol.ref_list);
|
|
ipa_remove_all_referring (&node->symbol.ref_list);
|
|
|
|
if (node->symbol.same_comdat_group)
|
|
{
|
|
symtab_node prev;
|
|
for (prev = node->symbol.same_comdat_group;
|
|
prev->symbol.same_comdat_group != node;
|
|
prev = prev->symbol.same_comdat_group)
|
|
;
|
|
if (node->symbol.same_comdat_group == prev)
|
|
prev->symbol.same_comdat_group = NULL;
|
|
else
|
|
prev->symbol.same_comdat_group = node->symbol.same_comdat_group;
|
|
node->symbol.same_comdat_group = NULL;
|
|
}
|
|
|
|
if (node->symbol.previous)
|
|
node->symbol.previous->symbol.next = node->symbol.next;
|
|
else
|
|
symtab_nodes = node->symbol.next;
|
|
if (node->symbol.next)
|
|
node->symbol.next->symbol.previous = node->symbol.previous;
|
|
node->symbol.next = NULL;
|
|
node->symbol.previous = NULL;
|
|
|
|
slot = htab_find_slot (symtab_hash, node, NO_INSERT);
|
|
if (*slot == node)
|
|
{
|
|
symtab_node replacement_node = NULL;
|
|
if (symtab_function_p (node))
|
|
replacement_node = (symtab_node)cgraph_find_replacement_node (cgraph (node));
|
|
if (!replacement_node)
|
|
htab_clear_slot (symtab_hash, slot);
|
|
else
|
|
*slot = replacement_node;
|
|
}
|
|
unlink_from_assembler_name_hash (node);
|
|
}
|
|
|
|
/* Return symbol table node associated with DECL, if any,
|
|
and NULL otherwise. */
|
|
|
|
symtab_node
|
|
symtab_get_node (const_tree decl)
|
|
{
|
|
symtab_node *slot;
|
|
struct symtab_node_base key;
|
|
|
|
gcc_checking_assert (TREE_CODE (decl) == FUNCTION_DECL
|
|
|| (TREE_CODE (decl) == VAR_DECL
|
|
&& (TREE_STATIC (decl) || DECL_EXTERNAL (decl)
|
|
|| in_lto_p)));
|
|
|
|
if (!symtab_hash)
|
|
return NULL;
|
|
|
|
key.decl = CONST_CAST2 (tree, const_tree, decl);
|
|
|
|
slot = (symtab_node *) htab_find_slot (symtab_hash, &key,
|
|
NO_INSERT);
|
|
|
|
if (slot)
|
|
return *slot;
|
|
return NULL;
|
|
}
|
|
|
|
/* Remove symtab NODE from the symbol table. */
|
|
|
|
void
|
|
symtab_remove_node (symtab_node node)
|
|
{
|
|
if (symtab_function_p (node))
|
|
cgraph_remove_node (cgraph (node));
|
|
else if (symtab_variable_p (node))
|
|
varpool_remove_node (varpool (node));
|
|
}
|
|
|
|
/* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME.
|
|
Return NULL if there's no such node. */
|
|
|
|
symtab_node
|
|
symtab_node_for_asm (const_tree asmname)
|
|
{
|
|
symtab_node node;
|
|
void **slot;
|
|
|
|
if (!assembler_name_hash)
|
|
{
|
|
assembler_name_hash =
|
|
htab_create_ggc (10, hash_node_by_assembler_name, eq_assembler_name,
|
|
NULL);
|
|
FOR_EACH_SYMBOL (node)
|
|
insert_to_assembler_name_hash (node);
|
|
}
|
|
|
|
slot = htab_find_slot_with_hash (assembler_name_hash, asmname,
|
|
decl_assembler_name_hash (asmname),
|
|
NO_INSERT);
|
|
|
|
if (slot)
|
|
{
|
|
node = (symtab_node) *slot;
|
|
return node;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* Set the DECL_ASSEMBLER_NAME and update symtab hashtables. */
|
|
|
|
void
|
|
change_decl_assembler_name (tree decl, tree name)
|
|
{
|
|
symtab_node node = NULL;
|
|
|
|
/* We can have user ASM names on things, like global register variables, that
|
|
are not in the symbol table. */
|
|
if ((TREE_CODE (decl) == VAR_DECL
|
|
&& (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
|
|
|| TREE_CODE (decl) == FUNCTION_DECL)
|
|
node = symtab_get_node (decl);
|
|
if (!DECL_ASSEMBLER_NAME_SET_P (decl))
|
|
{
|
|
SET_DECL_ASSEMBLER_NAME (decl, name);
|
|
if (node)
|
|
insert_to_assembler_name_hash (node);
|
|
}
|
|
else
|
|
{
|
|
if (name == DECL_ASSEMBLER_NAME (decl))
|
|
return;
|
|
|
|
if (node)
|
|
unlink_from_assembler_name_hash (node);
|
|
if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
|
|
&& DECL_RTL_SET_P (decl))
|
|
warning (0, "%D renamed after being referenced in assembly", decl);
|
|
|
|
SET_DECL_ASSEMBLER_NAME (decl, name);
|
|
if (node)
|
|
insert_to_assembler_name_hash (node);
|
|
}
|
|
}
|
|
|
|
/* Add NEW_ to the same comdat group that OLD is in. */
|
|
|
|
void
|
|
symtab_add_to_same_comdat_group (symtab_node new_node,
|
|
symtab_node old_node)
|
|
{
|
|
gcc_assert (DECL_ONE_ONLY (old_node->symbol.decl));
|
|
gcc_assert (!new_node->symbol.same_comdat_group);
|
|
gcc_assert (new_node != old_node);
|
|
|
|
DECL_COMDAT_GROUP (new_node->symbol.decl) = DECL_COMDAT_GROUP (old_node->symbol.decl);
|
|
new_node->symbol.same_comdat_group = old_node;
|
|
if (!old_node->symbol.same_comdat_group)
|
|
old_node->symbol.same_comdat_group = new_node;
|
|
else
|
|
{
|
|
symtab_node n;
|
|
for (n = old_node->symbol.same_comdat_group;
|
|
n->symbol.same_comdat_group != old_node;
|
|
n = n->symbol.same_comdat_group)
|
|
;
|
|
n->symbol.same_comdat_group = new_node;
|
|
}
|
|
}
|
|
|
|
/* Dissolve the same_comdat_group list in which NODE resides. */
|
|
|
|
void
|
|
symtab_dissolve_same_comdat_group_list (symtab_node node)
|
|
{
|
|
symtab_node n = node, next;
|
|
|
|
if (!node->symbol.same_comdat_group)
|
|
return;
|
|
do
|
|
{
|
|
next = n->symbol.same_comdat_group;
|
|
n->symbol.same_comdat_group = NULL;
|
|
n = next;
|
|
}
|
|
while (n != node);
|
|
}
|
|
|
|
/* Return printable assembler name of NODE.
|
|
This function is used only for debugging. When assembler name
|
|
is unknown go with identifier name. */
|
|
|
|
const char *
|
|
symtab_node_asm_name (symtab_node node)
|
|
{
|
|
if (!DECL_ASSEMBLER_NAME_SET_P (node->symbol.decl))
|
|
return lang_hooks.decl_printable_name (node->symbol.decl, 2);
|
|
return IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->symbol.decl));
|
|
}
|
|
|
|
/* Return printable identifier name. */
|
|
|
|
const char *
|
|
symtab_node_name (symtab_node node)
|
|
{
|
|
return lang_hooks.decl_printable_name (node->symbol.decl, 2);
|
|
}
|
|
|
|
static const char * const symtab_type_names[] = {"symbol", "function", "variable"};
|
|
|
|
/* Dump base fields of symtab nodes. Not to be used directly. */
|
|
|
|
void
|
|
dump_symtab_base (FILE *f, symtab_node node)
|
|
{
|
|
static const char * const visibility_types[] = {
|
|
"default", "protected", "hidden", "internal"
|
|
};
|
|
|
|
fprintf (f, "%s/%i (%s)",
|
|
symtab_node_asm_name (node),
|
|
node->symbol.order,
|
|
symtab_node_name (node));
|
|
dump_addr (f, " @", (void *)node);
|
|
fprintf (f, "\n Type: %s\n", symtab_type_names[node->symbol.type]);
|
|
fprintf (f, " Visibility:");
|
|
|
|
if (node->symbol.in_other_partition)
|
|
fprintf (f, " in_other_partition");
|
|
if (node->symbol.used_from_other_partition)
|
|
fprintf (f, " used_from_other_partition");
|
|
if (node->symbol.force_output)
|
|
fprintf (f, " force_output");
|
|
if (node->symbol.resolution != LDPR_UNKNOWN)
|
|
fprintf (f, " %s",
|
|
ld_plugin_symbol_resolution_names[(int)node->symbol.resolution]);
|
|
if (TREE_ASM_WRITTEN (node->symbol.decl))
|
|
fprintf (f, " asm_written");
|
|
if (DECL_EXTERNAL (node->symbol.decl))
|
|
fprintf (f, " external");
|
|
if (TREE_PUBLIC (node->symbol.decl))
|
|
fprintf (f, " public");
|
|
if (DECL_COMMON (node->symbol.decl))
|
|
fprintf (f, " common");
|
|
if (DECL_WEAK (node->symbol.decl))
|
|
fprintf (f, " weak");
|
|
if (DECL_DLLIMPORT_P (node->symbol.decl))
|
|
fprintf (f, " dll_import");
|
|
if (DECL_COMDAT (node->symbol.decl))
|
|
fprintf (f, " comdat");
|
|
if (DECL_COMDAT_GROUP (node->symbol.decl))
|
|
fprintf (f, " comdat_group:%s",
|
|
IDENTIFIER_POINTER (DECL_COMDAT_GROUP (node->symbol.decl)));
|
|
if (DECL_ONE_ONLY (node->symbol.decl))
|
|
fprintf (f, " one_only");
|
|
if (DECL_SECTION_NAME (node->symbol.decl))
|
|
fprintf (f, " section_name:%s",
|
|
TREE_STRING_POINTER (DECL_SECTION_NAME (node->symbol.decl)));
|
|
if (DECL_VISIBILITY_SPECIFIED (node->symbol.decl))
|
|
fprintf (f, " visibility_specified");
|
|
if (DECL_VISIBILITY (node->symbol.decl))
|
|
fprintf (f, " visibility:%s",
|
|
visibility_types [DECL_VISIBILITY (node->symbol.decl)]);
|
|
if (DECL_VIRTUAL_P (node->symbol.decl))
|
|
fprintf (f, " virtual");
|
|
if (DECL_ARTIFICIAL (node->symbol.decl))
|
|
fprintf (f, " artificial");
|
|
if (TREE_CODE (node->symbol.decl) == FUNCTION_DECL)
|
|
{
|
|
if (DECL_STATIC_CONSTRUCTOR (node->symbol.decl))
|
|
fprintf (f, " constructor");
|
|
if (DECL_STATIC_DESTRUCTOR (node->symbol.decl))
|
|
fprintf (f, " destructor");
|
|
}
|
|
fprintf (f, "\n");
|
|
|
|
if (node->symbol.same_comdat_group)
|
|
fprintf (f, " Same comdat group as: %s/%i\n",
|
|
symtab_node_asm_name (node->symbol.same_comdat_group),
|
|
node->symbol.same_comdat_group->symbol.order);
|
|
if (node->symbol.next_sharing_asm_name)
|
|
fprintf (f, " next sharing asm name: %i\n",
|
|
node->symbol.next_sharing_asm_name->symbol.order);
|
|
if (node->symbol.previous_sharing_asm_name)
|
|
fprintf (f, " previous sharing asm name: %i\n",
|
|
node->symbol.previous_sharing_asm_name->symbol.order);
|
|
|
|
if (node->symbol.address_taken)
|
|
fprintf (f, " Address is taken.\n");
|
|
if (node->symbol.aux)
|
|
{
|
|
fprintf (f, " Aux:");
|
|
dump_addr (f, " @", (void *)node->symbol.aux);
|
|
}
|
|
|
|
fprintf (f, " References: ");
|
|
ipa_dump_references (f, &node->symbol.ref_list);
|
|
fprintf (f, " Referring: ");
|
|
ipa_dump_referring (f, &node->symbol.ref_list);
|
|
}
|
|
|
|
/* Dump symtab node. */
|
|
|
|
void
|
|
dump_symtab_node (FILE *f, symtab_node node)
|
|
{
|
|
if (symtab_function_p (node))
|
|
dump_cgraph_node (f, cgraph (node));
|
|
else if (symtab_variable_p (node))
|
|
dump_varpool_node (f, varpool (node));
|
|
}
|
|
|
|
/* Dump symbol table. */
|
|
|
|
void
|
|
dump_symtab (FILE *f)
|
|
{
|
|
symtab_node node;
|
|
fprintf (f, "Symbol table:\n\n");
|
|
FOR_EACH_SYMBOL (node)
|
|
dump_symtab_node (f, node);
|
|
}
|
|
|
|
/* Dump symtab node NODE to stderr. */
|
|
|
|
DEBUG_FUNCTION void
|
|
debug_symtab_node (symtab_node node)
|
|
{
|
|
dump_symtab_node (stderr, node);
|
|
}
|
|
|
|
/* Dump symbol table to stderr. */
|
|
|
|
DEBUG_FUNCTION void
|
|
debug_symtab (void)
|
|
{
|
|
dump_symtab (stderr);
|
|
}
|
|
|
|
/* Verify common part of symtab nodes. */
|
|
|
|
DEBUG_FUNCTION bool
|
|
verify_symtab_base (symtab_node node)
|
|
{
|
|
bool error_found = false;
|
|
symtab_node hashed_node;
|
|
|
|
if (symtab_function_p (node))
|
|
{
|
|
if (TREE_CODE (node->symbol.decl) != FUNCTION_DECL)
|
|
{
|
|
error ("function symbol is not function");
|
|
error_found = true;
|
|
}
|
|
}
|
|
else if (symtab_variable_p (node))
|
|
{
|
|
if (TREE_CODE (node->symbol.decl) != VAR_DECL)
|
|
{
|
|
error ("variable symbol is not variable");
|
|
error_found = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error ("node has unknown type");
|
|
error_found = true;
|
|
}
|
|
|
|
hashed_node = symtab_get_node (node->symbol.decl);
|
|
if (!hashed_node)
|
|
{
|
|
error ("node not found in symtab decl hashtable");
|
|
error_found = true;
|
|
}
|
|
if (assembler_name_hash)
|
|
{
|
|
hashed_node = symtab_node_for_asm (DECL_ASSEMBLER_NAME (node->symbol.decl));
|
|
if (hashed_node && hashed_node->symbol.previous_sharing_asm_name)
|
|
{
|
|
error ("assembler name hash list corrupted");
|
|
error_found = true;
|
|
}
|
|
while (hashed_node)
|
|
{
|
|
if (hashed_node == node)
|
|
break;
|
|
hashed_node = hashed_node->symbol.next_sharing_asm_name;
|
|
}
|
|
if (!hashed_node)
|
|
{
|
|
error ("node not found in symtab assembler name hash");
|
|
error_found = true;
|
|
}
|
|
}
|
|
if (node->symbol.previous_sharing_asm_name
|
|
&& node->symbol.previous_sharing_asm_name->symbol.next_sharing_asm_name != node)
|
|
{
|
|
error ("double linked list of assembler names corrupted");
|
|
}
|
|
if (node->symbol.same_comdat_group)
|
|
{
|
|
symtab_node n = node->symbol.same_comdat_group;
|
|
|
|
if (!DECL_ONE_ONLY (n->symbol.decl))
|
|
{
|
|
error ("non-DECL_ONE_ONLY node in a same_comdat_group list");
|
|
error_found = true;
|
|
}
|
|
if (n->symbol.type != node->symbol.type)
|
|
{
|
|
error ("mixing different types of symbol in same comdat groups is not supported");
|
|
error_found = true;
|
|
}
|
|
if (n == node)
|
|
{
|
|
error ("node is alone in a comdat group");
|
|
error_found = true;
|
|
}
|
|
do
|
|
{
|
|
if (!n->symbol.same_comdat_group)
|
|
{
|
|
error ("same_comdat_group is not a circular list");
|
|
error_found = true;
|
|
break;
|
|
}
|
|
n = n->symbol.same_comdat_group;
|
|
}
|
|
while (n != node);
|
|
}
|
|
return error_found;
|
|
}
|
|
|
|
/* Verify consistency of NODE. */
|
|
|
|
DEBUG_FUNCTION void
|
|
verify_symtab_node (symtab_node node)
|
|
{
|
|
if (seen_error ())
|
|
return;
|
|
|
|
timevar_push (TV_CGRAPH_VERIFY);
|
|
if (symtab_function_p (node))
|
|
verify_cgraph_node (cgraph (node));
|
|
else
|
|
if (verify_symtab_base (node))
|
|
{
|
|
dump_symtab_node (stderr, node);
|
|
internal_error ("verify_symtab_node failed");
|
|
}
|
|
timevar_pop (TV_CGRAPH_VERIFY);
|
|
}
|
|
|
|
/* Verify symbol table for internal consistency. */
|
|
|
|
DEBUG_FUNCTION void
|
|
verify_symtab (void)
|
|
{
|
|
symtab_node node;
|
|
FOR_EACH_SYMBOL (node)
|
|
verify_symtab_node (node);
|
|
}
|
|
|
|
/* Return true when RESOLUTION indicate that linker will use
|
|
the symbol from non-LTO object files. */
|
|
|
|
bool
|
|
resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution resolution)
|
|
{
|
|
return (resolution == LDPR_PREVAILING_DEF
|
|
|| resolution == LDPR_PREEMPTED_REG
|
|
|| resolution == LDPR_RESOLVED_EXEC
|
|
|| resolution == LDPR_RESOLVED_DYN);
|
|
}
|
|
|
|
/* Return true when NODE is known to be used from other (non-LTO) object file.
|
|
Known only when doing LTO via linker plugin. */
|
|
|
|
bool
|
|
symtab_used_from_object_file_p (symtab_node node)
|
|
{
|
|
if (!TREE_PUBLIC (node->symbol.decl) || DECL_EXTERNAL (node->symbol.decl))
|
|
return false;
|
|
if (resolution_used_from_other_file_p (node->symbol.resolution))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/* Make DECL local. FIXME: We shouldn't need to mess with rtl this early,
|
|
but other code such as notice_global_symbol generates rtl. */
|
|
void
|
|
symtab_make_decl_local (tree decl)
|
|
{
|
|
rtx rtl, symbol;
|
|
|
|
if (TREE_CODE (decl) == VAR_DECL)
|
|
DECL_COMMON (decl) = 0;
|
|
else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
|
|
|
|
if (DECL_ONE_ONLY (decl) || DECL_COMDAT (decl))
|
|
{
|
|
/* It is possible that we are linking against library defining same COMDAT
|
|
function. To avoid conflict we need to rename our local name of the
|
|
function just in the case WHOPR partitioning decide to make it hidden
|
|
to avoid cross partition references. */
|
|
if (flag_wpa)
|
|
{
|
|
const char *old_name;
|
|
symtab_node node = symtab_get_node (decl);
|
|
old_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
|
|
change_decl_assembler_name (decl,
|
|
clone_function_name (decl, "local"));
|
|
if (node->symbol.lto_file_data)
|
|
lto_record_renamed_decl (node->symbol.lto_file_data,
|
|
old_name,
|
|
IDENTIFIER_POINTER
|
|
(DECL_ASSEMBLER_NAME (decl)));
|
|
}
|
|
DECL_SECTION_NAME (decl) = 0;
|
|
DECL_COMDAT (decl) = 0;
|
|
}
|
|
DECL_COMDAT_GROUP (decl) = 0;
|
|
DECL_WEAK (decl) = 0;
|
|
DECL_EXTERNAL (decl) = 0;
|
|
TREE_PUBLIC (decl) = 0;
|
|
if (!DECL_RTL_SET_P (decl))
|
|
return;
|
|
|
|
/* Update rtl flags. */
|
|
make_decl_rtl (decl);
|
|
|
|
rtl = DECL_RTL (decl);
|
|
if (!MEM_P (rtl))
|
|
return;
|
|
|
|
symbol = XEXP (rtl, 0);
|
|
if (GET_CODE (symbol) != SYMBOL_REF)
|
|
return;
|
|
|
|
SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl);
|
|
}
|
|
#include "gt-symtab.h"
|