Commit 5bccb77a by Jan Hubicka Committed by Jan Hubicka

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.

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

From-SVN: r207448
parent 9de2f554
2014-02-03 Jan Hubicka <jh@suse.cz>
PR ipa/59831
* ipa-cp.c (ipa_get_indirect_edge_target_1): Use ipa-devirt
to figure out targets of polymorphic calls with known decl.
* ipa-prop.c (try_make_edge_direct_virtual_call): Likewise.
* ipa-utils.h (get_polymorphic_call_info_from_invariant): Declare.
* ipa-devirt.c (get_polymorphic_call_info_for_decl): Break out from ...
(get_polymorphic_call_info): ... here.
(get_polymorphic_call_info_from_invariant): New function.
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.
......
......@@ -1601,15 +1601,24 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
if (TREE_CODE (t) != TREE_BINFO)
{
tree binfo;
binfo = gimple_extract_devirt_binfo_from_cst
(t, ie->indirect_info->otr_type);
if (!binfo)
ipa_polymorphic_call_context context;
vec <cgraph_node *>targets;
bool final;
if (!get_polymorphic_call_info_from_invariant
(&context, t, ie->indirect_info->otr_type,
anc_offset))
return NULL_TREE;
binfo = get_binfo_at_offset (binfo, anc_offset, otr_type);
if (!binfo)
targets = possible_polymorphic_call_targets
(ie->indirect_info->otr_type,
ie->indirect_info->otr_token,
context, &final);
if (!final || targets.length () > 1)
return NULL_TREE;
target = gimple_get_virt_method_for_binfo (token, binfo);
if (targets.length () == 1)
target = targets[0]->decl;
else
target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
}
else
{
......
......@@ -1071,6 +1071,60 @@ vtable_pointer_value_to_binfo (tree t)
offset, vtable);
}
/* Proudce polymorphic call context for call method of instance
that is located within BASE (that is assumed to be a decl) at OFFSET. */
static void
get_polymorphic_call_info_for_decl (ipa_polymorphic_call_context *context,
tree base, HOST_WIDE_INT offset)
{
gcc_assert (DECL_P (base));
context->outer_type = TREE_TYPE (base);
context->offset = offset;
/* Make very conservative assumption that all objects
may be in construction.
TODO: ipa-prop already contains code to tell better.
merge it later. */
context->maybe_in_construction = true;
context->maybe_derived_type = false;
}
/* CST is an invariant (address of decl), try to get meaningful
polymorphic call context for polymorphic call of method
if instance of OTR_TYPE that is located at OFFSET of this invariant.
Return FALSE if nothing meaningful can be found. */
bool
get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *context,
tree cst,
tree otr_type,
HOST_WIDE_INT offset)
{
HOST_WIDE_INT offset2, size, max_size;
tree base;
if (TREE_CODE (cst) != ADDR_EXPR)
return NULL_TREE;
cst = TREE_OPERAND (cst, 0);
base = get_ref_base_and_extent (cst, &offset2, &size, &max_size);
if (!DECL_P (base)
|| max_size == -1
|| max_size != size)
return NULL_TREE;
/* Only type inconsistent programs can have otr_type that is
not part of outer type. */
if (!contains_type_p (TREE_TYPE (base),
offset, otr_type))
return NULL_TREE;
get_polymorphic_call_info_for_decl (context,
base, offset);
return true;
}
/* 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 */
......@@ -1136,14 +1190,8 @@ get_polymorphic_call_info (tree fndecl,
if (!contains_type_p (TREE_TYPE (base),
context->offset + offset2, *otr_type))
return base_pointer;
context->outer_type = TREE_TYPE (base);
context->offset += offset2;
/* Make very conservative assumption that all objects
may be in construction.
TODO: ipa-prop already contains code to tell better.
merge it later. */
context->maybe_in_construction = true;
context->maybe_derived_type = false;
get_polymorphic_call_info_for_decl (context, base,
context->offset + offset2);
return NULL;
}
else
......
......@@ -2731,19 +2731,38 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
if (TREE_CODE (binfo) != TREE_BINFO)
{
binfo = gimple_extract_devirt_binfo_from_cst
(binfo, ie->indirect_info->otr_type);
if (!binfo)
ipa_polymorphic_call_context context;
vec <cgraph_node *>targets;
bool final;
if (!get_polymorphic_call_info_from_invariant
(&context, binfo, ie->indirect_info->otr_type,
ie->indirect_info->offset))
return NULL;
targets = possible_polymorphic_call_targets
(ie->indirect_info->otr_type,
ie->indirect_info->otr_token,
context, &final);
if (!final || targets.length () > 1)
return NULL;
if (targets.length () == 1)
target = targets[0]->decl;
else
{
target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
cgraph_get_create_node (target);
}
}
binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset,
ie->indirect_info->otr_type);
if (binfo)
target = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token,
binfo);
else
return NULL;
{
binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset,
ie->indirect_info->otr_type);
if (binfo)
target = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token,
binfo);
else
return NULL;
}
if (target)
{
......
......@@ -87,6 +87,8 @@ tree method_class_type (tree);
tree get_polymorphic_call_info (tree, tree, tree *,
HOST_WIDE_INT *,
ipa_polymorphic_call_context *);
bool get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *,
tree, tree, HOST_WIDE_INT);
tree vtable_pointer_value_to_binfo (tree t);
bool vtable_pointer_value_to_vtable (tree, tree *, unsigned HOST_WIDE_INT *);
......
2014-02-03 Jan Hubicka <jh@suse.cz>
PR ipa/59831
* g++.dg/ipa/devirt-22.C: New testcase.
2014-02-03 Jan Hubicka <jh@suse.cz>
* g++.dg/ipa/devirt-25.C: New testcase.
2014-02-04 Jakub Jelinek <jakub@redhat.com>
......
/* { dg-do compile } */
/* { dg-options "-O3 -fno-early-inlining -fno-ipa-sra -fdump-ipa-cp" } */
class A {};
class B {
public:
A &operator[](int);
};
class C : B {
public:
virtual int m_fn1() { return 0; }
A &operator[](int p1) {
int a;
a = m_fn1();
static_cast<void>(__builtin_expect(a, 0) ?: 0);
return B::operator[](p1);
}
};
C b;
int *e;
static void sort(C &p1, C &p2) {
for (int i=0;; i++) {
A c, d = p2[0];
p1[0] = c;
p2[0] = d;
}
}
void lookupSourceDone() { b[0]; }
void update_sources() {
if (e) {
C f;
sort(f, b);
}
}
/* Note that we miss one devirtualization because we are not able to track the
vtbl store in destructor.
Previously we devirtualized to C::m_fn1 instead of B::m_fn1. */
/* { dg-final { scan-tree-dump-times "Discovered a virtual call to a known target" 1 "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