aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2013-08-23 17:29:04 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2013-08-23 15:29:04 +0000
commitc4be65686206f422b2a3401b2e18bccf830984f4 (patch)
tree78fe4a2ac0c8d109d78cc2ce1774d010681a43d7
parent97aba8e901b999e49a988ace67dfa8c06ba364ac (diff)
downloadgcc-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
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/cgraphunit.c87
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-13.C22
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-14.C34
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" } } */