diff options
author | Jan Hubicka <jh@suse.cz> | 2013-08-23 17:29:04 +0200 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2013-08-23 15:29:04 +0000 |
commit | c4be65686206f422b2a3401b2e18bccf830984f4 (patch) | |
tree | 78fe4a2ac0c8d109d78cc2ce1774d010681a43d7 /gcc/cgraphunit.c | |
parent | 97aba8e901b999e49a988ace67dfa8c06ba364ac (diff) | |
download | gcc-c4be65686206f422b2a3401b2e18bccf830984f4.zip gcc-c4be65686206f422b2a3401b2e18bccf830984f4.tar.gz gcc-c4be65686206f422b2a3401b2e18bccf830984f4.tar.bz2 |
devirt-13.C: New testcase.
* g++.dg/ipa/devirt-13.C: New testcase.
* g++.dg/ipa/devirt-14.C: New testcase.
* cgraphunit.c (analyze_functions): Do basic devirtualization;
do not walk base classes of anonymous types.
From-SVN: r201942
Diffstat (limited to 'gcc/cgraphunit.c')
-rw-r--r-- | gcc/cgraphunit.c | 87 |
1 files changed, 67 insertions, 20 deletions
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 0b839b0..db3db4b 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -922,26 +922,73 @@ analyze_functions (void) enqueue_node ((symtab_node)edge->callee); if (optimize && flag_devirtualize) { - for (edge = cnode->indirect_calls; edge; edge = edge->next_callee) - if (edge->indirect_info->polymorphic) - { - unsigned int i; - void *cache_token; - vec <cgraph_node *>targets - = possible_polymorphic_call_targets - (edge, NULL, &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++) - enqueue_node ((symtab_node) targets[i]); - } - } + struct cgraph_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); + } + } + } + } + } } /* If decl is a clone of an abstract function, |