+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
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 */
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;
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);
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
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.
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>
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" } } */
--- /dev/null
+/* { 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" } } */