/* 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 "calls.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;
}
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 (decl))
return true;
if (DECL_PRESERVE_P (decl))
/* 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)
if (node->same_comdat_group)
for (symtab_node *next = node->same_comdat_group;
next != node; next = next->same_comdat_group)
- gcc_assert (!next->externally_visible
- || define == (next->resolution == LDPR_PREVAILING_DEF_IRONLY
- || next->resolution == LDPR_PREVAILING_DEF
- || next->resolution == LDPR_UNDEF
- || 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 ();
}
}
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)
{
fprintf (dump_file, " %s", vnode->name ());
fprintf (dump_file, "\n\n");
}
- cgraph_function_flags_ready = true;
+ symtab->function_flags_ready = true;
return 0;
}