From a6a543bfa860d89ca4fb5734233ede5796b10103 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 4 Mar 2015 21:28:08 +0100 Subject: [PATCH] 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 --- gcc/ChangeLog | 14 ++++++ gcc/cgraph.c | 97 ++++++++++++++++++++++++++++++++------ gcc/cgraph.h | 11 ++--- gcc/ipa-inline-analysis.c | 21 ++++----- gcc/ipa-inline-transform.c | 7 ++- 5 files changed, 113 insertions(+), 37 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 27c712b1453..db131ee7868 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2015-03-03 Jan Hubicka + + * 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 * config/rl78/rl78.h (enum reg_class): Remove real registers from diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 9bae35ebbee..b2109bd5172 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 (same_comdat_group); + next != this; next = dyn_cast (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 (same_comdat_group); + next != this; + next = dyn_cast (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 (); } diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 82519fa8a3e..c4f39bab4e1 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -258,8 +258,8 @@ public: When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are skipped. */ bool call_for_symbol_and_aliases (bool (*callback) (symtab_node *, void *), - void *data, - bool include_overwrite); + void *data, + bool include_overwrite); /* If node can not be interposable by static or dynamic linker to point to different definition, return this symbol. Otherwise look for alias with @@ -1187,12 +1187,6 @@ public: returns cgraph_node::get (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. */ 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_STATIC_CONSTRUCTOR (decl) && !DECL_STATIC_DESTRUCTOR (decl) + && !used_from_object_file_p () && !externally_visible); } diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c index 7a9c99cc512..d7471630617 100644 --- a/gcc/ipa-inline-analysis.c +++ b/gcc/ipa-inline-analysis.c @@ -4007,6 +4007,8 @@ growth_likely_positive (struct cgraph_node *node, struct cgraph_edge *e; gcc_checking_assert (edge_growth > 0); + if (DECL_EXTERNAL (node->decl)) + return true; /* Unlike for functions called once, we play unsafe with COMDATs. We can allow that since we know functions 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 current unit. With good probability making aggressive choice in all units is going to make overall program - smaller. - - Consequently we ask cgraph_can_remove_if_no_direct_calls_p - instead of - 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; - - if (!node->will_be_removed_from_program_if_no_direct_calls_p () - && (!DECL_COMDAT (node->decl) - || !node->can_remove_if_no_direct_calls_p ())) + smaller. */ + if (DECL_COMDAT (node->decl)) + { + if (!node->can_remove_if_no_direct_calls_p ()) + return true; + } + else if (!node->will_be_removed_from_program_if_no_direct_calls_p ()) return true; max_callers = inline_summaries->get (node)->size * 4 / edge_growth + 2; diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c index 38a98dbe43c..43bb41fa8fa 100644 --- a/gcc/ipa-inline-transform.c +++ b/gcc/ipa-inline-transform.c @@ -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 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 - && 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 those only after all devirtualizable virtual calls are processed. Lacking may edges in callgraph we just preserve them post -- 2.30.2