From patchwork Wed Feb 15 22:50:19 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lawrence Crowl X-Patchwork-Id: 141423 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 6EE321007D4 for ; Thu, 16 Feb 2012 09:51:22 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1329951083; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: MIME-Version:Received:Received:Received:Received:To:Subject: Message-Id:Date:From:Mailing-List:Precedence:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:Sender: Delivered-To; bh=L8xcFT50C9B4aHpY3cHFVPOt4tg=; b=K8/2ECMkgA4Xda1 iibMYl4TnP3Rhg6m+1ZWFViqHnptu0dGMc6SpM6dQ2fssRkCwJoC5Sv2xFoBA1Zv FHvPMJqOcIDAT8tLoKz4Wqljt5Gz2L55NcvNCpKZdHZHLQKL3LKfw6jBG+QUWDfG 8myaLv6n5dgWI/5PssYjVKCul+1Y= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:MIME-Version:Received:Received:Received:Received:To:Subject:Message-Id:Date:From:X-Gm-Message-State:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=BGhwuFjUL3s/r2k44padsKJ5bpANPzAOQnRiDql6lFfivmr2ayi+1AtnlGXHgM dYpdy/1qFBymut/G26VQlQxJTlvIw0PCGOAPrcFYER6oqSKYmT0J4Cn+4scFl6Qw h5YvAPVjAXcdvXDtidJ9oIyBjX1joKj01gw9mbj0UDOsA=; Received: (qmail 32692 invoked by alias); 15 Feb 2012 22:51:16 -0000 Received: (qmail 32678 invoked by uid 22791); 15 Feb 2012 22:51:13 -0000 X-SWARE-Spam-Status: No, hits=-2.3 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_LOW, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mail-gy0-f201.google.com (HELO mail-gy0-f201.google.com) (209.85.160.201) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 15 Feb 2012 22:50:21 +0000 Received: by ghy10 with SMTP id 10so210239ghy.2 for ; Wed, 15 Feb 2012 14:50:20 -0800 (PST) Received: by 10.101.183.31 with SMTP id k31mr78739anp.8.1329346220717; Wed, 15 Feb 2012 14:50:20 -0800 (PST) MIME-Version: 1.0 Received: by 10.101.183.31 with SMTP id k31mr78726anp.8.1329346220608; Wed, 15 Feb 2012 14:50:20 -0800 (PST) Received: from wpzn3.hot.corp.google.com (216-239-44-65.google.com [216.239.44.65]) by gmr-mx.google.com with ESMTPS id d68si2253176yhe.4.2012.02.15.14.50.20 (version=TLSv1/SSLv3 cipher=AES128-SHA); Wed, 15 Feb 2012 14:50:20 -0800 (PST) Received: from jade.mtv.corp.google.com (jade.mtv.corp.google.com [172.18.110.116]) by wpzn3.hot.corp.google.com (Postfix) with ESMTP id 5E294100052; Wed, 15 Feb 2012 14:50:20 -0800 (PST) Received: by jade.mtv.corp.google.com (Postfix, from userid 21482) id F2E6C222677; Wed, 15 Feb 2012 14:50:19 -0800 (PST) To: reply@codereview.appspotmail.com, dnovillo@google.com, gcc-patches@gcc.gnu.org Subject: [pph] Merge inline function definitions. (issue5677058) Message-Id: <20120215225019.F2E6C222677@jade.mtv.corp.google.com> Date: Wed, 15 Feb 2012 14:50:19 -0800 (PST) From: crowl@google.com (Lawrence Crowl) X-Gm-Message-State: ALoCoQnSFZS9BP3w9JiDJSZSRlFipNSOC5cZoVl5Jej8nQxh+09aR2CtzVRLe+nmETb2f6pcU3xyt3ZZHKf29/qV2wTpJJzTR/T0iVx3tNbC7bO5u5RNJwNLLK64RDDhoCw4T/kpq4L1lh6UIkZrjtEYXFB+aCuOO72cEPHYkYlz6zOT85hxGYI= X-IsSubscribed: yes 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 This patch merges inline functions where a plain declaration is read from a pph file after an earlier pph file provides the full definition. Making this merge happen required refactoring the several pph routines. Ideally, we should have merge versions of the common tree streamer. However, we live saving and restoring so as minimize disruption in the branch. We add four new tests, x3funcinl12.cc, x3funcinl13.cc, x4funcinl21.cc, and x4funcinl31.cc to capture the various orders of processing. The x3 tests were working. The x4 tests are now fixed. Tested on x64. --- This patch is available for review at http://codereview.appspot.com/5677058 Index: gcc/testsuite/ChangeLog.pph 2012-02-15 Lawrence Crowl * lib/dg-pph.exp: Clarify kind of test in log file. * g++.dg/pph/x0funcinl1.h: New. * g++.dg/pph/x0funcinl2.h: New. * g++.dg/pph/x0funcinl3.h: New. * g++.dg/pph/x3funcinl12.cc: New. * g++.dg/pph/x3funcinl13.cc: New. * g++.dg/pph/x4funcinl21.cc: New. * g++.dg/pph/x4funcinl31.cc: New. Index: gcc/cp/ChangeLog.pph 2012-02-15 Lawrence Crowl * pph-in.c (pph_in_merge_ld_base): Merge odr_used. (pph_in_lang_indep_tree_body): New, replacing idiom. (pph_in_merge_lang_indep_tree_body): Decl merge corresponding to above. (pph_reset_external): New, from refactoring. (pph_in_tcc_declaration_tail): Moved into pph_in_tcc_declaration. (pph_in_tcc_declaration): As above. Factor out pph_reset_external. (pph_in_nonnull_tree): New. (pph_in_merge_tcc_declaration): Do serious decl merging. (pph_in_identifier_bindings): Factor out pph_in_lang_indep_tree_body. (pph_in_merge_tree_body): Factor out pph_in_lang_indep_tree_body. Move pph_in_lang_indep_tree_body and TREE_CHAIN save/restore into pph_in_merge_tcc_declaration. Do some spacing corrections. Index: gcc/testsuite/lib/dg-pph.exp =================================================================== --- gcc/testsuite/lib/dg-pph.exp (revision 184170) +++ gcc/testsuite/lib/dg-pph.exp (working copy) @@ -34,7 +34,7 @@ proc dg-pph-hdr { subdir test options ma set nshort "$subdir/[file tail $test]" set bname "[file rootname [file tail $nshort]]" - verbose -log "\nTesting $nshort, $options" + verbose -log "\nTesting header $nshort, $options" set dg-do-what-default preparse dg-test -keep-output $test "-fpph-gen $options $mapflag $stable" "" @@ -57,7 +57,7 @@ proc dg-pph-neg { subdir test options ma set nshort "$subdir/[file tail $test]" set bname "[file rootname [file tail $nshort]]" - verbose -log "\nTesting $nshort, $options" + verbose -log "\nTesting negative $nshort, $options" set dg-do-what-default compile dg-test -keep-output $test "$options $mapflag $stable" "" @@ -86,7 +86,7 @@ proc dg-pph-pos { subdir test options ma set dg-do-what-default compile set nshort "$subdir/[file tail $test]" set bname "[file rootname [file tail $nshort]]" - verbose -log "\nTesting $nshort, $options" + verbose -log "\nTesting positive $nshort, $options" # Determine whether this is an assembly comparison test set is_exec [llength [grep $test "dg-do run"]] Index: gcc/testsuite/g++.dg/pph/x4funcinl21.cc =================================================================== --- gcc/testsuite/g++.dg/pph/x4funcinl21.cc (revision 0) +++ gcc/testsuite/g++.dg/pph/x4funcinl21.cc (revision 0) @@ -0,0 +1,7 @@ +#include "x0funcinl2.h" +#include "x0funcinl1.h" + +int main() +{ + return func() + user(); +} Index: gcc/testsuite/g++.dg/pph/x3funcinl12.cc =================================================================== --- gcc/testsuite/g++.dg/pph/x3funcinl12.cc (revision 0) +++ gcc/testsuite/g++.dg/pph/x3funcinl12.cc (revision 0) @@ -0,0 +1,7 @@ +#include "x0funcinl1.h" +#include "x0funcinl2.h" + +int main() +{ + return func() + user(); +} Index: gcc/testsuite/g++.dg/pph/x0funcinl1.h =================================================================== --- gcc/testsuite/g++.dg/pph/x0funcinl1.h (revision 0) +++ gcc/testsuite/g++.dg/pph/x0funcinl1.h (revision 0) @@ -0,0 +1,8 @@ +#ifndef X0FUNCINL1_H +#define X0FUNCINL1_H + +inline int func(); + +extern int user(); + +#endif Index: gcc/testsuite/g++.dg/pph/x4funcinl31.cc =================================================================== --- gcc/testsuite/g++.dg/pph/x4funcinl31.cc (revision 0) +++ gcc/testsuite/g++.dg/pph/x4funcinl31.cc (revision 0) @@ -0,0 +1,7 @@ +#include "x0funcinl3.h" +#include "x0funcinl1.h" + +int main() +{ + return func() + user(); +} Index: gcc/testsuite/g++.dg/pph/x0funcinl2.h =================================================================== --- gcc/testsuite/g++.dg/pph/x0funcinl2.h (revision 0) +++ gcc/testsuite/g++.dg/pph/x0funcinl2.h (revision 0) @@ -0,0 +1,9 @@ +#ifndef X0FUNCINL2_H +#define X0FUNCINL2_H + +inline int func() +{ + return 3; +} + +#endif Index: gcc/testsuite/g++.dg/pph/x3funcinl13.cc =================================================================== --- gcc/testsuite/g++.dg/pph/x3funcinl13.cc (revision 0) +++ gcc/testsuite/g++.dg/pph/x3funcinl13.cc (revision 0) @@ -0,0 +1,7 @@ +#include "x0funcinl1.h" +#include "x0funcinl3.h" + +int main() +{ + return func() + user(); +} Index: gcc/testsuite/g++.dg/pph/x0funcinl3.h =================================================================== --- gcc/testsuite/g++.dg/pph/x0funcinl3.h (revision 0) +++ gcc/testsuite/g++.dg/pph/x0funcinl3.h (revision 0) @@ -0,0 +1,14 @@ +#ifndef X0FUNCINL2_H +#define X0FUNCINL2_H + +inline int func() +{ + return 3; +} + +int user() +{ + return func(); +} + +#endif Index: gcc/cp/pph-in.c =================================================================== --- gcc/cp/pph-in.c (revision 184170) +++ gcc/cp/pph-in.c (working copy) @@ -1464,8 +1464,8 @@ pph_in_merge_ld_base (pph_stream *stream struct bitpack_d bp; bp = pph_in_bitpack (stream); - /* FIXME pph: At present, we are only merging the anticipated bit. - The rest are simply overwritten. */ + /* FIXME pph: At present, we are only merging the anticipated and odr_used + bits. The rest are simply overwritten. */ ldb->selector = bp_unpack_value (&bp, 16); ldb->language = (enum languages) bp_unpack_value (&bp, 4); ldb->use_template = bp_unpack_value (&bp, 2); @@ -1476,7 +1476,7 @@ pph_in_merge_ld_base (pph_stream *stream ldb->anticipated_p &= bp_unpack_value (&bp, 1); ldb->friend_attr = bp_unpack_value (&bp, 1); ldb->template_conv_p = bp_unpack_value (&bp, 1); - ldb->odr_used = bp_unpack_value (&bp, 1); + ldb->odr_used |= bp_unpack_value (&bp, 1); ldb->u2sel = bp_unpack_value (&bp, 1); } @@ -1622,6 +1622,87 @@ pph_in_lang_decl (pph_stream *stream, tr /********************************************************* tree base classes */ +/* Stream in the language-independent parts of EXPR's body. */ + +static void +pph_in_lang_indep_tree_body (pph_stream *stream, tree expr) +{ + struct lto_input_block *ib = stream->encoder.r.ib; + struct data_in *data_in = stream->encoder.r.data_in; + streamer_read_tree_body (ib, data_in, expr); +} + + +/* Stream in the language-independent parts of EXPR's body. */ + +static void +pph_in_merge_lang_indep_tree_body (pph_stream *stream, tree expr) +{ + enum tree_code code = TREE_CODE (expr); + bool decl_comdat; + tree decl_comdat_group; + bool decl_declared_inline; + tree decl_result; + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) + { + decl_comdat = DECL_COMDAT (expr); + decl_comdat_group = DECL_COMDAT_GROUP (expr); + /* FIXME pph: These too? + bool decl_common = DECL_COMMON (expr); + bool decl_weak = DECL_WEAK (expr); + enum symbol_visibility decl_visibility = DECL_VISIBILITY (expr); + bool decl_visibility_specified = DECL_VISIBILITY_SPECIFIED (expr); + tree decl_section_name = DECL_SECTION_NAME (expr); + */ + } + if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL)) + { + decl_declared_inline = DECL_DECLARED_INLINE_P (expr); + } + if (code == FUNCTION_DECL) + { + decl_result = DECL_RESULT (expr); + /* FIXME pph: These too? + decl_arguments = DECL_ARGUMENTS (expr); + */ + } + + /* FIXME pph: Also see the functions below for more potential fields. + unpack_ts_decl_with_vis_value_fields + lto_input_ts_decl_with_vis_tree_pointers + unpack_ts_function_decl_value_fields + lto_input_ts_decl_non_common_tree_pointers + */ + + pph_in_lang_indep_tree_body (stream, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) + { + decl_comdat ? DECL_COMDAT (expr) = true : 0; + decl_comdat_group ? DECL_COMDAT_GROUP (expr) = decl_comdat_group : 0; + /* FIXME pph: These too? + decl_common ? DECL_COMMON (expr) = true : 0; + decl_weak ? DECL_WEAK (expr) = true : 0; + decl_visibility ? DECL_VISIBILITY (expr) = decl_visibility : 0; + decl_visibility_specified ? DECL_VISIBILITY_SPECIFIED (expr) = true : 0; + decl_section_name ? DECL_SECTION_NAME (expr) = decl_section_name : 0; + */ + } + if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL)) + { + decl_declared_inline ? DECL_DECLARED_INLINE_P (expr) = true : 0; + } + if (code == FUNCTION_DECL) + { + decl_result ? DECL_RESULT (expr) = decl_result : 0; + /* FIXME pph: These too? + decl_arguments ? DECL_ARGUMENTS (expr) = decl_arguments : 0; + */ + } +} + + /* Read in the tree_common fields. */ static void @@ -1851,28 +1932,52 @@ pph_in_tcc_type (pph_stream *stream, tre } +/* Reset the external state for a function DECL. */ + +static void +pph_reset_external (tree decl) +{ + /* When the declaration was compiled originally, the parser marks + it DECL_EXTERNAL, to avoid emitting it more than once. It also + remembers the true external state in DECL_NOT_REALLY_EXTERN. So, + if both bits are set, the declaration should not be considered + external. */ + gcc_assert (DECL_LANG_SPECIFIC (decl)); + if (DECL_NOT_REALLY_EXTERN (decl) + && DECL_EXTERNAL (decl)) + { + DECL_EXTERNAL (decl) = 0; + DECL_NOT_REALLY_EXTERN (decl) = 0; + } +} + + /* Read from STREAM the body of tcc_declaration tree DECL. */ static void -pph_in_tcc_declaration_tail (pph_stream *stream, tree decl) +pph_in_tcc_declaration (pph_stream *stream, tree decl) { + pph_in_lang_decl (stream, decl); DECL_INITIAL (decl) = pph_in_tree (stream); DECL_ABSTRACT_ORIGIN (decl) = pph_in_tree (stream); - /* The tree streamer only writes DECL_CHAIN for PARM_DECL nodes. - We need to read DECL_CHAIN for variables and functions because - they are sometimes chained together in places other than regular - tree chains. For example in BINFO_VTABLEs, the decls are chained - together). */ - if (TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == FUNCTION_DECL) - DECL_CHAIN (decl) = pph_in_tree (stream); - /* Handle some individual decl nodes. */ switch (TREE_CODE (decl)) { + /* The tree streamer only writes TREE_CHAIN for PARM_DECL nodes. + We need to read TREE_CHAIN for variables and functions because + they are sometimes chained together in places other than regular + tree chains. For example in BINFO_VTABLEs, the decls are chained + together). */ + + case VAR_DECL: + TREE_CHAIN (decl) = pph_in_tree (stream); + break; + case FUNCTION_DECL: + TREE_CHAIN (decl) = pph_in_tree (stream); DECL_SAVED_TREE (decl) = pph_in_tree (stream); + pph_reset_external (decl); break; case TYPE_DECL: @@ -1887,30 +1992,18 @@ pph_in_tcc_declaration_tail (pph_stream default: break; } - - /* When the declaration was compiled originally, the parser marks - it DECL_EXTERNAL, to avoid emitting it more than once. It also - remembers the true external state in DECL_NOT_REALLY_EXTERN. So, - if both bits are set, the declaration should not be considered - external. */ - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_LANG_SPECIFIC (decl) - && DECL_NOT_REALLY_EXTERN (decl) - && DECL_EXTERNAL (decl)) - { - DECL_EXTERNAL (decl) = 0; - DECL_NOT_REALLY_EXTERN (decl) = 0; - } } -/* Read from STREAM the body of tcc_declaration tree DECL. */ +/* Read a tree from STREAM, and if non-null, assign to *FIELD. */ static void -pph_in_tcc_declaration (pph_stream *stream, tree decl) +pph_in_nonnull_tree (tree *field, pph_stream *stream) { - pph_in_lang_decl (stream, decl); - pph_in_tcc_declaration_tail (stream, decl); + tree candidate; + candidate = pph_in_tree (stream); + if (candidate) + *field = candidate; } @@ -1919,9 +2012,46 @@ pph_in_tcc_declaration (pph_stream *stre static void pph_in_merge_tcc_declaration (pph_stream *stream, tree decl) { + pph_in_merge_lang_indep_tree_body (stream, decl); pph_in_lang_decl (stream, decl); - /* FIXME pph: Some of the tail may not be necessary. */ - pph_in_tcc_declaration_tail (stream, decl); + + /* FIXME pph: Some of the following may not be necessary. */ + + pph_in_nonnull_tree (&DECL_INITIAL (decl), stream); + pph_in_nonnull_tree (&DECL_ABSTRACT_ORIGIN (decl), stream); + + /* Handle some individual decl nodes. */ + switch (TREE_CODE (decl)) + { + /* The tree streamer only writes TREE_CHAIN for PARM_DECL nodes. + We need to read TREE_CHAIN for variables and functions because + they are sometimes chained together in places other than regular + tree chains. For example in BINFO_VTABLEs, the decls are chained + together). However, in merging, we will actually ignore the new + chain, and thus not overwrite the previous one. */ + + case VAR_DECL: + /* ignore TREE_CHAIN (decl) = */ pph_in_tree (stream); + break; + + case FUNCTION_DECL: + /* ignore TREE_CHAIN (decl) = */ pph_in_tree (stream); + pph_in_nonnull_tree (&DECL_SAVED_TREE (decl), stream); + pph_reset_external (decl); + break; + + case TYPE_DECL: + DECL_ORIGINAL_TYPE (decl) = pph_in_tree (stream); + break; + + case TEMPLATE_DECL: + DECL_TEMPLATE_RESULT (decl) = pph_in_tree (stream); + DECL_TEMPLATE_PARMS (decl) = pph_in_tree (stream); + break; + + default: + break; + } } @@ -1946,12 +2076,9 @@ pph_in_identifier_bindings (pph_stream * static void pph_in_tree_body (pph_stream *stream, tree expr) { - struct lto_input_block *ib = stream->encoder.r.ib; - struct data_in *data_in = stream->encoder.r.data_in; bool handled_p; - /* Read the language-independent parts of EXPR's body. */ - streamer_read_tree_body (ib, data_in, expr); + pph_in_lang_indep_tree_body (stream, expr); /* Handle common tree code classes first. */ handled_p = true; @@ -2119,35 +2246,24 @@ pph_in_tree_body (pph_stream *stream, tr static void pph_in_merge_tree_body (pph_stream *stream, tree expr) { - struct lto_input_block *ib = stream->encoder.r.ib; - struct data_in *data_in = stream->encoder.r.data_in; - - /* Read the language-independent parts of EXPR's body. */ - streamer_read_tree_body (ib, data_in, expr); - /* Handle common tree code classes first. */ switch (TREE_CODE_CLASS (TREE_CODE (expr))) { case tcc_declaration: { - /* If we are reading a merge body, it means that EXPR is already in - some chain. Given that EXPR may now be in a different location - in the chain, we need to make sure we do not lose it. - FIXME pph: We should just not save TREE_CHAIN for merge bodies. */ - tree saved_expr_chain = TREE_CHAIN (expr); - pph_in_merge_tcc_declaration (stream, expr); - TREE_CHAIN (expr) = saved_expr_chain; + pph_in_merge_tcc_declaration (stream, expr); } break; case tcc_type: - pph_in_tcc_type (stream, expr); - break; + pph_in_lang_indep_tree_body (stream, expr); + pph_in_tcc_type (stream, expr); + break; default: - fatal_error ("PPH: unrecognized tree node '%s'", - pph_tree_code_text (TREE_CODE (expr))); - break; + fatal_error ("PPH: unrecognized tree node '%s'", + pph_tree_code_text (TREE_CODE (expr))); + break; } }