aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJan Hubicka <hubicka@ucw.cz>2014-10-04 05:24:42 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2014-10-04 03:24:42 +0000
commit07f4a83d4afba28f8b73a9b9a8aeb48adec9eac3 (patch)
tree4e12538abcb7a57877879348dae3ea4837723aa8 /gcc
parentdbaba85539c4742ccb02f4750c05ccc296cbbb7b (diff)
downloadgcc-07f4a83d4afba28f8b73a9b9a8aeb48adec9eac3.zip
gcc-07f4a83d4afba28f8b73a9b9a8aeb48adec9eac3.tar.gz
gcc-07f4a83d4afba28f8b73a9b9a8aeb48adec9eac3.tar.bz2
devirt-42.C: New testcase.
* testsuite/g++.dg/ipa/devirt-42.C: New testcase. * testsuite/g++.dg/ipa/devirt-43.C: New testcase. * testsuite/g++.dg/ipa/devirt-44.C: New testcase. * testsuite/g++.dg/ipa/devirt-45.C: New testcase. * ipa-polymorphic-call.c (ipa_polymorphic_call_context::ipa_polymorphic_call_context): Fix code determining speculative type. (ipa_polymorphic_call_context::combine_with): Fix speculation merge. From-SVN: r215886
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/ipa-polymorphic-call.c5
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-41.C31
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-42.C42
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-43.C27
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-44.C33
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-45.C43
8 files changed, 192 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f7724f5..9437414 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2014-10-03 Jan Hubicka <hubicka@ucw.cz>
+
+ * ipa-polymorphic-call.c
+ (ipa_polymorphic_call_context::ipa_polymorphic_call_context): Fix
+ code determining speculative type.
+ (ipa_polymorphic_call_context::combine_with): Fix speculation merge.
+
2014-10-03 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
* altivec.md (altivec_lvsl): New define_expand.
diff --git a/gcc/ipa-polymorphic-call.c b/gcc/ipa-polymorphic-call.c
index f352625..a9b037a 100644
--- a/gcc/ipa-polymorphic-call.c
+++ b/gcc/ipa-polymorphic-call.c
@@ -820,8 +820,7 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
&offset2, &size, &max_size);
if (max_size != -1 && max_size == size)
- combine_speculation_with (TYPE_MAIN_VARIANT
- (TREE_TYPE (TREE_TYPE (base_pointer))),
+ combine_speculation_with (TYPE_MAIN_VARIANT (TREE_TYPE (base)),
offset + offset2,
true,
NULL /* Do not change outer type. */);
@@ -1970,7 +1969,7 @@ ipa_polymorphic_call_context::combine_with (ipa_polymorphic_call_context ctx,
updated |= combine_speculation_with (ctx.speculative_outer_type,
ctx.speculative_offset,
- ctx.maybe_in_construction,
+ ctx.speculative_maybe_derived_type,
otr_type);
if (updated && dump_file && (dump_flags & TDF_DETAILS))
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 036b171..2293926 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2014-10-03 Jan Hubicka <hubicka@ucw.cz>
+
+ * testsuite/g++.dg/ipa/devirt-42.C: New testcase.
+ * testsuite/g++.dg/ipa/devirt-43.C: New testcase.
+ * testsuite/g++.dg/ipa/devirt-44.C: New testcase.
+ * testsuite/g++.dg/ipa/devirt-45.C: New testcase.
+
2014-10-03 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
* gcc.target/powerpc/lvsl-lvsr.c: New test.
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-41.C b/gcc/testsuite/g++.dg/ipa/devirt-41.C
new file mode 100644
index 0000000..5ba1158
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/devirt-41.C
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-ipa-inline-details -fno-early-inlining -fno-ipa-cp" } */
+struct A {virtual int foo () {return 1;}};
+struct B:A {virtual int foo () {return 2;}};
+
+void dostuff(struct A *);
+
+static void
+test (struct A *a)
+{
+ dostuff (a);
+ if (a->foo ()!= 2)
+ __builtin_abort ();
+}
+
+main()
+{
+ struct B a;
+ dostuff (&a);
+ test (&a);
+}
+/* Inlining of dostuff into main should combine polymorphic context
+ specifying Outer type:struct B offset 0
+ with Outer type (dynamic):struct A (or a derived type) offset 0
+ and enable devirtualization.
+
+ Because the type is in static storage, we know it won't change type in dostuff
+ and from callstack we can tell that is is not in construction/destruction. */
+/* { dg-final { scan-ipa-dump-times "First type is base of second" 1 "inline" } } */
+/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "inline" } } */
+/* { dg-final { cleanup-ipa-dump "inline" } } */
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-42.C b/gcc/testsuite/g++.dg/ipa/devirt-42.C
new file mode 100644
index 0000000..40076dd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/devirt-42.C
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fno-ipa-cp -fdump-ipa-inline-details -fno-early-inlining -fdump-tree-optimized" } */
+struct A {
+ virtual int foo () {return 1;}
+ int bar () {return foo();}
+ int barbar ();
+};
+namespace {
+ struct B:A {virtual int foo () {return 2;}
+ int barbar () {return bar();}};
+}
+
+int
+A::barbar()
+{
+ return static_cast<B*>(this)->barbar();
+}
+
+main()
+{
+ struct B b;
+ struct A *a = &b;
+ return a->barbar ();
+}
+
+/* Inlining everything into main makes type clear from type of variable b.
+ However devirtualization is also possible for offline copy of A::barbar. Invoking
+ B's barbar makes it clear the type is at least B and B is an anonymous
+ namespace type and therefore we know it has no derivations.
+ FIXME: Currently we devirtualize speculatively only because we do not track
+ dynamic type changes well. */
+/* { dg-final { scan-ipa-dump-times "First type is base of second" 1 "inline" } } */
+/* { dg-final { scan-ipa-dump-times "Outer types match, merging flags" 2 "inline" } } */
+/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "inline" } } */
+/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a speculative target" 1 "inline" } } */
+
+/* Verify that speculation is optimized by late optimizers. */
+/* { dg-final { scan-ipa-dump-times "return 2" 2 "optimized" } } */
+/* { dg-final { scan-ipa-dump-not "OBJ_TYPE_REF" "optimized" } } */
+
+/* { dg-final { cleanup-ipa-dump "inline" } } */
+/* { dg-final { cleanup-ipa-dump "optimized" } } */
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-43.C b/gcc/testsuite/g++.dg/ipa/devirt-43.C
new file mode 100644
index 0000000..9be49e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/devirt-43.C
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-ipa-inline-details -fno-ipa-cp -fno-early-inlining" } */
+struct A {virtual int foo () {return 1;}};
+struct B {int i; struct A a;};
+struct C:A {virtual int foo () {return 2;}};
+
+void dostuff(struct A *);
+
+static void
+test (struct A *a)
+{
+ dostuff (a);
+ if (a->foo ()!= 2)
+ __builtin_abort ();
+}
+
+void
+t(struct B *b)
+{
+ test(&b->a);
+}
+/* Here b comes externally, but we take speculative hint from type of the pointer that it is
+ of type B. This makes A fully specified and we know C::foo is unlikely.
+ FIXME: We could most probably can devirtualize unconditonally because dereference of b in
+ &b->a makes the type known. GIMPLE does not represent this. */
+/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a speculative target" 1 "inline" } } */
+/* { dg-final { cleanup-ipa-dump "inline" } } */
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-44.C b/gcc/testsuite/g++.dg/ipa/devirt-44.C
new file mode 100644
index 0000000..4f6ab30
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/devirt-44.C
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fno-ipa-cp -fdump-ipa-inline-details -fno-early-inlining -fdump-tree-optimized" } */
+struct A {
+ virtual int foo () {return 1;}
+ int wrapfoo () {foo();}
+ A() {wrapfoo();}
+};
+struct B:A {virtual int foo () {return 2;}};
+
+void dostuff(struct A *);
+
+static void
+test (struct A *a)
+{
+ dostuff (a);
+ if (a->foo ()!= 2)
+ __builtin_abort ();
+}
+
+main()
+{
+ struct B a;
+ dostuff (&a);
+ test (&a);
+}
+/* Here one invocation of foo is while type is in construction, while other is not.
+ Check that we handle that. */
+
+/* { dg-final { scan-ipa-dump-times "First type is base of second" 1 "inline" } } */
+/* { dg-final { scan-ipa-dump "(maybe in construction)" "inline" } } */
+/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*A::foo" 1 "inline" } } */
+/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*B::foo" 1 "inline" } } */
+/* { dg-final { cleanup-ipa-dump "inline" } } */
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-45.C b/gcc/testsuite/g++.dg/ipa/devirt-45.C
new file mode 100644
index 0000000..2158c7e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/devirt-45.C
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fno-ipa-cp -fdump-ipa-inline-details -fno-early-inlining -fdump-tree-optimized" } */
+struct A {
+ virtual int foo () {return 1;}
+ int wrapfoo () {foo();}
+ A() {wrapfoo();}
+};
+inline void* operator new(__SIZE_TYPE__ s, void* buf) throw() {
+ return buf;
+}
+struct B:A {virtual int foo () {return 2;}};
+
+void dostuff(struct A *);
+
+static void
+test2 (struct A *a)
+{
+ dostuff (a);
+ if (a->foo ()!= 2)
+ __builtin_abort ();
+}
+
+static void
+test (struct A *a)
+{
+ dostuff (a);
+ static_cast<B*>(a)->~B();
+ new(a) B();
+ test2(a);
+}
+
+main()
+{
+ struct B a;
+ dostuff (&a);
+ test (&a);
+}
+
+/* One invocation is A::foo () other is B::foo () even though the type is destroyed and rebuilt in test() */
+/* { dg-final { scan-ipa-dump "(maybe in construction)" "inline" } } */
+/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*A::foo" 1 "inline" } } */
+/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*B::foo" 1 "inline" } } */
+/* { dg-final { cleanup-ipa-dump "inline" } } */