PR ipa/59831 (ipa-cp devirt issues)
Jan Hubicka
hubicka@ucw.cz
Tue Feb 4 05:44:00 GMT 2014
Hi,
this patch solves the actual ICE in PR59831 by using ipa-devirt instead of
gimple_extract_devirt_binfo_from_cst as discussed in the first post.
Honza
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.
* g++.dg/ipa/devirt-22.C: New testcase.
Index: ipa-cp.c
===================================================================
--- ipa-cp.c (revision 207447)
+++ ipa-cp.c (working copy)
@@ -1601,15 +1601,24 @@ ipa_get_indirect_edge_target_1 (struct c
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
{
Index: testsuite/g++.dg/ipa/devirt-22.C
===================================================================
--- testsuite/g++.dg/ipa/devirt-22.C (revision 0)
+++ testsuite/g++.dg/ipa/devirt-22.C (revision 0)
@@ -0,0 +1,41 @@
+/* { 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" } } */
Index: ipa-utils.h
===================================================================
--- ipa-utils.h (revision 207439)
+++ ipa-utils.h (working copy)
@@ -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 *);
Index: ipa-prop.c
===================================================================
--- ipa-prop.c (revision 207447)
+++ ipa-prop.c (working copy)
@@ -2731,19 +2731,38 @@ try_make_edge_direct_virtual_call (struc
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)
{
Index: ipa-devirt.c
===================================================================
--- ipa-devirt.c (revision 207439)
+++ ipa-devirt.c (working copy)
@@ -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
More information about the Gcc-patches
mailing list