Commit 390675c8 by Jan Hubicka

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
parent 06fcf6c1
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
......
......@@ -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 */
......
......@@ -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
......
......@@ -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.
......
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>
......
......@@ -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" } } */
/* { 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" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment