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:
parent
4b076d8a4d
commit
9de2f554ec
|
@ -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
|
||||
|
|
|
@ -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,14 +3268,23 @@ 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;
|
||||
|
||||
/* 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, v);
|
||||
if (!fn || integer_zerop (fn))
|
||||
return NULL_TREE;
|
||||
gcc_assert (TREE_CODE (fn) == ADDR_EXPR
|
||||
|| TREE_CODE (fn) == FDESC_EXPR);
|
||||
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);
|
||||
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
|
||||
|
@ -3281,6 +3292,7 @@ gimple_get_virt_method_for_vtable (HOST_WIDE_INT token,
|
|||
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
|
||||
|
|
26
gcc/ipa-cp.c
26
gcc/ipa-cp.c
|
@ -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)
|
||||
|
|
|
@ -2687,22 +2687,43 @@ 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);
|
||||
|
||||
if (!binfo)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" } } */
|
Loading…
Reference in New Issue