ipa-cp.c (ipa_get_indirect_edge_target_1): Do direct lookup via vtable pointer...

* 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.

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

From-SVN: r207447
This commit is contained in:
Jan Hubicka 2014-02-04 04:42:37 +01:00 committed by Jan Hubicka
parent 4b076d8a4d
commit 9de2f554ec
6 changed files with 118 additions and 23 deletions

View File

@ -1,3 +1,13 @@
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.
* 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.
2014-02-03 Richard Henderson <rth@twiddle.net>
PR tree-opt/59924

View File

@ -3247,12 +3247,14 @@ gimple_get_virt_method_for_vtable (HOST_WIDE_INT token,
tree vtable = v, init, fn;
unsigned HOST_WIDE_INT size;
/* First of all double check we have virtual table. */
if (TREE_CODE (v) != VAR_DECL
|| !DECL_VIRTUAL_P (v))
return NULL_TREE;
init = ctor_for_folding (v);
/* The virtual tables should always be born with constructors.
/* The virtual tables should always be born with constructors
and we always should assume that they are avaialble for
folding. At the moment we do not stream them in all cases,
but it should never happen that ctor seem unreachable. */
@ -3266,21 +3268,31 @@ gimple_get_virt_method_for_vtable (HOST_WIDE_INT token,
size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (TREE_TYPE (v))));
offset *= BITS_PER_UNIT;
offset += token * size;
fn = fold_ctor_reference (TREE_TYPE (TREE_TYPE (v)), init,
offset, size, v);
if (!fn || integer_zerop (fn))
return NULL_TREE;
gcc_assert (TREE_CODE (fn) == ADDR_EXPR
|| TREE_CODE (fn) == FDESC_EXPR);
fn = TREE_OPERAND (fn, 0);
gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
/* When cgraph node is missing and function is not public, we cannot
devirtualize. This can happen in WHOPR when the actual method
ends up in other partition, because we found devirtualization
possibility too late. */
if (!can_refer_decl_in_current_unit_p (fn, vtable))
return NULL_TREE;
/* Do not pass from_decl here, we want to know even about values we can
not use and will check can_refer_decl_in_current_unit_p ourselves. */
fn = fold_ctor_reference (TREE_TYPE (TREE_TYPE (v)), init,
offset, size, NULL);
/* For type inconsistent program we may end up looking up virtual method
in virtual table that does not contain TOKEN entries. We may overrun
the virtual table and pick up a constant or RTTI info pointer.
In any case the call is undefined. */
if (!fn
|| (TREE_CODE (fn) != ADDR_EXPR && TREE_CODE (fn) != FDESC_EXPR)
|| TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL)
fn = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
else
{
fn = TREE_OPERAND (fn, 0);
/* When cgraph node is missing and function is not public, we cannot
devirtualize. This can happen in WHOPR when the actual method
ends up in other partition, because we found devirtualization
possibility too late. */
if (!can_refer_decl_in_current_unit_p (fn, vtable))
return NULL_TREE;
}
/* Make sure we create a cgraph node for functions we'll reference.
They can be non-existent if the reference comes from an entry

View File

@ -1564,9 +1564,31 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
true);
}
/* If we found the virtual table pointer, lookup the binfo. */
/* If we found the virtual table pointer, lookup the target. */
if (t)
t = vtable_pointer_value_to_binfo (t);
{
tree vtable;
unsigned HOST_WIDE_INT offset;
if (vtable_pointer_value_to_vtable (t, &vtable, &offset))
{
target = gimple_get_virt_method_for_vtable (ie->indirect_info->otr_token,
vtable, offset);
if ((TREE_CODE (TREE_TYPE (target)) == FUNCTION_TYPE
&& DECL_FUNCTION_CODE (target) == BUILT_IN_UNREACHABLE)
|| !possible_polymorphic_call_target_p
(ie, cgraph_get_node (target)))
{
if (dump_file)
fprintf (dump_file,
"Type inconsident devirtualization: %s/%i->%s\n",
ie->caller->name (), ie->caller->order,
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (target)));
target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
cgraph_get_create_node (target);
}
return target;
}
}
/* Did we work out BINFO via type propagation? */
if (!t && known_binfos.length () > (unsigned int) param_index)

View File

@ -2687,23 +2687,44 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
struct ipa_jump_func *jfunc,
struct ipa_node_params *new_root_info)
{
tree binfo = NULL, target;
tree binfo, target;
if (!flag_devirtualize)
return NULL;
/* First try to do lookup binfo via known virtual table pointer value. */
/* First try to do lookup via known virtual table pointer value. */
if (!ie->indirect_info->by_ref)
{
tree vtable;
unsigned HOST_WIDE_INT offset;
tree t = ipa_find_agg_cst_for_param (&jfunc->agg,
ie->indirect_info->offset,
true);
if (t)
binfo = vtable_pointer_value_to_binfo (t);
if (t && vtable_pointer_value_to_vtable (t, &vtable, &offset))
{
target = gimple_get_virt_method_for_vtable (ie->indirect_info->otr_token,
vtable, offset);
if (target)
{
if ((TREE_CODE (TREE_TYPE (target)) == FUNCTION_TYPE
&& DECL_FUNCTION_CODE (target) == BUILT_IN_UNREACHABLE)
|| !possible_polymorphic_call_target_p
(ie, cgraph_get_node (target)))
{
if (dump_file)
fprintf (dump_file,
"Type inconsident devirtualization: %s/%i->%s\n",
ie->caller->name (), ie->caller->order,
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (target)));
target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
cgraph_get_create_node (target);
}
return ipa_make_edge_direct_to_target (ie, target);
}
}
}
if (!binfo)
binfo = ipa_value_from_jfunc (new_root_info, jfunc);
binfo = ipa_value_from_jfunc (new_root_info, jfunc);
if (!binfo)
return NULL;

View File

@ -1,3 +1,7 @@
2014-02-03 Jan Hubicka <jh@suse.cz>
* g++.dg/ipa/devirt-25.C: New testcase.
2014-02-04 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/59924

View File

@ -0,0 +1,26 @@
/* { dg-do compile } */
/* { dg-options "-O3 -fdump-ipa-cp" } */
class ert_RefCounter {
protected:
int refCounterE;
virtual ~ert_RefCounter() {}
};
class ebs_Object : virtual public ert_RefCounter {
};
class dpr_App : public ebs_Object {
public:
virtual void run();
};
class dpr_Job : public ebs_Object {};
void dpr_run(ebs_Object& objectA) {
((dpr_App&)objectA).run();
dpr_Job jobL;
dpr_run(jobL);
}
/* { dg-final { scan-ipa-dump "Type inconsident devirtualization" "cp" } } */
/* { dg-final { cleanup-ipa-dump "cp" } } */