From patchwork Sun Jul 4 22:57:17 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Hubicka X-Patchwork-Id: 57857 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]) by ozlabs.org (Postfix) with SMTP id 09257B6F0C for ; Mon, 5 Jul 2010 08:57:28 +1000 (EST) Received: (qmail 10993 invoked by alias); 4 Jul 2010 22:57:26 -0000 Received: (qmail 10984 invoked by uid 22791); 4 Jul 2010 22:57:25 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL, BAYES_00, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from nikam-dmz.ms.mff.cuni.cz (HELO nikam.ms.mff.cuni.cz) (195.113.20.16) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 04 Jul 2010 22:57:20 +0000 Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id BCF909AC84C; Mon, 5 Jul 2010 00:57:17 +0200 (CEST) Date: Mon, 5 Jul 2010 00:57:17 +0200 From: Jan Hubicka To: gcc-patches@gcc.gnu.org, rguenther@suse.de Subject: Fix unresolved symbols during Mozilla WHOPR build Message-ID: <20100704225717.GC29130@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.18 (2008-05-17) 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 Hi, Mozilla fails to build with WHOPR on undefined symbols. The symbol belongs to COMDAT function that ends up being used in one ltrans and defined in another. In normal compilation this never happens, since we define comdat functions in every unit referring it and it seems that the same has to be done in WHOPR partitioning too, since linker drops the comdat sections if they are not used in same unit. This patch updated partitioning algorithm to put COMDAT function into every partition that refers to it. This shown latent bug in referenced_from_other_partition_p logic that assume that if function is found in current partition, it is not part of other partition. This is not correct for functions present in multiple partitions. Since the predicate sees one partition at a time (and I think it is good idea to do so), I need to record what nodes are present in multiple units. I ended up using in_other_partition flg for this purpose during WPA stage. When inserting node, first time I set aux pointer to the corresponding partition and when we insert it into second partiiton, we set the flag. Bootstrapped/regtested x86_64-linux. I also tested it on mozilla build (that still fails but for other reasons) and I am running WHOPR bootstrap. OK if that passes? Honza * cgraph.h (cgraph_node, cgraph_varpool_node): Update docmentation of in_other_partition. * lto-cgraph.c (referenced_from_other_partition_p, reachable_from_other_partition_p): Use in_other_partition flags. (output_node, output_varpool_node): COMDAT nodes always have private copies and thus are never used from other partition. * lto.c (add_cgraph_node_to_partition): Forward declare; walk also nodes from same comdat group as well as all comdat functions referenced here. (add_varpool_node_to_partition, add_references_to_partition): New function. (lto_1_1_map): Skip COMDAT fnctions/variables; use add_varpool_node_to_partition; clear aux flags when done. (lto_promote_cross_file_statics): Do not promote stuff that gets duplicated to each ltrans. Index: cgraph.h =================================================================== --- cgraph.h (revision 161812) +++ cgraph.h (working copy) @@ -286,7 +286,9 @@ /* Set once the function has been instantiated and its callee lists created. */ unsigned analyzed : 1; - /* Set when function is available in the other LTRANS partition. */ + /* Set when function is available in the other LTRANS partition. + During WPA output it is used to mark nodes that are present in + multiple partitions. */ unsigned in_other_partition : 1; /* Set when function is scheduled to be processed by local passes. */ unsigned process : 1; @@ -497,7 +499,9 @@ unsigned alias : 1; /* Set when variable is used from other LTRANS partition. */ unsigned used_from_other_partition : 1; - /* Set when variable is available in the other LTRANS partition. */ + /* Set when variable is available in the other LTRANS partition. + During WPA output it is used to mark nodes that are present in + multiple partitions. */ unsigned in_other_partition : 1; }; @@ -556,6 +560,7 @@ struct cgraph_edge *cgraph_create_indirect_edge (struct cgraph_node *, gimple, int, gcov_type, int, int); struct cgraph_node * cgraph_get_node (tree); +struct cgraph_node * cgraph_get_node_or_alias (tree); struct cgraph_node *cgraph_node (tree); bool cgraph_same_body_alias (tree, tree); void cgraph_add_thunk (tree, tree, bool, HOST_WIDE_INT, HOST_WIDE_INT, tree, tree); Index: lto-cgraph.c =================================================================== --- lto-cgraph.c (revision 161812) +++ lto-cgraph.c (working copy) @@ -319,13 +319,15 @@ { if (ref->refering_type == IPA_REF_CGRAPH) { - if (!cgraph_node_in_set_p (ipa_ref_refering_node (ref), set)) + if (ipa_ref_refering_node (ref)->in_other_partition + || !cgraph_node_in_set_p (ipa_ref_refering_node (ref), set)) return true; } else { - if (!varpool_node_in_set_p (ipa_ref_refering_varpool_node (ref), - vset)) + if (ipa_ref_refering_varpool_node (ref)->in_other_partition + || !varpool_node_in_set_p (ipa_ref_refering_varpool_node (ref), + vset)) return true; } } @@ -343,7 +345,8 @@ if (node->global.inlined_to) return false; for (e = node->callers; e; e = e->next_caller) - if (!cgraph_node_in_set_p (e->caller, set)) + if (e->caller->in_other_partition + || !cgraph_node_in_set_p (e->caller, set)) return true; return false; } @@ -503,6 +506,7 @@ bp_pack_value (&bp, node->abstract_and_needed, 1); bp_pack_value (&bp, tag == LTO_cgraph_analyzed_node && !DECL_EXTERNAL (node->decl) + && !DECL_COMDAT (node->decl) && (reachable_from_other_partition_p (node, set) || referenced_from_other_partition_p (&node->ref_list, set, vset)), 1); bp_pack_value (&bp, node->lowered, 1); @@ -576,7 +580,8 @@ /* Constant pool initializers can be de-unified into individual ltrans units. FIXME: Alternatively at -Os we may want to avoid generating for them the local labels and share them across LTRANS partitions. */ - if (DECL_IN_CONSTANT_POOL (node->decl)) + if (DECL_IN_CONSTANT_POOL (node->decl) + && !DECL_COMDAT (node->decl)) { bp_pack_value (&bp, 0, 1); /* used_from_other_parition. */ bp_pack_value (&bp, 0, 1); /* in_other_partition. */ Index: lto/lto.c =================================================================== --- lto/lto.c (revision 161812) +++ lto/lto.c (working copy) @@ -525,6 +525,9 @@ static GTY (()) VEC(ltrans_partition, gc) *ltrans_partitions; +static void add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node); +static void add_varpool_node_to_partition (ltrans_partition part, struct varpool_node *vnode); + /* Create new partition with name NAME. */ static ltrans_partition new_partition (const char *name) @@ -538,19 +541,79 @@ return part; } -/* Add NODE to partition as well as the inline callees into partition PART. */ +/* See all references that go to comdat objects and bring them into partition too. */ +static void +add_references_to_partition (ltrans_partition part, struct ipa_ref_list *refs) +{ + int i; + struct ipa_ref *ref; + for (i = 0; ipa_ref_list_reference_iterate (refs, i, ref); i++) + { + if (ref->refered_type == IPA_REF_CGRAPH + && DECL_COMDAT (ipa_ref_node (ref)->decl) + && !cgraph_node_in_set_p (ipa_ref_node (ref), part->cgraph_set)) + add_cgraph_node_to_partition (part, ipa_ref_node (ref)); + else + if (ref->refered_type == IPA_REF_VARPOOL + && DECL_COMDAT (ipa_ref_varpool_node (ref)->decl) + && !varpool_node_in_set_p (ipa_ref_varpool_node (ref), part->varpool_set)) + add_varpool_node_to_partition (part, ipa_ref_varpool_node (ref)); + } +} +/* Add NODE to partition as well as the inline callees and referred comdats into partition PART. */ + static void add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node) { struct cgraph_edge *e; + part->insns += node->local.inline_summary.self_size; + + if (node->aux) + { + gcc_assert (node->aux != part); + node->in_other_partition = 1; + } + else + node->aux = part; + cgraph_node_set_add (part->cgraph_set, node); + for (e = node->callees; e; e = e->next_callee) - if (!e->inline_failed) + if ((!e->inline_failed || DECL_ONE_ONLY (e->callee->decl)) + && !cgraph_node_in_set_p (e->callee, part->cgraph_set)) add_cgraph_node_to_partition (part, e->callee); + + add_references_to_partition (part, &node->ref_list); + + if (node->same_comdat_group + && !cgraph_node_in_set_p (node->same_comdat_group, part->cgraph_set)) + add_cgraph_node_to_partition (part, node->same_comdat_group); } +/* Add VNODE to partition as well as comdat references partition PART. */ + +static void +add_varpool_node_to_partition (ltrans_partition part, struct varpool_node *vnode) +{ + varpool_node_set_add (part->varpool_set, vnode); + + if (vnode->aux) + { + gcc_assert (vnode->aux != part); + vnode->in_other_partition = 1; + } + else + vnode->aux = part; + + add_references_to_partition (part, &vnode->ref_list); + + if (vnode->same_comdat_group + && !varpool_node_in_set_p (vnode->same_comdat_group, part->varpool_set)) + add_varpool_node_to_partition (part, vnode->same_comdat_group); +} + /* Group cgrah nodes by input files. This is used mainly for testing right now. */ @@ -577,6 +640,10 @@ /* Nodes without a body do not need partitioning. */ if (!node->analyzed) continue; + /* Extern inlines and comdat are always only in partitions they are needed. */ + if (DECL_EXTERNAL (node->decl) + || DECL_COMDAT (node->decl)) + continue; file_data = node->local.lto_file_data; gcc_assert (!node->same_body_alias && file_data); @@ -599,6 +666,10 @@ { if (vnode->alias || !vnode->needed) continue; + /* Constant pool and comdat are always only in partitions they are needed. */ + if (DECL_IN_CONSTANT_POOL (vnode->decl) + || DECL_COMDAT (vnode->decl)) + continue; file_data = vnode->lto_file_data; slot = pointer_map_contains (pmap, file_data); if (slot) @@ -611,8 +682,12 @@ npartitions++; } - varpool_node_set_add (partition->varpool_set, vnode); + add_varpool_node_to_partition (partition, vnode); } + for (node = cgraph_nodes; node; node = node->next) + node->aux = NULL; + for (vnode = varpool_nodes; vnode; vnode = vnode->next) + vnode->aux = NULL; /* If the cgraph is empty, create one cgraph node set so that there is still an output file for any variables that need to be exported in a DSO. */ @@ -704,7 +779,7 @@ continue; if (node->global.inlined_to) continue; - if (!DECL_EXTERNAL (node->decl) + if ((!DECL_EXTERNAL (node->decl) && !DECL_COMDAT (node->decl)) && (referenced_from_other_partition_p (&node->ref_list, set, vset) || reachable_from_other_partition_p (node, set))) promote_fn (node); @@ -715,10 +790,10 @@ /* Constant pool references use internal labels and thus can not be made global. It is sensible to keep those ltrans local to allow better optimization. */ - if (!DECL_IN_CONSTANT_POOL (vnode->decl) - && !vnode->externally_visible && vnode->analyzed - && referenced_from_other_partition_p (&vnode->ref_list, - set, vset)) + if (!DECL_IN_CONSTANT_POOL (vnode->decl) && !DECL_COMDAT (vnode->decl) + && !vnode->externally_visible && vnode->analyzed + && referenced_from_other_partition_p (&vnode->ref_list, + set, vset)) promote_var (vnode); }