From 07f4a83d4afba28f8b73a9b9a8aeb48adec9eac3 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sat, 4 Oct 2014 05:24:42 +0200 Subject: [PATCH] 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 --- gcc/ChangeLog | 7 +++++ gcc/ipa-polymorphic-call.c | 5 ++-- gcc/testsuite/ChangeLog | 7 +++++ gcc/testsuite/g++.dg/ipa/devirt-41.C | 31 ++++++++++++++++++++ gcc/testsuite/g++.dg/ipa/devirt-42.C | 42 +++++++++++++++++++++++++++ gcc/testsuite/g++.dg/ipa/devirt-43.C | 27 +++++++++++++++++ gcc/testsuite/g++.dg/ipa/devirt-44.C | 33 +++++++++++++++++++++ gcc/testsuite/g++.dg/ipa/devirt-45.C | 43 ++++++++++++++++++++++++++++ 8 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ipa/devirt-41.C create mode 100644 gcc/testsuite/g++.dg/ipa/devirt-42.C create mode 100644 gcc/testsuite/g++.dg/ipa/devirt-43.C create mode 100644 gcc/testsuite/g++.dg/ipa/devirt-44.C create mode 100644 gcc/testsuite/g++.dg/ipa/devirt-45.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f7724f5b696..9437414fb9b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2014-10-03 Jan Hubicka + + * 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 * altivec.md (altivec_lvsl): New define_expand. diff --git a/gcc/ipa-polymorphic-call.c b/gcc/ipa-polymorphic-call.c index f352625fc78..a9b037a5211 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 036b171d079..2293926ea89 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2014-10-03 Jan Hubicka + + * 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 * 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 00000000000..5ba1158f8f7 --- /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 00000000000..40076ddf33e --- /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(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 00000000000..9be49e764ea --- /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 00000000000..4f6ab30cb02 --- /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 00000000000..2158c7e5987 --- /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(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" } } */