aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <hubicka@gcc.gnu.org>2014-02-03 00:24:52 +0000
committerJan Hubicka <hubicka@gcc.gnu.org>2014-02-03 00:24:52 +0000
commit390675c87ddc147b6d1982824b329e119ae5148b (patch)
tree76bd028dd2a79384d67f52b8ff5e5cbe8b093dfa
parent06fcf6c19c42b104bb0e8598c9f9f8cbd4a8b8c7 (diff)
downloadgcc-390675c87ddc147b6d1982824b329e119ae5148b.zip
gcc-390675c87ddc147b6d1982824b329e119ae5148b.tar.gz
gcc-390675c87ddc147b6d1982824b329e119ae5148b.tar.bz2
ipa-devirt.c (subbinfo_with_vtable_at_offset, [...]): New functions.
* 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
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/ipa-devirt.c64
-rw-r--r--gcc/ipa-prop.c21
-rw-r--r--gcc/ipa-utils.h1
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-20.C2
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-23.C49
7 files changed, 139 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b08ccc9..39e69d3 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index fb03dd2..dcaebdf 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -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 */
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index f8a1ca4..3024414 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -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
diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h
index 8e32fb2..3212f38 100644
--- a/gcc/ipa-utils.h
+++ b/gcc/ipa-utils.h
@@ -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.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 0e17c17..284b5bb 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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>
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-20.C b/gcc/testsuite/g++.dg/ipa/devirt-20.C
index aee9514..0ea245b 100644
--- a/gcc/testsuite/g++.dg/ipa/devirt-20.C
+++ b/gcc/testsuite/g++.dg/ipa/devirt-20.C
@@ -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
index 0000000..a32c7d6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/devirt-23.C
@@ -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" } } */