aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJan Hubicka <hubicka@ucw.cz>2015-03-04 21:28:08 +0100
committerJan Hubicka <hubicka@gcc.gnu.org>2015-03-04 20:28:08 +0000
commita6a543bfa860d89ca4fb5734233ede5796b10103 (patch)
tree2724c9b62285c2c1dc7ecae0dea0d9cc465c8847 /gcc
parentd720e658eba57e78e8493d9126921bd4f07130b0 (diff)
downloadgcc-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')
-rw-r--r--gcc/ChangeLog14
-rw-r--r--gcc/cgraph.c97
-rw-r--r--gcc/cgraph.h11
-rw-r--r--gcc/ipa-inline-analysis.c21
-rw-r--r--gcc/ipa-inline-transform.c7
5 files changed, 113 insertions, 37 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 27c712b..db131ee 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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>
* config/rl78/rl78.h (enum reg_class): Remove real registers from
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 ();
}
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 82519fa..c4f39ba 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 7a9c99c..d747163 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 38a98db..43bb41f 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