mirror of git://gcc.gnu.org/git/gcc.git
cgraph.c (cgraph_node::can_remove_if_no_direct_calls_p): Rewrite for correct comdat handling.
* cgraph.c (cgraph_node::can_remove_if_no_direct_calls_p): Rewrite for correct comdat handling. (cgraph_node::will_be_removed_from_program_if_no_direct_calls_p): Likewise. * cgraph.h (call_for_symbol_and_aliases): Fix formating. (used_from_object_file_p_worker): Remove. (cgraph_node::only_called_directly_or_alised): Add used_from_object_file_p. * ipa-inline-analysis.c (growth_likely_positive): Optimie. * ipa-inline-transform.c (can_remove_node_now_p_1): Use can_remove_if_no_direct_calls_and_refs_p. From-SVN: r221193
This commit is contained in:
parent
d720e658eb
commit
a6a543bfa8
|
|
@ -1,3 +1,17 @@
|
||||||
|
2015-03-03 Jan Hubicka <hubicka@ucw.cz>
|
||||||
|
|
||||||
|
* cgraph.c (cgraph_node::can_remove_if_no_direct_calls_p): Rewrite
|
||||||
|
for correct comdat handling.
|
||||||
|
(cgraph_node::will_be_removed_from_program_if_no_direct_calls_p):
|
||||||
|
Likewise.
|
||||||
|
* cgraph.h (call_for_symbol_and_aliases): Fix formating.
|
||||||
|
(used_from_object_file_p_worker): Remove.
|
||||||
|
(cgraph_node::only_called_directly_or_alised): Add
|
||||||
|
used_from_object_file_p.
|
||||||
|
* ipa-inline-analysis.c (growth_likely_positive): Optimie.
|
||||||
|
* ipa-inline-transform.c (can_remove_node_now_p_1): Use
|
||||||
|
can_remove_if_no_direct_calls_and_refs_p.
|
||||||
|
|
||||||
2015-03-04 Nick Clifton <nickc@redhat.com>
|
2015-03-04 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
* config/rl78/rl78.h (enum reg_class): Remove real registers from
|
* config/rl78/rl78.h (enum reg_class): Remove real registers from
|
||||||
|
|
|
||||||
91
gcc/cgraph.c
91
gcc/cgraph.c
|
|
@ -2411,13 +2411,18 @@ nonremovable_p (cgraph_node *node, void *)
|
||||||
return !node->can_remove_if_no_direct_calls_and_refs_p ();
|
return !node->can_remove_if_no_direct_calls_and_refs_p ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true when function cgraph_node and its aliases can be removed from
|
/* Return true if whole comdat group can be removed if there are no direct
|
||||||
callgraph if all direct calls are eliminated. */
|
calls to THIS. */
|
||||||
|
|
||||||
bool
|
bool
|
||||||
cgraph_node::can_remove_if_no_direct_calls_p (void)
|
cgraph_node::can_remove_if_no_direct_calls_p (void)
|
||||||
{
|
{
|
||||||
/* Extern inlines can always go, we will use the external definition. */
|
struct ipa_ref *ref;
|
||||||
|
|
||||||
|
/* For local symbols or non-comdat group it is the same as
|
||||||
|
can_remove_if_no_direct_calls_p. */
|
||||||
|
if (!externally_visible || !same_comdat_group)
|
||||||
|
{
|
||||||
if (DECL_EXTERNAL (decl))
|
if (DECL_EXTERNAL (decl))
|
||||||
return true;
|
return true;
|
||||||
if (address_taken)
|
if (address_taken)
|
||||||
|
|
@ -2425,6 +2430,40 @@ cgraph_node::can_remove_if_no_direct_calls_p (void)
|
||||||
return !call_for_symbol_and_aliases (nonremovable_p, NULL, true);
|
return !call_for_symbol_and_aliases (nonremovable_p, NULL, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Otheriwse check if we can remove the symbol itself and then verify
|
||||||
|
that only uses of the comdat groups are direct call to THIS
|
||||||
|
or its aliases. */
|
||||||
|
if (!can_remove_if_no_direct_calls_and_refs_p ())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Check that all refs come from within the comdat group. */
|
||||||
|
for (int i = 0; iterate_referring (i, ref); i++)
|
||||||
|
if (ref->referring->get_comdat_group () != get_comdat_group ())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
struct cgraph_node *target = ultimate_alias_target ();
|
||||||
|
for (cgraph_node *next = dyn_cast<cgraph_node *> (same_comdat_group);
|
||||||
|
next != this; next = dyn_cast<cgraph_node *> (next->same_comdat_group))
|
||||||
|
{
|
||||||
|
if (!externally_visible)
|
||||||
|
continue;
|
||||||
|
if (!next->alias
|
||||||
|
&& !next->can_remove_if_no_direct_calls_and_refs_p ())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* If we see different symbol than THIS, be sure to check calls. */
|
||||||
|
if (next->ultimate_alias_target () != target)
|
||||||
|
for (cgraph_edge *e = next->callers; e; e = e->next_caller)
|
||||||
|
if (e->caller->get_comdat_group () != get_comdat_group ())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; next->iterate_referring (i, ref); i++)
|
||||||
|
if (ref->referring->get_comdat_group () != get_comdat_group ())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return true when function cgraph_node can be expected to be removed
|
/* Return true when function cgraph_node can be expected to be removed
|
||||||
from program when direct calls in this compilation unit are removed.
|
from program when direct calls in this compilation unit are removed.
|
||||||
|
|
||||||
|
|
@ -2442,20 +2481,48 @@ cgraph_node::can_remove_if_no_direct_calls_p (void)
|
||||||
bool
|
bool
|
||||||
cgraph_node::will_be_removed_from_program_if_no_direct_calls_p (void)
|
cgraph_node::will_be_removed_from_program_if_no_direct_calls_p (void)
|
||||||
{
|
{
|
||||||
|
struct ipa_ref *ref;
|
||||||
gcc_assert (!global.inlined_to);
|
gcc_assert (!global.inlined_to);
|
||||||
|
|
||||||
if (call_for_symbol_and_aliases (used_from_object_file_p_worker,
|
|
||||||
NULL, true))
|
|
||||||
return false;
|
|
||||||
if (!in_lto_p && !flag_whole_program)
|
|
||||||
return only_called_directly_p ();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (DECL_EXTERNAL (decl))
|
if (DECL_EXTERNAL (decl))
|
||||||
return true;
|
return true;
|
||||||
return can_remove_if_no_direct_calls_p ();
|
|
||||||
|
if (!in_lto_p && !flag_whole_program)
|
||||||
|
{
|
||||||
|
/* If the symbol is in comdat group, we need to verify that whole comdat
|
||||||
|
group becomes unreachable. Technically we could skip references from
|
||||||
|
within the group, too. */
|
||||||
|
if (!only_called_directly_p ())
|
||||||
|
return false;
|
||||||
|
if (same_comdat_group && externally_visible)
|
||||||
|
{
|
||||||
|
struct cgraph_node *target = ultimate_alias_target ();
|
||||||
|
for (cgraph_node *next = dyn_cast<cgraph_node *> (same_comdat_group);
|
||||||
|
next != this;
|
||||||
|
next = dyn_cast<cgraph_node *> (next->same_comdat_group))
|
||||||
|
{
|
||||||
|
if (!externally_visible)
|
||||||
|
continue;
|
||||||
|
if (!next->alias
|
||||||
|
&& !next->only_called_directly_p ())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* If we see different symbol than THIS,
|
||||||
|
be sure to check calls. */
|
||||||
|
if (next->ultimate_alias_target () != target)
|
||||||
|
for (cgraph_edge *e = next->callers; e; e = e->next_caller)
|
||||||
|
if (e->caller->get_comdat_group () != get_comdat_group ())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; next->iterate_referring (i, ref); i++)
|
||||||
|
if (ref->referring->get_comdat_group () != get_comdat_group ())
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return can_remove_if_no_direct_calls_p ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Worker for cgraph_only_called_directly_p. */
|
/* Worker for cgraph_only_called_directly_p. */
|
||||||
|
|
|
||||||
|
|
@ -1187,12 +1187,6 @@ public:
|
||||||
returns cgraph_node::get (DECL). */
|
returns cgraph_node::get (DECL). */
|
||||||
static cgraph_node * create_same_body_alias (tree alias, tree decl);
|
static cgraph_node * create_same_body_alias (tree alias, tree decl);
|
||||||
|
|
||||||
/* Worker for cgraph_can_remove_if_no_direct_calls_p. */
|
|
||||||
static bool used_from_object_file_p_worker (cgraph_node *node, void *)
|
|
||||||
{
|
|
||||||
return node->used_from_object_file_p ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify whole cgraph structure. */
|
/* Verify whole cgraph structure. */
|
||||||
static void DEBUG_FUNCTION verify_cgraph_nodes (void);
|
static void DEBUG_FUNCTION verify_cgraph_nodes (void);
|
||||||
|
|
||||||
|
|
@ -2736,6 +2730,7 @@ cgraph_node::only_called_directly_or_aliased_p (void)
|
||||||
&& !DECL_VIRTUAL_P (decl)
|
&& !DECL_VIRTUAL_P (decl)
|
||||||
&& !DECL_STATIC_CONSTRUCTOR (decl)
|
&& !DECL_STATIC_CONSTRUCTOR (decl)
|
||||||
&& !DECL_STATIC_DESTRUCTOR (decl)
|
&& !DECL_STATIC_DESTRUCTOR (decl)
|
||||||
|
&& !used_from_object_file_p ()
|
||||||
&& !externally_visible);
|
&& !externally_visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4007,6 +4007,8 @@ growth_likely_positive (struct cgraph_node *node,
|
||||||
struct cgraph_edge *e;
|
struct cgraph_edge *e;
|
||||||
gcc_checking_assert (edge_growth > 0);
|
gcc_checking_assert (edge_growth > 0);
|
||||||
|
|
||||||
|
if (DECL_EXTERNAL (node->decl))
|
||||||
|
return true;
|
||||||
/* Unlike for functions called once, we play unsafe with
|
/* Unlike for functions called once, we play unsafe with
|
||||||
COMDATs. We can allow that since we know functions
|
COMDATs. We can allow that since we know functions
|
||||||
in consideration are small (and thus risk is small) and
|
in consideration are small (and thus risk is small) and
|
||||||
|
|
@ -4014,18 +4016,13 @@ growth_likely_positive (struct cgraph_node *node,
|
||||||
functions may or may not disappear when eliminated from
|
functions may or may not disappear when eliminated from
|
||||||
current unit. With good probability making aggressive
|
current unit. With good probability making aggressive
|
||||||
choice in all units is going to make overall program
|
choice in all units is going to make overall program
|
||||||
smaller.
|
smaller. */
|
||||||
|
if (DECL_COMDAT (node->decl))
|
||||||
Consequently we ask cgraph_can_remove_if_no_direct_calls_p
|
{
|
||||||
instead of
|
if (!node->can_remove_if_no_direct_calls_p ())
|
||||||
cgraph_will_be_removed_from_program_if_no_direct_calls */
|
|
||||||
if (DECL_EXTERNAL (node->decl)
|
|
||||||
|| !node->can_remove_if_no_direct_calls_p ())
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (!node->will_be_removed_from_program_if_no_direct_calls_p ()
|
else if (!node->will_be_removed_from_program_if_no_direct_calls_p ())
|
||||||
&& (!DECL_COMDAT (node->decl)
|
|
||||||
|| !node->can_remove_if_no_direct_calls_p ()))
|
|
||||||
return true;
|
return true;
|
||||||
max_callers = inline_summaries->get (node)->size * 4 / edge_growth + 2;
|
max_callers = inline_summaries->get (node)->size * 4 / edge_growth + 2;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -112,9 +112,12 @@ can_remove_node_now_p_1 (struct cgraph_node *node, struct cgraph_edge *e)
|
||||||
}
|
}
|
||||||
/* FIXME: When address is taken of DECL_EXTERNAL function we still
|
/* FIXME: When address is taken of DECL_EXTERNAL function we still
|
||||||
can remove its offline copy, but we would need to keep unanalyzed node in
|
can remove its offline copy, but we would need to keep unanalyzed node in
|
||||||
the callgraph so references can point to it. */
|
the callgraph so references can point to it.
|
||||||
|
|
||||||
|
Also for comdat group we can ignore references inside a group as we
|
||||||
|
want to prove the group as a whole to be dead. */
|
||||||
return (!node->address_taken
|
return (!node->address_taken
|
||||||
&& node->can_remove_if_no_direct_calls_p ()
|
&& node->can_remove_if_no_direct_calls_and_refs_p ()
|
||||||
/* Inlining might enable more devirtualizing, so we want to remove
|
/* Inlining might enable more devirtualizing, so we want to remove
|
||||||
those only after all devirtualizable virtual calls are processed.
|
those only after all devirtualizable virtual calls are processed.
|
||||||
Lacking may edges in callgraph we just preserve them post
|
Lacking may edges in callgraph we just preserve them post
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue