diff options
author | Jan Hubicka <hubicka@ucw.cz> | 2015-03-04 21:28:08 +0100 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2015-03-04 20:28:08 +0000 |
commit | a6a543bfa860d89ca4fb5734233ede5796b10103 (patch) | |
tree | 2724c9b62285c2c1dc7ecae0dea0d9cc465c8847 /gcc/cgraph.c | |
parent | d720e658eba57e78e8493d9126921bd4f07130b0 (diff) | |
download | gcc-a6a543bfa860d89ca4fb5734233ede5796b10103.zip gcc-a6a543bfa860d89ca4fb5734233ede5796b10103.tar.gz gcc-a6a543bfa860d89ca4fb5734233ede5796b10103.tar.bz2 |
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
Diffstat (limited to 'gcc/cgraph.c')
-rw-r--r-- | gcc/cgraph.c | 97 |
1 files changed, 82 insertions, 15 deletions
diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 9bae35e..b2109bd 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -2411,18 +2411,57 @@ nonremovable_p (cgraph_node *node, void *) return !node->can_remove_if_no_direct_calls_and_refs_p (); } -/* Return true when function cgraph_node and its aliases can be removed from - callgraph if all direct calls are eliminated. */ +/* Return true if whole comdat group can be removed if there are no direct + calls to THIS. */ bool cgraph_node::can_remove_if_no_direct_calls_p (void) { - /* Extern inlines can always go, we will use the external definition. */ - if (DECL_EXTERNAL (decl)) - return true; - if (address_taken) + 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)) + return true; + if (address_taken) + return false; + 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; - return !call_for_symbol_and_aliases (nonremovable_p, NULL, true); + + /* 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 @@ -2442,19 +2481,47 @@ cgraph_node::can_remove_if_no_direct_calls_p (void) bool cgraph_node::will_be_removed_from_program_if_no_direct_calls_p (void) { + struct ipa_ref *ref; gcc_assert (!global.inlined_to); + if (DECL_EXTERNAL (decl)) + return true; - 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)) - return true; - return can_remove_if_no_direct_calls_p (); + /* 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 (); } |