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 | |
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')
-rw-r--r-- | gcc/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/cgraphunit.c | 87 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ipa/devirt-13.C | 22 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ipa/devirt-14.C | 34 |
5 files changed, 133 insertions, 20 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 07d70ee..76609fb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2013-08-23 Jan Hubicka <jh@suse.cz> + + * cgraphunit.c (analyze_functions): Do basic devirtualization; + do not walk base classes of anonymous types. + 2013-08-23 Kaz Kojima <kkojima@gcc.gnu.org> PR rtl-optimization/58220 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, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index db1c984..47196da 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2013-08-23 Jan Hubicka <jh@suse.cz> + + * g++.dg/ipa/devirt-13.C: New testcase. + * g++.dg/ipa/devirt-14.C: New testcase. + 2013-08-23 Jakub Jelinek <jakub@redhat.com> PR target/58218 diff --git a/gcc/testsuite/g++.dg/ipa/devirt-13.C b/gcc/testsuite/g++.dg/ipa/devirt-13.C new file mode 100644 index 0000000..13fbaee --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/devirt-13.C @@ -0,0 +1,22 @@ +/* { dg-do run } */ +/* Call to foo should be devirtualized because there are no derived types of A. */ +/* { dg-options "-O2 -fdump-ipa-cgraph -fdump-tree-ssa" } */ +namespace { +class A { +public: + virtual int foo(void) +{ + return 0; +} +}; +} +class A a, *b=&a; +main() +{ + return b->foo(); +} + +/* { dg-final { scan-ipa-dump "Devirtualizing call" "cgraph" } } */ +/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "ssa"} } */ +/* { dg-final { cleanup-ipa-dump "cgraph" } } */ +/* { dg-final { cleanup-tree-dump "ssa" } } */ diff --git a/gcc/testsuite/g++.dg/ipa/devirt-14.C b/gcc/testsuite/g++.dg/ipa/devirt-14.C new file mode 100644 index 0000000..1a87c25 --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/devirt-14.C @@ -0,0 +1,34 @@ +/* No devirtualization happens here, but A::foo should not end up as reachable + because the constructor of A is unreachable and therefore the virtual + method table referring to A::foo is optimized out. */ +/* { dg-do run } */ +/* { dg-options "-O2 -fdump-tree-ssa" } */ +class B { +public: + virtual int foo(void) +{ + return 0; +} +}; +namespace { +class A : public B { +public: + virtual int foo(void) +{ + return 1; +} +}; +} +class B a, *b=&a; +main() +{ + if (0) + { + class A a; + a.foo(); + } + return b->foo(); +} + +/* { dg-final { scan-tree-dump-nop "A::foo" 0 "ssa"} } */ +/* { dg-final { cleanup-tree-dump "ssa" } } */ |