aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2014-02-04 06:40:21 +0100
committerJan Hubicka <hubicka@gcc.gnu.org>2014-02-04 05:40:21 +0000
commit5bccb77a773b916d4824688e9138921f93c35039 (patch)
treec78cc4b81e9fffb8c0810f34976aecfcf20b5c3d
parent9de2f554ec689296676dee4f4482e059438a5991 (diff)
downloadgcc-5bccb77a773b916d4824688e9138921f93c35039.zip
gcc-5bccb77a773b916d4824688e9138921f93c35039.tar.gz
gcc-5bccb77a773b916d4824688e9138921f93c35039.tar.bz2
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
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/ipa-cp.c23
-rw-r--r--gcc/ipa-devirt.c64
-rw-r--r--gcc/ipa-prop.c39
-rw-r--r--gcc/ipa-utils.h2
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-22.C41
7 files changed, 160 insertions, 25 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 4baab8e..c4c197a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,16 @@
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.
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index e210176..68afeb0 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -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
{
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index fb9c666..f137874 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -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
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 39c01c5..69566e9 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -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)
{
diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h
index 3f9be17..d595e8a 100644
--- a/gcc/ipa-utils.h
+++ b/gcc/ipa-utils.h
@@ -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 *);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 3a0c944..131b6c9 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,10 @@
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>
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-22.C b/gcc/testsuite/g++.dg/ipa/devirt-22.C
new file mode 100644
index 0000000..8b8279a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/devirt-22.C
@@ -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" } } */