/* IPA visibility pass
- Copyright (C) 2003-2014 Free Software Foundation, Inc.
+ Copyright (C) 2003-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "hard-reg-set.h"
+#include "function.h"
#include "cgraph.h"
#include "tree-pass.h"
-#include "pointer-set.h"
#include "calls.h"
#include "gimple-expr.h"
#include "varasm.h"
/* Return true when NODE can not be local. Worker for cgraph_local_node_p. */
-bool
-cgraph_node::non_local_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+static bool
+non_local_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
{
- /* FIXME: Aliases can be local, but i386 gets thunks wrong then. */
- return !(node->only_called_directly_or_aliased_p ()
- && !node->has_aliases_p ()
- && node->definition
- && !DECL_EXTERNAL (node->decl)
- && !node->externally_visible
- && !node->used_from_other_partition
- && !node->in_other_partition);
+ return !(node->only_called_directly_or_aliased_p ()
+ /* i386 would need update to output thunk with locak calling
+ ocnvetions. */
+ && !node->thunk.thunk_p
+ && node->definition
+ && !DECL_EXTERNAL (node->decl)
+ && !node->externally_visible
+ && !node->used_from_other_partition
+ && !node->in_other_partition);
}
/* Return true when function can be marked local. */
{
cgraph_node *n = ultimate_alias_target ();
- /* FIXME: thunks can be considered local, but we need prevent i386
- from attempting to change calling convention of them. */
if (n->thunk.thunk_p)
- return false;
- return !n->call_for_symbol_thunks_and_aliases (cgraph_node::non_local_p,
- NULL, true);
+ return n->callees->callee->local_p ();
+ return !n->call_for_symbol_thunks_and_aliases (non_local_p,
+ NULL, true);
}
-/* Return true when there is a reference to node and it is not vtable. */
-
-bool
-symtab_node::address_taken_from_non_vtable_p (void)
-{
- int i;
- struct ipa_ref *ref = NULL;
-
- for (i = 0; iterate_referring (i, ref); i++)
- if (ref->use == IPA_REF_ADDR)
- {
- varpool_node *node;
- if (is_a <cgraph_node *> (ref->referring))
- return true;
- node = dyn_cast <varpool_node *> (ref->referring);
- if (!DECL_VIRTUAL_P (node->decl))
- return true;
- }
- return false;
-}
-
/* A helper for comdat_can_be_unshared_p. */
static bool
{
if (!node->externally_visible)
return true;
- /* When address is taken, we don't know if equality comparison won't
- break eventually. Exception are virutal functions, C++
- constructors/destructors and vtables, where this is not possible by
- language standard. */
- if (!DECL_VIRTUAL_P (node->decl)
- && (TREE_CODE (node->decl) != FUNCTION_DECL
- || (!DECL_CXX_CONSTRUCTOR_P (node->decl)
- && !DECL_CXX_DESTRUCTOR_P (node->decl)))
- && node->address_taken_from_non_vtable_p ())
- return false;
+ if (node->address_can_be_compared_p ())
+ {
+ struct ipa_ref *ref;
+
+ for (unsigned int i = 0; node->iterate_referring (i, ref); i++)
+ if (ref->address_matters_p ())
+ return false;
+ }
/* If the symbol is used in some weird way, better to not touch it. */
if (node->force_output)
if (MAIN_NAME_P (DECL_NAME (node->decl)))
return true;
+ if (node->instrumentation_clone
+ && MAIN_NAME_P (DECL_NAME (node->orig_decl)))
+ return true;
+
return false;
}
-/* Return true when variable VNODE should be considered externally visible. */
+/* Return true when variable should be considered externally visible. */
bool
-varpool_externally_visible_p (varpool_node *vnode)
+varpool_node::externally_visible_p (void)
{
- if (DECL_EXTERNAL (vnode->decl))
+ if (DECL_EXTERNAL (decl))
return true;
- if (!TREE_PUBLIC (vnode->decl))
+ if (!TREE_PUBLIC (decl))
return false;
/* If linker counts on us, we must preserve the function. */
- if (vnode->used_from_object_file_p ())
+ if (used_from_object_file_p ())
+ return true;
+
+ /* Bringing TLS variables local may cause dynamic linker failures
+ on limits of static TLS vars. */
+ if (DECL_THREAD_LOCAL_P (decl)
+ && (DECL_TLS_MODEL (decl) != TLS_MODEL_EMULATED
+ && DECL_TLS_MODEL (decl) != TLS_MODEL_INITIAL_EXEC))
return true;
- if (DECL_HARD_REGISTER (vnode->decl))
+ if (DECL_HARD_REGISTER (decl))
return true;
- if (DECL_PRESERVE_P (vnode->decl))
+ if (DECL_PRESERVE_P (decl))
return true;
if (lookup_attribute ("externally_visible",
- DECL_ATTRIBUTES (vnode->decl)))
+ DECL_ATTRIBUTES (decl)))
return true;
if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
&& lookup_attribute ("dllexport",
- DECL_ATTRIBUTES (vnode->decl)))
+ DECL_ATTRIBUTES (decl)))
return true;
/* See if we have linker information about symbol not being used or
Even if the linker clams the symbol is unused, never bring internal
symbols that are declared by user as used or externally visible.
This is needed for i.e. references from asm statements. */
- if (vnode->used_from_object_file_p ())
+ if (used_from_object_file_p ())
return true;
- if (vnode->resolution == LDPR_PREVAILING_DEF_IRONLY)
+ if (resolution == LDPR_PREVAILING_DEF_IRONLY)
return false;
/* As a special case, the COMDAT virtual tables can be unshared.
is faster for dynamic linking. Also this match logic hidding vtables
from LTO symbol tables. */
if ((in_lto_p || flag_whole_program)
- && DECL_COMDAT (vnode->decl)
- && comdat_can_be_unshared_p (vnode))
+ && DECL_COMDAT (decl)
+ && comdat_can_be_unshared_p (this))
return false;
/* When doing link time optimizations, hidden symbols become local. */
if (in_lto_p
- && (DECL_VISIBILITY (vnode->decl) == VISIBILITY_HIDDEN
- || DECL_VISIBILITY (vnode->decl) == VISIBILITY_INTERNAL)
+ && (DECL_VISIBILITY (decl) == VISIBILITY_HIDDEN
+ || DECL_VISIBILITY (decl) == VISIBILITY_INTERNAL)
/* Be sure that node is defined in IR file, not in other object
file. In that case we don't set used_from_other_object_file. */
- && vnode->definition)
+ && definition)
;
else if (!flag_whole_program)
return true;
FIXME: We can do so for readonly vars with no address taken and
possibly also for vtables since no direct pointer comparsion is done.
It might be interesting to do so to reduce linking overhead. */
- if (DECL_COMDAT (vnode->decl) || DECL_WEAK (vnode->decl))
+ if (DECL_COMDAT (decl) || DECL_WEAK (decl))
return true;
return false;
}
/* walk_tree callback that rewrites initializer references. */
static tree
-update_vtable_references (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
+update_vtable_references (tree *tp, int *walk_subtrees,
+ void *data ATTRIBUTE_UNUSED)
{
if (TREE_CODE (*tp) == VAR_DECL
|| TREE_CODE (*tp) == FUNCTION_DECL)
define = (node->resolution == LDPR_PREVAILING_DEF_IRONLY
|| node->resolution == LDPR_PREVAILING_DEF
+ || node->resolution == LDPR_UNDEF
|| node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP);
/* The linker decisions ought to agree in the whole group. */
if (node->same_comdat_group)
for (symtab_node *next = node->same_comdat_group;
next != node; next = next->same_comdat_group)
- gcc_assert (!node->externally_visible
- || define == (next->resolution == LDPR_PREVAILING_DEF_IRONLY
- || next->resolution == LDPR_PREVAILING_DEF
- || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP));
+ {
+ if (!next->externally_visible)
+ continue;
+
+ bool same_def
+ = define == (next->resolution == LDPR_PREVAILING_DEF_IRONLY
+ || next->resolution == LDPR_PREVAILING_DEF
+ || next->resolution == LDPR_UNDEF
+ || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP);
+ gcc_assert (in_lto_p || same_def);
+ if (!same_def)
+ return;
+ }
if (node->same_comdat_group)
for (symtab_node *next = node->same_comdat_group;
}
if (node->thunk.thunk_p
+ && !node->thunk.add_pointer_bounds_args
&& TREE_PUBLIC (node->decl))
{
struct cgraph_node *decl_node = node;
}
FOR_EACH_DEFINED_FUNCTION (node)
{
- node->local.local |= node->local_p ();
+ if (!node->local.local)
+ node->local.local |= node->local_p ();
/* If we know that function can not be overwritten by a different semantics
and moreover its section can not be discarded, replace all direct calls
{
struct cgraph_edge *e = node->callers;
- cgraph_redirect_edge_callee (e, alias);
+ e->redirect_callee (alias);
if (gimple_has_body_p (e->caller->decl))
{
push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl));
- cgraph_redirect_edge_call_stmt_to_callee (e);
+ e->redirect_call_stmt_to_callee ();
pop_cfun ();
}
}
{
if (!vnode->definition)
continue;
- if (varpool_externally_visible_p (vnode))
+ if (vnode->externally_visible_p ())
vnode->externally_visible = true;
else
{
vnode->externally_visible = false;
vnode->forced_by_abi = false;
}
+ if (lookup_attribute ("no_reorder",
+ DECL_ATTRIBUTES (vnode->decl)))
+ vnode->no_reorder = 1;
if (!vnode->externally_visible
&& !vnode->weakref)
{
}
if (found)
{
- struct pointer_set_t *visited_nodes = pointer_set_create ();
+ hash_set<tree> visited_nodes;
- varpool_get_constructor (vnode);
+ vnode->get_constructor ();
walk_tree (&DECL_INITIAL (vnode->decl),
- update_vtable_references, NULL, visited_nodes);
- pointer_set_destroy (visited_nodes);
+ update_vtable_references, NULL, &visited_nodes);
vnode->remove_all_references ();
record_references_in_initializer (vnode->decl, false);
}
fprintf (dump_file, " %s", vnode->name ());
fprintf (dump_file, "\n\n");
}
- cgraph_function_flags_ready = true;
+ symtab->function_flags_ready = true;
return 0;
}