ipa-cp.c (ipa_get_indirect_edge_target_1): Do direct lookup via vtable pointer...
authorJan Hubicka <jh@suse.cz>
Tue, 4 Feb 2014 05:40:21 +0000 (06:40 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Tue, 4 Feb 2014 05:40:21 +0000 (05:40 +0000)
* ipa-cp.c (ipa_get_indirect_edge_target_1): Do direct
lookup via vtable pointer; check for type consistency
and turn inconsitent facts into UNREACHABLE.
* ipa-prop.c (try_make_edge_direct_virtual_call): Likewise.
* gimple-fold.c (gimple_get_virt_method_for_vtable):
Do not ICE on type inconsistent querries; return UNREACHABLE
instead.

* testsuite/g++.dg/ipa/devirt-25.C: New testcase.

From-SVN: r207448

gcc/ChangeLog
gcc/ipa-cp.c
gcc/ipa-devirt.c
gcc/ipa-prop.c
gcc/ipa-utils.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ipa/devirt-22.C [new file with mode: 0644]

index 4baab8e..c4c197a 100644 (file)
@@ -1,5 +1,16 @@
 2014-02-03  Jan Hubicka  <jh@suse.cz>
 
+       PR ipa/59831
+       * ipa-cp.c (ipa_get_indirect_edge_target_1): Use ipa-devirt
+       to figure out targets of polymorphic calls with known decl.
+       * ipa-prop.c (try_make_edge_direct_virtual_call): Likewise.
+       * ipa-utils.h (get_polymorphic_call_info_from_invariant): Declare.
+       * ipa-devirt.c (get_polymorphic_call_info_for_decl): Break out from ...
+       (get_polymorphic_call_info): ... here.
+       (get_polymorphic_call_info_from_invariant): New function.
+
+2014-02-03  Jan Hubicka  <jh@suse.cz>
+
        * ipa-cp.c (ipa_get_indirect_edge_target_1): Do direct
        lookup via vtable pointer; check for type consistency
        and turn inconsitent facts into UNREACHABLE.
index e210176..68afeb0 100644 (file)
@@ -1601,15 +1601,24 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
 
   if (TREE_CODE (t) != TREE_BINFO)
     {
-      tree binfo;
-      binfo = gimple_extract_devirt_binfo_from_cst
-                (t, ie->indirect_info->otr_type);
-      if (!binfo)
+      ipa_polymorphic_call_context context;
+      vec <cgraph_node *>targets;
+      bool final;
+
+      if (!get_polymorphic_call_info_from_invariant
+            (&context, t, ie->indirect_info->otr_type,
+             anc_offset))
        return NULL_TREE;
-      binfo = get_binfo_at_offset (binfo, anc_offset, otr_type);
-      if (!binfo)
+      targets = possible_polymorphic_call_targets
+                (ie->indirect_info->otr_type,
+                 ie->indirect_info->otr_token,
+                 context, &final);
+      if (!final || targets.length () > 1)
        return NULL_TREE;
-      target = gimple_get_virt_method_for_binfo (token, binfo);
+      if (targets.length () == 1)
+       target = targets[0]->decl;
+      else
+       target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
     }
   else
     {
index fb9c666..f137874 100644 (file)
@@ -1071,6 +1071,60 @@ vtable_pointer_value_to_binfo (tree t)
                                         offset, vtable);
 }
 
+/* Proudce polymorphic call context for call method of instance
+   that is located within BASE (that is assumed to be a decl) at OFFSET. */
+
+static void
+get_polymorphic_call_info_for_decl (ipa_polymorphic_call_context *context,
+                                   tree base, HOST_WIDE_INT offset)
+{
+  gcc_assert (DECL_P (base));
+
+  context->outer_type = TREE_TYPE (base);
+  context->offset = offset;
+  /* Make very conservative assumption that all objects
+     may be in construction. 
+     TODO: ipa-prop already contains code to tell better. 
+     merge it later.  */
+  context->maybe_in_construction = true;
+  context->maybe_derived_type = false;
+}
+
+/* CST is an invariant (address of decl), try to get meaningful
+   polymorphic call context for polymorphic call of method 
+   if instance of OTR_TYPE that is located at OFFSET of this invariant.
+   Return FALSE if nothing meaningful can be found.  */
+
+bool
+get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *context,
+                                         tree cst,
+                                         tree otr_type,
+                                         HOST_WIDE_INT offset)
+{
+  HOST_WIDE_INT offset2, size, max_size;
+  tree base;
+
+  if (TREE_CODE (cst) != ADDR_EXPR)
+    return NULL_TREE;
+
+  cst = TREE_OPERAND (cst, 0);
+  base = get_ref_base_and_extent (cst, &offset2, &size, &max_size);
+  if (!DECL_P (base)
+      || max_size == -1
+      || max_size != size)
+    return NULL_TREE;
+
+  /* Only type inconsistent programs can have otr_type that is
+     not part of outer type.  */
+  if (!contains_type_p (TREE_TYPE (base),
+                       offset, otr_type))
+    return NULL_TREE;
+
+  get_polymorphic_call_info_for_decl (context,
+                                    base, offset);
+  return true;
+}
+
 /* Given REF call in FNDECL, determine class of the polymorphic
    call (OTR_TYPE), its token (OTR_TOKEN) and CONTEXT.
    Return pointer to object described by the context  */
@@ -1136,14 +1190,8 @@ get_polymorphic_call_info (tree fndecl,
                  if (!contains_type_p (TREE_TYPE (base),
                                        context->offset + offset2, *otr_type))
                    return base_pointer;
-                 context->outer_type = TREE_TYPE (base);
-                 context->offset += offset2;
-                 /* Make very conservative assumption that all objects
-                    may be in construction. 
-                    TODO: ipa-prop already contains code to tell better. 
-                    merge it later.  */
-                 context->maybe_in_construction = true;
-                 context->maybe_derived_type = false;
+                 get_polymorphic_call_info_for_decl (context, base,
+                                                     context->offset + offset2);
                  return NULL;
                }
              else
index 39c01c5..69566e9 100644 (file)
@@ -2731,19 +2731,38 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
 
   if (TREE_CODE (binfo) != TREE_BINFO)
     {
-      binfo = gimple_extract_devirt_binfo_from_cst
-                (binfo, ie->indirect_info->otr_type);
-      if (!binfo)
+      ipa_polymorphic_call_context context;
+      vec <cgraph_node *>targets;
+      bool final;
+
+      if (!get_polymorphic_call_info_from_invariant
+            (&context, binfo, ie->indirect_info->otr_type,
+             ie->indirect_info->offset))
+       return NULL;
+      targets = possible_polymorphic_call_targets
+                (ie->indirect_info->otr_type,
+                 ie->indirect_info->otr_token,
+                 context, &final);
+      if (!final || targets.length () > 1)
        return NULL;
+      if (targets.length () == 1)
+       target = targets[0]->decl;
+      else
+       {
+          target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
+         cgraph_get_create_node (target);
+       }
     }
-
-  binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset,
-                              ie->indirect_info->otr_type);
-  if (binfo)
-    target = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token,
-                                              binfo);
   else
-    return NULL;
+    {
+      binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset,
+                                  ie->indirect_info->otr_type);
+      if (binfo)
+       target = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token,
+                                                  binfo);
+      else
+       return NULL;
+    }
 
   if (target)
     {
index 3f9be17..d595e8a 100644 (file)
@@ -87,6 +87,8 @@ tree method_class_type (tree);
 tree get_polymorphic_call_info (tree, tree, tree *,
                                HOST_WIDE_INT *,
                                ipa_polymorphic_call_context *);
+bool get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *,
+                                              tree, tree, HOST_WIDE_INT);
 tree vtable_pointer_value_to_binfo (tree t);
 bool vtable_pointer_value_to_vtable (tree, tree *, unsigned HOST_WIDE_INT *);
 
index 3a0c944..131b6c9 100644 (file)
@@ -1,5 +1,10 @@
 2014-02-03  Jan Hubicka  <jh@suse.cz>
 
+       PR ipa/59831
+       * g++.dg/ipa/devirt-22.C: New testcase.
+
+2014-02-03  Jan Hubicka  <jh@suse.cz>
+
        * g++.dg/ipa/devirt-25.C: New testcase.
 
 2014-02-04  Jakub Jelinek  <jakub@redhat.com>
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-22.C b/gcc/testsuite/g++.dg/ipa/devirt-22.C
new file mode 100644 (file)
index 0000000..8b8279a
--- /dev/null
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fno-early-inlining -fno-ipa-sra -fdump-ipa-cp"  } */
+class A {};
+class B {
+public:
+  A &operator[](int);
+};
+class C : B {
+public:
+  virtual int m_fn1() { return 0; }
+  A &operator[](int p1) {
+    int a;
+    a = m_fn1();
+    static_cast<void>(__builtin_expect(a, 0) ?: 0);
+    return B::operator[](p1);
+  }
+};
+
+C b;
+int *e;
+static void sort(C &p1, C &p2) {
+  for (int i=0;; i++) {
+    A c, d = p2[0];
+    p1[0] = c;
+    p2[0] = d;
+  }
+}
+
+void lookupSourceDone() { b[0]; }
+
+void update_sources() {
+  if (e) {
+    C f;
+    sort(f, b);
+  }
+}
+/* Note that we miss one devirtualization because we are not able to track the
+   vtbl store in destructor.  
+   Previously we devirtualized to C::m_fn1 instead of B::m_fn1.  */
+/* { dg-final { scan-tree-dump-times "Discovered a virtual call to a known target" 1 "cp"  } } */
+/* { dg-final { cleanup-ipa-dump "cp" } } */