cgraphunit.c (walk_polymorphic_call_targets): Break out from ...

* cgraphunit.c (walk_polymorphic_call_targets): Break out from ...
	(analyze_functions): ... here.

From-SVN: r202299
This commit is contained in:
Jan Hubicka 2013-09-06 01:06:10 +02:00 committed by Jan Hubicka
parent d352b2459f
commit e18412fc01
2 changed files with 79 additions and 62 deletions

View File

@ -1,3 +1,8 @@
2013-09-04 Jan Hubicka <jh@suse.cz>
* cgraphunit.c (walk_polymorphic_call_targets): Break out from ...
(analyze_functions): ... here.
2013-09-04 Jan Hubicka <jh@suse.cz>
PR middle-end/58201

View File

@ -821,6 +821,76 @@ varpool_finalize_decl (tree decl)
varpool_assemble_decl (node);
}
/* EDGE is an polymorphic call. Mark all possible targets as reachable
and if there is only one target, perform trivial devirtualization.
REACHABLE_CALL_TARGETS collects target lists we already walked to
avoid udplicate work. */
static void
walk_polymorphic_call_targets (pointer_set_t *reachable_call_targets,
struct cgraph_edge *edge)
{
unsigned int i;
void *cache_token;
bool final;
vec <cgraph_node *>targets
= possible_polymorphic_call_targets
(edge, &final, &cache_token);
if (!pointer_set_insert (reachable_call_targets,
cache_token))
{
if (cgraph_dump_file)
dump_possible_polymorphic_call_targets
(cgraph_dump_file, edge);
for (i = 0; i < targets.length(); i++)
{
/* Do not bother to mark virtual methods in anonymous namespace;
either we will find use of virtual table defining it, or it is
unused. */
if (targets[i]->symbol.definition
&& TREE_CODE
(TREE_TYPE (targets[i]->symbol.decl))
== METHOD_TYPE
&& !type_in_anonymous_namespace_p
(method_class_type
(TREE_TYPE (targets[i]->symbol.decl))))
enqueue_node ((symtab_node) targets[i]);
}
}
/* Very trivial devirtualization; when the type is
final or anonymous (so we know all its derivation)
and there is only one possible virtual call target,
make the edge direct. */
if (final)
{
gcc_assert (targets.length());
if (targets.length() == 1)
{
if (cgraph_dump_file)
{
fprintf (cgraph_dump_file,
"Devirtualizing call: ");
print_gimple_stmt (cgraph_dump_file,
edge->call_stmt, 0,
TDF_SLIM);
}
cgraph_make_edge_direct (edge, targets[0]);
cgraph_redirect_edge_call_stmt_to_callee (edge);
if (cgraph_dump_file)
{
fprintf (cgraph_dump_file,
"Devirtualized as: ");
print_gimple_stmt (cgraph_dump_file,
edge->call_stmt, 0,
TDF_SLIM);
}
}
}
}
/* Discover all functions and variables that are trivially needed, analyze
them as well as all functions and variables referred by them */
@ -923,71 +993,13 @@ analyze_functions (void)
if (optimize && flag_devirtualize)
{
struct cgraph_edge *next;
for (edge = cnode->indirect_calls; edge; edge = next)
for (edge = cnode->indirect_calls; edge; edge = next)
{
next = edge->next_callee;
if (edge->indirect_info->polymorphic)
{
unsigned int i;
void *cache_token;
bool final;
vec <cgraph_node *>targets
= possible_polymorphic_call_targets
(edge, &final, &cache_token);
if (!pointer_set_insert (reachable_call_targets,
cache_token))
{
if (cgraph_dump_file)
dump_possible_polymorphic_call_targets
(cgraph_dump_file, edge);
for (i = 0; i < targets.length(); i++)
{
/* Do not bother to mark virtual methods in anonymous namespace;
either we will find use of virtual table defining it, or it is
unused. */
if (targets[i]->symbol.definition
&& TREE_CODE
(TREE_TYPE (targets[i]->symbol.decl))
== METHOD_TYPE
&& !type_in_anonymous_namespace_p
(method_class_type
(TREE_TYPE (targets[i]->symbol.decl))))
enqueue_node ((symtab_node) targets[i]);
}
}
/* Very trivial devirtualization; when the type is
final or anonymous (so we know all its derivation)
and there is only one possible virtual call target,
make the edge direct. */
if (final)
{
gcc_assert (targets.length());
if (targets.length() == 1)
{
if (cgraph_dump_file)
{
fprintf (cgraph_dump_file,
"Devirtualizing call: ");
print_gimple_stmt (cgraph_dump_file,
edge->call_stmt, 0,
TDF_SLIM);
}
cgraph_make_edge_direct (edge, targets[0]);
cgraph_redirect_edge_call_stmt_to_callee (edge);
if (cgraph_dump_file)
{
fprintf (cgraph_dump_file,
"Devirtualized as: ");
print_gimple_stmt (cgraph_dump_file,
edge->call_stmt, 0,
TDF_SLIM);
}
}
}
}
walk_polymorphic_call_targets (reachable_call_targets,
edge);
}
}