From patchwork Thu Mar 10 16:12:59 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Hubicka X-Patchwork-Id: 595840 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 63DDE140307 for ; Fri, 11 Mar 2016 03:13:15 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=NHMV8lEn; dkim-atps=neutral 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=Cqsjx+urdfBhPNqqxZguttKtbYECsU2docmi+3Zjchb4+cvaS6pKa mQ/s3CaisZabXdNfvObzwP41PWNHI7UnBtRkWwCDSEBPCpIwdS2fMK0EoJ9BLJha 4XqABFENVZShmnATzi8S2gLjYTj1DBwVqH0QhDdZoMro+mJcUuXH0M= 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=S+Gv6pqmU7S/I8qH+vmdvzyrUig=; b=NHMV8lEniH/pgI69U6Dg dZc4UpotZK+L+BwX6nAfCLcOzOXasVo/yb7S23UoC4eRhqZ/gXyYZKmUTpk/QqRY 5u7JqcaV/MSB1ycZDtMU9lha9E8INzlqKejrdenhfq012/LHGjgLpno/DCpBVNdc iNKIEfkDv3P/ARjGlOgD8RE= Received: (qmail 103789 invoked by alias); 10 Mar 2016 16:13:04 -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 103765 invoked by uid 89); 10 Mar 2016 16:13:04 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.2 required=5.0 tests=AWL, BAYES_00, KAM_ASCII_DIVIDERS, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD autolearn=no version=3.3.2 spammy=UD:local, polymorphic, 3327, 41, 7 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; Thu, 10 Mar 2016 16:13:02 +0000 Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id 2F43D541E1C; Thu, 10 Mar 2016 17:12:59 +0100 (CET) Date: Thu, 10 Mar 2016 17:12:59 +0100 From: Jan Hubicka To: gcc-patches@gcc.gnu.org Subject: Fix ICE in initialize_node_lattices Message-ID: <20160310161258.GB47843@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) Hi, this patch fixes ICE in ipa-cp that detects local function that is dead. The issue is that virutal functions may have no address taken but still may be virtual call targets. This patch makes remove_unreachable_nodes to handle this and not mark them local (since they are not) Honza * cgraph.c (cgraph_node::dump): Dump split_part and indirect_call_target. * cgraph.h (cgraph_node): Add indirect_call_target flag. * ipa.c (has_addr_references_p): Cleanup. (is_indirect_call_target_p): New. (walk_polymorphic_call_targets): Do not mark virtuals that may be called indirectly as local. (symbol_table::remove_unreachable_nodes): Compute indirect_call_target. PR lto/69589 * g++.dg/lto/pr69589_0.C: New testcase * g++.dg/lto/pr69589_1.C: New testcase Index: cgraph.c =================================================================== --- cgraph.c (revision 234108) +++ cgraph.c (working copy) @@ -2061,6 +2061,10 @@ cgraph_node::dump (FILE *f) fprintf (f, " icf_merged"); if (merged_comdat) fprintf (f, " merged_comdat"); + if (split_part) + fprintf (f, " split_part"); + if (indirect_call_target) + fprintf (f, " indirect_call_target"); if (nonfreeing_fn) fprintf (f, " nonfreeing_fn"); if (DECL_STATIC_CONSTRUCTOR (decl)) Index: cgraph.h =================================================================== --- cgraph.h (revision 234108) +++ cgraph.h (working copy) @@ -1366,6 +1366,8 @@ public: unsigned parallelized_function : 1; /* True if function is part split out by ipa-split. */ unsigned split_part : 1; + /* True if the function appears as possible target of indirect call. */ + unsigned indirect_call_target : 1; private: /* Worker for call_for_symbol_and_aliases. */ Index: ipa.c =================================================================== --- ipa.c (revision 234108) +++ ipa.c (working copy) @@ -41,7 +41,7 @@ along with GCC; see the file COPYING3. static bool has_addr_references_p (struct cgraph_node *node, - void *data ATTRIBUTE_UNUSED) + void *) { int i; struct ipa_ref *ref = NULL; @@ -52,6 +52,14 @@ has_addr_references_p (struct cgraph_nod return false; } +/* Return true when NODE can be target of an indirect call. */ + +static bool +is_indirect_call_target_p (struct cgraph_node *node, void *) +{ + return node->indirect_call_target; +} + /* Look for all functions inlined to NODE and update their inlined_to pointers to INLINED_TO. */ @@ -172,23 +180,24 @@ walk_polymorphic_call_targets (hash_set< (TYPE_METHOD_BASETYPE (TREE_TYPE (n->decl)))) continue; - symtab_node *body = n->function_symbol (); + n->indirect_call_target = true; + symtab_node *body = n->function_symbol (); /* Prior inlining, keep alive bodies of possible targets for devirtualization. */ - if (n->definition - && (before_inlining_p - && opt_for_fn (body->decl, optimize) - && opt_for_fn (body->decl, flag_devirtualize))) - { - /* Be sure that we will not optimize out alias target - body. */ - if (DECL_EXTERNAL (n->decl) - && n->alias - && before_inlining_p) - reachable->add (body); - reachable->add (n); - } + if (n->definition + && (before_inlining_p + && opt_for_fn (body->decl, optimize) + && opt_for_fn (body->decl, flag_devirtualize))) + { + /* Be sure that we will not optimize out alias target + body. */ + if (DECL_EXTERNAL (n->decl) + && n->alias + && before_inlining_p) + reachable->add (body); + reachable->add (n); + } /* Even after inlining we want to keep the possible targets in the boundary, so late passes can still produce direct call even if the chance for inlining is lost. */ @@ -323,6 +332,7 @@ symbol_table::remove_unreachable_nodes ( FOR_EACH_FUNCTION (node) { node->used_as_abstract_origin = false; + node->indirect_call_target = false; if (node->definition && !node->global.inlined_to && !node->in_other_partition @@ -659,7 +669,14 @@ symbol_table::remove_unreachable_nodes ( fprintf (file, " %s", node->name ()); node->address_taken = false; changed = true; - if (node->local_p ()) + if (node->local_p () + /* Virtual functions may be kept in cgraph just because + of possible later devirtualization. Do not mark them as + local too early so we won't optimize them out before + we are done with polymorphic call analysis. */ + && (!before_inlining_p + || !node->call_for_symbol_and_aliases + (is_indirect_call_target_p, NULL, true))) { node->local.local = true; if (file) Index: testsuite/g++.dg/lto/pr69589_0.C =================================================================== --- testsuite/g++.dg/lto/pr69589_0.C (revision 0) +++ testsuite/g++.dg/lto/pr69589_0.C (working copy) @@ -0,0 +1,26 @@ +// { dg-lto-do link } +// { dg-lto-options "-O2 -rdynamic" } +// { dg-extra-ld-options "-r -nostdlib" } +#pragma GCC visibility push(hidden) +struct A { int &operator[] (long); }; +template struct B; +template > +using Z = int; +template struct C; +struct S { + int e; + virtual ~S () {} +}; +struct D : S { + A a; + long i; + D() { { e ? &a[i] : nullptr; } } +}; +template <> +struct C { Z m8 () const; }; +Z +C::m8 () const +{ + D (); +} + Index: testsuite/g++.dg/lto/pr69589_1.C =================================================================== --- testsuite/g++.dg/lto/pr69589_1.C (revision 0) +++ testsuite/g++.dg/lto/pr69589_1.C (working copy) @@ -0,0 +1,61 @@ +struct A; +template +struct Q { Q (T); }; +template +struct U { + ~U () { m1 (nullptr); } + D m2 (); + T *u; + void m1 (T *) { m2 () (u); } +}; +struct F { F (int *); }; +template +using W = Q; +int a, b; +void fn1 (void *); +template +void +fn2 (T *x) +{ + if (x) + x->~T(); + fn1 (x); +} +template +struct C { + void operator() (T *x) { fn2 (x); } +}; +struct D; +template > +using V = U; +struct A { + A (int *); +}; +struct S; +struct G { + V m3 (); +}; +struct S { + int e; + virtual ~S () {} +}; +template +struct H { + H (int, T x, int) : h(x) {} + G g; + void m4 () { g.m3 (); } + T h; +}; +struct I { + I(A, W); +}; +void +test () +{ + A c (&b); + W d (&b); + I e (c, d); + H f (0, e, a); + f.m4 (); +} +