From patchwork Fri Oct 3 22:45:30 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Hubicka X-Patchwork-Id: 396470 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 755DF1400AB for ; Sat, 4 Oct 2014 08:45:44 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=iQ3deCQF74FKIKbuIjgT+iImmMNg6zD7y8IYi9FMClMSYZq2ejKTT wmdV6sp65LbowntRoulKuUJImdHFZtgqeOeUuFteibXwyAWZ+rZRTrqMJGwSZiNS KuAmhRTyeLxM7Kvc+ASy28wLR6lf3fOsh3UVKt2YCwssFLh0PktIWA= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=GSWC0+TzWXApXwH0zwBAQpINV+4=; b=v1DJ2DiHwW6gZ8oYoAs1 RXCKA/EyN4o7J2q8C0UZWMtmlQ9CRg25a5V4Cs+MJ6pm6RA8XA592qFxYd/+YxNd Kv5E3adOamI0k6ZFgXIIf70t4tQp8awzq/OSW5P+Ldr8FwfccNZM3lLzhvVlcBla UZaLcdogzfeeDH/3+9pT380= Received: (qmail 22316 invoked by alias); 3 Oct 2014 22:45:38 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 22307 invoked by uid 89); 3 Oct 2014 22:45:37 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.1 required=5.0 tests=AWL, BAYES_00, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: nikam.ms.mff.cuni.cz Received: from nikam.ms.mff.cuni.cz (HELO nikam.ms.mff.cuni.cz) (195.113.20.16) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Fri, 03 Oct 2014 22:45:35 +0000 Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id 906535409DF; Sat, 4 Oct 2014 00:45:30 +0200 (CEST) Date: Sat, 4 Oct 2014 00:45:30 +0200 From: Jan Hubicka To: gcc-patches@gcc.gnu.org, mjambor@suse.cz, jason@redhat.com Subject: Add testcases for new devirtualization code paths; fix merging of speculative devirt Message-ID: <20141003224530.GB25357@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) Hi, this patch add basic testcaes for new devirtualization features (more to come) and also fixes bug I introduced while refactoring the speculative context merging code - that most likely explains why I observed number of speculative devirt to drop considerably after finishing the patch. Jason, can you, please, double check the second FIXME in testcases? Will commit it once bootstrap/regtest of x86_64-linux finishes. * 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. Index: testsuite/g++.dg/ipa/devirt-42.C =================================================================== --- testsuite/g++.dg/ipa/devirt-42.C (revision 0) +++ testsuite/g++.dg/ipa/devirt-42.C (revision 0) @@ -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" } } */ Index: testsuite/g++.dg/ipa/devirt-44.C =================================================================== --- testsuite/g++.dg/ipa/devirt-44.C (revision 0) +++ testsuite/g++.dg/ipa/devirt-44.C (revision 0) @@ -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" } } */ Index: testsuite/g++.dg/ipa/devirt-41.C =================================================================== --- testsuite/g++.dg/ipa/devirt-41.C (revision 0) +++ testsuite/g++.dg/ipa/devirt-41.C (revision 0) @@ -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" } } */ Index: testsuite/g++.dg/ipa/devirt-43.C =================================================================== --- testsuite/g++.dg/ipa/devirt-43.C (revision 0) +++ testsuite/g++.dg/ipa/devirt-43.C (revision 0) @@ -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" } } */ Index: testsuite/g++.dg/ipa/devirt-45.C =================================================================== --- testsuite/g++.dg/ipa/devirt-45.C (revision 0) +++ testsuite/g++.dg/ipa/devirt-45.C (revision 0) @@ -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" } } */ Index: ipa-polymorphic-call.c =================================================================== --- ipa-polymorphic-call.c (revision 215876) +++ ipa-polymorphic-call.c (working copy) @@ -820,8 +820,7 @@ ipa_polymorphic_call_context::ipa_polymo &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_wi 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))