devirt-13.C: New testcase.
authorJan Hubicka <jh@suse.cz>
Fri, 23 Aug 2013 15:29:04 +0000 (17:29 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Fri, 23 Aug 2013 15:29:04 +0000 (15:29 +0000)
* 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

gcc/ChangeLog
gcc/cgraphunit.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ipa/devirt-13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ipa/devirt-14.C [new file with mode: 0644]

index 07d70ee67cf55a9b2c108e40b8b299e1bb0896b1..76609fb7416229f4a60874e4c928138007945317 100644 (file)
@@ -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
index 0b839b06697e324f304bea424ce5e8f7228d86a6..db3db4bdef7c4100de357b99097abb86aee1faf5 100644 (file)
@@ -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,
index db1c984459c1b417a1826e808217bb9cef5ccac1..47196da050889b5c9dc720410b164ea990d3a05b 100644 (file)
@@ -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 (file)
index 0000000..13fbaee
--- /dev/null
@@ -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 (file)
index 0000000..1a87c25
--- /dev/null
@@ -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" } } */