/* Symbol table.
- Copyright (C) 2012-2014 Free Software Foundation, Inc.
+ Copyright (C) 2012-2015 Free Software Foundation, Inc.
Contributed by Jan Hubicka
This file is part of GCC.
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
#include "tree.h"
+#include "fold-const.h"
#include "print-tree.h"
#include "varasm.h"
#include "hashtab.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "machmode.h"
#include "hard-reg-set.h"
#include "input.h"
#include "function.h"
#include "gimple.h"
#include "tree-inline.h"
#include "langhooks.h"
+#include "hash-map.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
#include "cgraph.h"
#include "diagnostic.h"
#include "timevar.h"
#include "ipa-utils.h"
#include "calls.h"
-static const char *ipa_ref_use_name[] = {"read","write","addr","alias"};
+static const char *ipa_ref_use_name[] = {"read","write","addr","alias","chkp"};
const char * const ld_plugin_symbol_resolution_names[]=
{
tree name = DECL_ASSEMBLER_NAME (node->decl);
+ /* C++ FE can produce decls without associated assembler name and insert
+ them to symtab to hold section or TLS information. */
+ if (!name)
+ return;
+
hashval_t hash = decl_assembler_name_hash (name);
aslot = assembler_name_hash->find_slot_with_hash (name, hash, INSERT);
gcc_assert (*aslot != node);
{
tree name = DECL_ASSEMBLER_NAME (node->decl);
symtab_node **slot;
+
+ if (!name)
+ return;
+
hashval_t hash = decl_assembler_name_hash (name);
slot = assembler_name_hash->find_slot_with_hash (name, hash,
NO_INSERT);
}
}
-/* 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);
-}
-
/* Hash sections by their names. */
hashval_t
/* IPA_REF_ALIAS is always inserted at the beginning of the list. */
if(use_type == IPA_REF_ALIAS)
- {
- list2->referring.safe_insert (0, ref);
- ref->referred_index = 0;
+ {
+ list2->referring.safe_insert (0, ref);
+ ref->referred_index = 0;
- for (unsigned int i = 1; i < list2->referring.length (); i++)
- list2->referring[i]->referred_index = i;
- }
+ for (unsigned int i = 1; i < list2->referring.length (); i++)
+ list2->referring[i]->referred_index = i;
+ }
else
- {
- list2->referring.safe_push (ref);
- ref->referred_index = list2->referring.length () - 1;
- }
+ {
+ list2->referring.safe_push (ref);
+ ref->referred_index = list2->referring.length () - 1;
+ }
ref->referring = this;
ref->referred = referred_node;
fprintf (file, "\n");
}
-/* Return true if list contains an alias. */
-bool
-symtab_node::has_aliases_p (void)
-{
- ipa_ref *ref = NULL;
- int i;
-
- for (i = 0; iterate_referring (i, ref); i++)
- if (ref->use == IPA_REF_ALIAS)
- return true;
- return false;
-}
-
-/* Iterates I-th reference in the list, REF is also set. */
-
-ipa_ref *
-symtab_node::iterate_reference (unsigned i, ipa_ref *&ref)
-{
- vec_safe_iterate (ref_list.references, i, &ref);
-
- return ref;
-}
-
-/* Iterates I-th referring item in the list, REF is also set. */
-
-ipa_ref *
-symtab_node::iterate_referring (unsigned i, ipa_ref *&ref)
-{
- ref_list.referring.iterate (i, &ref);
-
- return ref;
-}
-
-/* Iterates I-th referring alias item in the list, REF is also set. */
-
-ipa_ref *
-symtab_node::iterate_direct_aliases (unsigned i, ipa_ref *&ref)
-{
- ref_list.referring.iterate (i, &ref);
-
- if (ref && ref->use != IPA_REF_ALIAS)
- return NULL;
-
- return ref;
-}
-
static const char * const symtab_type_names[] = {"symbol", "function", "variable"};
/* Dump base fields of symtab nodes to F. Not to be used directly. */
error ("double linked list of assembler names corrupted");
error_found = true;
}
+ if (body_removed && definition)
+ {
+ error ("node has body_removed but is definition");
+ error_found = true;
+ }
if (analyzed && !definition)
{
error ("node is analyzed byt it is not a definition");
error ("same_comdat_group list across different groups");
error_found = true;
}
- if (!n->definition)
- {
- error ("Node has same_comdat_group but it is not a definition");
- error_found = true;
- }
if (n->type != type)
{
error ("mixing different types of symbol in same comdat groups is not supported");
error_found = true;
}
if (get_section () && get_comdat_group ()
- && !implicit_section)
+ && !implicit_section
+ && !lookup_attribute ("section", DECL_ATTRIBUTES (decl)))
{
error ("Both section and comdat group is set");
error_found = true;
&existed);
if (!existed)
*entry = node;
- else
- for (s = (*entry)->same_comdat_group; s != NULL && s != node; s = s->same_comdat_group)
+ else if (!DECL_EXTERNAL (node->decl))
+ {
+ for (s = (*entry)->same_comdat_group;
+ s != NULL && s != node && s != *entry;
+ s = s->same_comdat_group)
+ ;
if (!s || s == *entry)
{
- error ("Two symbols with same comdat_group are not linked by the same_comdat_group list.");
+ error ("Two symbols with same comdat_group are not linked by "
+ "the same_comdat_group list.");
(*entry)->debug ();
node->debug ();
internal_error ("symtab_node::verify failed");
}
+ }
}
}
}
-/* 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_node::used_from_object_file_p_worker (symtab_node *node)
-{
- if (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl))
- return false;
- if (resolution_used_from_other_file_p (node->resolution))
- return true;
- return false;
-}
-
-
-/* Return true when symtab_node is known to be used from other (non-LTO)
- object file. Known only when doing LTO via linker plugin. */
-
-bool
-symtab_node::used_from_object_file_p (void)
-{
- return symtab_node::used_from_object_file_p_worker (this);
-}
-
/* Make DECL local. FIXME: We shouldn't need to mess with rtl this early,
but other code such as notice_global_symbol generates rtl. */
return;
if (TREE_CODE (decl) == VAR_DECL)
- DECL_COMMON (decl) = 0;
+ {
+ DECL_COMMON (decl) = 0;
+ /* ADDRESSABLE flag is not defined for public symbols. */
+ TREE_ADDRESSABLE (decl) = 1;
+ }
else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
DECL_COMDAT (decl) = 0;
DECL_VISIBILITY_SPECIFIED (decl) = 0;
DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
TREE_PUBLIC (decl) = 0;
+ DECL_DLLIMPORT_P (decl) = 0;
if (!DECL_RTL_SET_P (decl))
return;
/* Walk the alias chain to return the symbol NODE is alias of.
If NODE is not an alias, return NODE.
- When AVAILABILITY is non-NULL, get minimal availability in the chain. */
+ Assumes NODE is known to be alias. */
symtab_node *
-symtab_node::ultimate_alias_target (enum availability *availability)
+symtab_node::ultimate_alias_target_1 (enum availability *availability)
{
bool weakref_p = false;
- if (!alias)
- {
- if (availability)
- *availability = get_availability ();
- return this;
- }
-
/* To determine visibility of the target, we follow ELF semantic of aliases.
Here alias is an alternative assembler name of a given definition. Its
availability prevails the availability of its target (i.e. static alias of
return h ? h->init : DEFAULT_INIT_PRIORITY;
}
-/* Return availability of NODE. */
-enum availability symtab_node::get_availability (void)
-{
- if (is_a <cgraph_node *> (this))
- return dyn_cast <cgraph_node *> (this)->get_availability ();
- else
- return dyn_cast <varpool_node *> (this)->get_availability ();;
-}
-
-
/* Return the finalization priority. */
priority_type
/* If alias has address taken, so does the target. */
if (address_taken)
target->ultimate_alias_target ()->address_taken = true;
- return true;
-}
-
-/* Call calback on symtab node and aliases associated to this node.
- When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
- skipped. */
-bool
-symtab_node::call_for_symbol_and_aliases (bool (*callback) (symtab_node *,
- void *),
- void *data, bool include_overwritable)
-{
- int i;
+ /* All non-weakref aliases of THIS are now in fact aliases of TARGET. */
ipa_ref *ref;
-
- if (callback (this, data))
- return true;
- for (i = 0; iterate_referring (i, ref); i++)
- if (ref->use == IPA_REF_ALIAS)
- {
- symtab_node *alias = ref->referring;
- if (include_overwritable
- || alias->get_availability () > AVAIL_INTERPOSABLE)
- if (alias->call_for_symbol_and_aliases (callback, data,
- include_overwritable))
- return true;
- }
- return false;
+ for (unsigned i = 0; iterate_direct_aliases (i, ref);)
+ {
+ struct symtab_node *alias_alias = ref->referring;
+ if (!alias_alias->weakref)
+ {
+ alias_alias->remove_all_references ();
+ alias_alias->create_reference (target, IPA_REF_ALIAS, NULL);
+ }
+ else i++;
+ }
+ return true;
}
/* Worker searching noninterposable alias. */
!= flags_from_decl_or_type (fn->decl))
|| DECL_ATTRIBUTES (node->decl) != DECL_ATTRIBUTES (fn->decl))
return false;
-
*(symtab_node **)data = node;
return true;
}
/* Otherwise create a new one. */
new_decl = copy_node (node->decl);
+ DECL_DLLIMPORT_P (new_decl) = 0;
DECL_NAME (new_decl) = clone_function_name (node->decl, "localalias");
if (TREE_CODE (new_decl) == FUNCTION_DECL)
DECL_STRUCT_FUNCTION (new_decl) = NULL;
if (varpool_node *vnode = dyn_cast <varpool_node *> (this))
{
+ if (alias && definition && !ultimate_alias_target ()->definition)
+ return SYMBOL_EXTERNAL;
/* Constant pool references use local symbol names that can not
be promoted global. We should never put into a constant pool
objects that can not be duplicated across partitions. */
if (DECL_IN_CONSTANT_POOL (decl))
return SYMBOL_DUPLICATE;
+ if (DECL_HARD_REGISTER (decl))
+ return SYMBOL_DUPLICATE;
gcc_checking_assert (vnode->definition);
}
/* Functions that are cloned may stay in callgraph even if they are unused.
Handle them as external; compute_ltrans_boundary take care to make
proper things to happen (i.e. to make them appear in the boundary but
with body streamed, so clone can me materialized). */
- else if (!dyn_cast <cgraph_node *> (this)->definition)
+ else if (!dyn_cast <cgraph_node *> (this)->function_symbol ()->definition)
return SYMBOL_EXTERNAL;
/* Linker discardable symbols are duplicated to every use unless they are
return true;
return false;
}
+
+/* Return 0 if symbol is known to have different address than S2,
+ Return 1 if symbol is known to have same address as S2,
+ return 2 otherwise. */
+int
+symtab_node::equal_address_to (symtab_node *s2)
+{
+ enum availability avail1, avail2;
+
+ /* A Shortcut: equivalent symbols are always equivalent. */
+ if (this == s2)
+ return 1;
+
+ /* For non-interposable aliases, lookup and compare their actual definitions.
+ Also check if the symbol needs to bind to given definition. */
+ symtab_node *rs1 = ultimate_alias_target (&avail1);
+ symtab_node *rs2 = s2->ultimate_alias_target (&avail2);
+ bool binds_local1 = rs1->analyzed && decl_binds_to_current_def_p (this->decl);
+ bool binds_local2 = rs2->analyzed && decl_binds_to_current_def_p (s2->decl);
+ bool really_binds_local1 = binds_local1;
+ bool really_binds_local2 = binds_local2;
+
+ /* Addresses of vtables and virtual functions can not be used by user
+ code and are used only within speculation. In this case we may make
+ symbol equivalent to its alias even if interposition may break this
+ rule. Doing so will allow us to turn speculative inlining into
+ non-speculative more agressively. */
+ if (DECL_VIRTUAL_P (this->decl) && avail1 >= AVAIL_AVAILABLE)
+ binds_local1 = true;
+ if (DECL_VIRTUAL_P (s2->decl) && avail2 >= AVAIL_AVAILABLE)
+ binds_local2 = true;
+
+ /* If both definitions are available we know that even if they are bound
+ to other unit they must be defined same way and therefore we can use
+ equivalence test. */
+ if (rs1 != rs2 && avail1 >= AVAIL_AVAILABLE && avail2 >= AVAIL_AVAILABLE)
+ binds_local1 = binds_local2 = true;
+
+ if ((binds_local1 ? rs1 : this)
+ == (binds_local2 ? rs2 : s2))
+ {
+ /* We made use of the fact that alias is not weak. */
+ if (binds_local1 && rs1 != this)
+ refuse_visibility_changes = true;
+ if (binds_local2 && rs2 != s2)
+ s2->refuse_visibility_changes = true;
+ return 1;
+ }
+
+ /* If both symbols may resolve to NULL, we can not really prove them different. */
+ if (!nonzero_address () && !s2->nonzero_address ())
+ return 2;
+
+ /* Except for NULL, functions and variables never overlap. */
+ if (TREE_CODE (decl) != TREE_CODE (s2->decl))
+ return 0;
+
+ /* If one of the symbols is unresolved alias, punt. */
+ if (rs1->alias || rs2->alias)
+ return 2;
+
+ /* If we have a non-interposale definition of at least one of the symbols
+ and the other symbol is different, we know other unit can not interpose
+ it to the first symbol; all aliases of the definition needs to be
+ present in the current unit. */
+ if (((really_binds_local1 || really_binds_local2)
+ /* If we have both definitions and they are different, we know they
+ will be different even in units they binds to. */
+ || (binds_local1 && binds_local2))
+ && rs1 != rs2)
+ {
+ /* We make use of the fact that one symbol is not alias of the other
+ and that the definition is non-interposable. */
+ refuse_visibility_changes = true;
+ s2->refuse_visibility_changes = true;
+ rs1->refuse_visibility_changes = true;
+ rs2->refuse_visibility_changes = true;
+ return 0;
+ }
+
+ /* TODO: Alias oracle basically assume that addresses of global variables
+ are different unless they are declared as alias of one to another.
+ We probably should be consistent and use this fact here, too, and update
+ alias oracle to use this predicate. */
+
+ return 2;
+}
+
+/* Worker for call_for_symbol_and_aliases. */
+
+bool
+symtab_node::call_for_symbol_and_aliases_1 (bool (*callback) (symtab_node *,
+ void *),
+ void *data,
+ bool include_overwritable)
+{
+ ipa_ref *ref;
+ FOR_EACH_ALIAS (this, ref)
+ {
+ symtab_node *alias = ref->referring;
+ if (include_overwritable
+ || alias->get_availability () > AVAIL_INTERPOSABLE)
+ if (alias->call_for_symbol_and_aliases (callback, data,
+ include_overwritable))
+ return true;
+ }
+ return false;
+}
+
+/* Return ture if address of N is possibly compared. */
+
+static bool
+address_matters_1 (symtab_node *n, void *)
+{
+ struct ipa_ref *ref;
+
+ if (!n->address_can_be_compared_p ())
+ return false;
+ if (n->externally_visible || n->force_output)
+ return true;
+
+ for (unsigned int i = 0; n->iterate_referring (i, ref); i++)
+ if (ref->address_matters_p ())
+ return true;
+ return false;
+}
+
+/* Return true if symbol's address may possibly be compared to other
+ symbol's address. */
+
+bool
+symtab_node::address_matters_p ()
+{
+ gcc_assert (!alias);
+ return call_for_symbol_and_aliases (address_matters_1, NULL, true);
+}
+
+/* Return ture if symbol's alignment may be increased. */
+
+bool
+symtab_node::can_increase_alignment_p (void)
+{
+ symtab_node *target = ultimate_alias_target ();
+
+ /* For now support only variables. */
+ if (TREE_CODE (decl) != VAR_DECL)
+ return false;
+
+ /* With -fno-toplevel-reorder we may have already output the constant. */
+ if (TREE_ASM_WRITTEN (target->decl))
+ return false;
+
+ /* If target is already placed in an anchor, we can not touch its
+ alignment. */
+ if (DECL_RTL_SET_P (target->decl)
+ && MEM_P (DECL_RTL (target->decl))
+ && SYMBOL_REF_HAS_BLOCK_INFO_P (XEXP (DECL_RTL (target->decl), 0)))
+ return false;
+
+ /* Constant pool entries may be shared. */
+ if (DECL_IN_CONSTANT_POOL (target->decl))
+ return false;
+
+ /* We cannot change alignment of symbols that may bind to symbols
+ in other translation unit that may contain a definition with lower
+ alignment. */
+ if (!decl_binds_to_current_def_p (decl))
+ return false;
+
+ /* When compiling partition, be sure the symbol is not output by other
+ partition. */
+ if (flag_ltrans
+ && (target->in_other_partition
+ || target->get_partitioning_class () == SYMBOL_DUPLICATE))
+ return false;
+
+ /* Do not override the alignment as specified by the ABI when the used
+ attribute is set. */
+ if (DECL_PRESERVE_P (decl) || DECL_PRESERVE_P (target->decl))
+ return false;
+
+ /* Do not override explicit alignment set by the user when an explicit
+ section name is also used. This is a common idiom used by many
+ software projects. */
+ if (DECL_SECTION_NAME (target->decl) != NULL && !target->implicit_section)
+ return false;
+
+ return true;
+}
+
+/* Worker for symtab_node::increase_alignment. */
+
+static bool
+increase_alignment_1 (symtab_node *n, void *v)
+{
+ unsigned int align = (size_t)v;
+ if (DECL_ALIGN (n->decl) < align
+ && n->can_increase_alignment_p ())
+ {
+ DECL_ALIGN (n->decl) = align;
+ DECL_USER_ALIGN (n->decl) = 1;
+ }
+ return false;
+}
+
+/* Increase alignment of THIS to ALIGN. */
+
+void
+symtab_node::increase_alignment (unsigned int align)
+{
+ gcc_assert (can_increase_alignment_p () && align < MAX_OFILE_ALIGNMENT);
+ ultimate_alias_target()->call_for_symbol_and_aliases (increase_alignment_1,
+ (void *)(size_t) align,
+ true);
+ gcc_assert (DECL_ALIGN (decl) >= align);
+}
+
+/* Helper for symtab_node::definition_alignment. */
+
+static bool
+get_alignment_1 (symtab_node *n, void *v)
+{
+ *((unsigned int *)v) = MAX (*((unsigned int *)v), DECL_ALIGN (n->decl));
+ return false;
+}
+
+/* Return desired alignment of the definition. This is NOT alignment useful
+ to access THIS, because THIS may be interposable and DECL_ALIGN should
+ be used instead. It however must be guaranteed when output definition
+ of THIS. */
+
+unsigned int
+symtab_node::definition_alignment ()
+{
+ unsigned int align = 0;
+ gcc_assert (!alias);
+ call_for_symbol_and_aliases (get_alignment_1, &align, true);
+ return align;
+}