]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
ipa-devirt.c (subbinfo_with_vtable_at_offset, [...]): New functions.
authorJan Hubicka <hubicka@gcc.gnu.org>
Mon, 3 Feb 2014 00:24:52 +0000 (00:24 +0000)
committerJan Hubicka <hubicka@gcc.gnu.org>
Mon, 3 Feb 2014 00:24:52 +0000 (00:24 +0000)
* ipa-devirt.c (subbinfo_with_vtable_at_offset,
vtable_pointer_value_to_binfo): New functions.
* ipa-utils.h (vtable_pointer_value_to_binfo): Declare.
* ipa-prop.c (extr_type_from_vtbl_ptr_store): Use it.
* g++.dg/ipa/devirt-23.C: New testcase.
* g++.dg/ipa/devirt-20.C: Fix template.

From-SVN: r207413

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

index b08ccc98087f85df6de4b575e6d4fc188606939d..39e69d378d0dd5153ec812da839ff150130e553e 100644 (file)
@@ -1,3 +1,10 @@
+2014-02-02  Jan Hubicka  <jh@suse.cz>
+
+       * ipa-devirt.c (subbinfo_with_vtable_at_offset,
+       vtable_pointer_value_to_binfo): New functions.
+       * ipa-utils.h (vtable_pointer_value_to_binfo): Declare.
+       * ipa-prop.c (extr_type_from_vtbl_ptr_store): Use it.
+
 2014-02-02  Sandra Loosemore  <sandra@codesourcery.com>
 
        * config/nios2/nios2.md (load_got_register): Initialize GOT
index fb03dd2618d15f9d7bcc1fecebdfb3d275c31444..dcaebdf8659346d41ab5d4fd0ba212234c4f3d4c 100644 (file)
@@ -972,6 +972,70 @@ contains_type_p (tree outer_type, HOST_WIDE_INT offset,
   return get_class_context (&context, otr_type);
 }
 
+/* Lookup base of BINFO that has virtual table VTABLE with OFFSET.  */
+
+static tree
+subbinfo_with_vtable_at_offset (tree binfo, tree offset, tree vtable)
+{
+  tree v = BINFO_VTABLE (binfo);
+  int i;
+  tree base_binfo;
+
+  gcc_assert (!v || TREE_CODE (v) == POINTER_PLUS_EXPR);
+  
+  if (v && tree_int_cst_equal (TREE_OPERAND (v, 1), offset)
+      && TREE_OPERAND (TREE_OPERAND (v, 0), 0) == vtable)
+    return binfo;
+  for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+    if (polymorphic_type_binfo_p (base_binfo))
+      {
+       base_binfo = subbinfo_with_vtable_at_offset (base_binfo, offset, vtable);
+       if (base_binfo)
+         return base_binfo;
+      }
+  return NULL;
+}
+
+/* T is known constant value of virtual table pointer.  Return BINFO of the
+   instance type.  */
+
+tree
+vtable_pointer_value_to_binfo (tree t)
+{
+  /* We expect &MEM[(void *)&virtual_table + 16B].
+     We obtain object's BINFO from the context of the virtual table. 
+     This one contains pointer to virtual table represented via
+     POINTER_PLUS_EXPR.  Verify that this pointer match to what
+     we propagated through.
+
+     In the case of virtual inheritance, the virtual tables may
+     be nested, i.e. the offset may be different from 16 and we may
+     need to dive into the type representation.  */
+  if (t && TREE_CODE (t) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (t, 0)) == MEM_REF
+      && TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 0)) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 1)) == INTEGER_CST
+      && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (t, 0), 0), 0))
+         == VAR_DECL)
+      && DECL_VIRTUAL_P (TREE_OPERAND (TREE_OPERAND
+                                        (TREE_OPERAND (t, 0), 0), 0)))
+    {
+      tree vtable = TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (t, 0), 0), 0);
+      tree offset = TREE_OPERAND (TREE_OPERAND (t, 0), 1);
+      tree binfo = TYPE_BINFO (DECL_CONTEXT (vtable));
+
+      binfo = subbinfo_with_vtable_at_offset (binfo, offset, vtable);
+
+      /* FIXME: for stores of construction vtables we return NULL,
+        because we do not have BINFO for those. Eventually we should fix
+        our representation to allow this case to be handled, too.
+        In the case we see store of BINFO we however may assume
+        that standard folding will be ale to cope with it.  */
+      return binfo;
+    }
+  return NULL;
+}
+
 /* 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  */
index f8a1ca4f3d448cbcf6cec942dd3631e2a1190c8e..3024414ab8ac5ed73eaea0bda6181d4e87d6c8cb 100644 (file)
@@ -591,7 +591,7 @@ static tree
 extr_type_from_vtbl_ptr_store (gimple stmt, struct type_change_info *tci)
 {
   HOST_WIDE_INT offset, size, max_size;
-  tree lhs, rhs, base;
+  tree lhs, rhs, base, binfo;
 
   if (!gimple_assign_single_p (stmt))
     return NULL_TREE;
@@ -599,13 +599,7 @@ extr_type_from_vtbl_ptr_store (gimple stmt, struct type_change_info *tci)
   lhs = gimple_assign_lhs (stmt);
   rhs = gimple_assign_rhs1 (stmt);
   if (TREE_CODE (lhs) != COMPONENT_REF
-      || !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1))
-      || TREE_CODE (rhs) != ADDR_EXPR)
-    return NULL_TREE;
-  rhs = get_base_address (TREE_OPERAND (rhs, 0));
-  if (!rhs
-      || TREE_CODE (rhs) != VAR_DECL
-      || !DECL_VIRTUAL_P (rhs))
+      || !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1)))
     return NULL_TREE;
 
   base = get_ref_base_and_extent (lhs, &offset, &size, &max_size);
@@ -624,7 +618,16 @@ extr_type_from_vtbl_ptr_store (gimple stmt, struct type_change_info *tci)
   else if (tci->object != base)
     return NULL_TREE;
 
-  return DECL_CONTEXT (rhs);
+  binfo = vtable_pointer_value_to_binfo (rhs);
+
+  /* FIXME: vtable_pointer_value_to_binfo may return BINFO of a
+     base of outer type.  In this case we would need to either
+     work on binfos or translate it back to outer type and offset.
+     KNOWN_TYPE jump functions are not ready for that, yet.  */
+  if (!binfo || TYPE_BINFO (BINFO_TYPE (binfo)) != binfo)
+   return NULL;
+
+  return BINFO_TYPE (binfo);
 }
 
 /* Callback of walk_aliased_vdefs and a helper function for
index 8e32fb22d5fa3c19c3a04398f41d096912302860..3212f38cc4c04cdac0ea02286b6191920ec72571 100644 (file)
@@ -87,6 +87,7 @@ tree method_class_type (tree);
 tree get_polymorphic_call_info (tree, tree, tree *,
                                HOST_WIDE_INT *,
                                ipa_polymorphic_call_context *);
+tree vtable_pointer_value_to_binfo (tree t);
 
 /* Return vector containing possible targets of polymorphic call E.
    If FINALP is non-NULL, store true if the list is complette. 
index 0e17c17166a63ff30bbaba8934275e3e35a9d0b6..284b5bbd52e8765b391cf8cf0b06584c6174a00e 100644 (file)
@@ -1,6 +1,11 @@
 2014-02-02  Jan Hubicka  <hubicka@ucw.cz>
 
        * g++.dg/ipa/devirt-23.C: New testcase.
+       * g++.dg/ipa/devirt-20.C: Fix template.
+
+2014-02-02  Jan Hubicka  <jh@suse.cz>
+
+       * g++.dg/ipa/devirt-21.C: New testcase.
 
 2014-02-02  Richard Sandiford  <rdsandiford@googlemail.com>
 
index aee95147a6348c59f99f2e23ca4cf9778ac56554..0ea245bafdf4ed6508738347b4f6c6d8b120a1ca 100644 (file)
@@ -28,4 +28,4 @@ main(void)
   return 0;
 }
 /* { dg-final { scan-tree-dump-not "abort" "release_ssa"  } } */
-/* { dg-final { cleanup-ipa-dump "release_ssa" } } */
+/* { dg-final { cleanup-tree-dump "release_ssa" } } */
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-23.C b/gcc/testsuite/g++.dg/ipa/devirt-23.C
new file mode 100644 (file)
index 0000000..a32c7d6
--- /dev/null
@@ -0,0 +1,49 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-partial-inlining -fdump-ipa-cp -fno-devirtualize-speculatively"  } */
+/* Main purpose is to verify that we do not produce wrong devirtualization to
+   C::m_fn1.  We currently devirtualize to B::m_fn1, so check that. */
+#include <stdlib.h>
+class A {
+public:
+  unsigned length;
+};
+class B {};
+class MultiTermDocs : public virtual B {
+protected:
+  A readerTermDocs;
+  A subReaders;
+  virtual B *m_fn1(int *) {}
+  virtual inline  ~MultiTermDocs();
+  inline void wrap(void)
+  {
+  m_fn1(NULL);
+  m_fn1(NULL);
+  m_fn1(NULL);
+  m_fn1(NULL);
+  m_fn1(NULL);
+  m_fn1(NULL);
+  m_fn1(NULL);
+  m_fn1(NULL);
+  m_fn1(NULL);
+  }
+};
+class C : MultiTermDocs {
+  B *m_fn1(int *);
+};
+MultiTermDocs::~MultiTermDocs() {
+  wrap ();
+  if (&readerTermDocs) {
+    B *a;
+    for (unsigned i = 0; i < subReaders.length; i++)
+      (a != 0);
+  }
+}
+
+B *C::m_fn1(int *) { abort (); }
+
+main()
+{
+  class C c;
+}
+/* { dg-final { scan-ipa-dump "Discovered a virtual call to" "cp" } } */
+/* { dg-final { cleanup-ipa-dump "cp" } } */