From patchwork Fri Jul 11 17:47:41 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Hubicka X-Patchwork-Id: 369213 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 92511140088 for ; Sat, 12 Jul 2014 03:48:06 +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:cc:subject:message-id:references:mime-version :content-type:in-reply-to; q=dns; s=default; b=RjdMD0Vd3U5JX0aFb 2nsPMSyGWFVGsSiB4ta4NFk5TZwgEVsthbu9VkaSboDh49TQbRjHtqydFbBPpQy4 3IUpQok5EnzkyKhhX5XR5R8OLN1PpFaFff2T/nTG/ROi+weu1f8W/PnBiDCN7kbV fyBoty/KyT6SsjJox9rt+a3W4U= 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:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=default; bh=QH2qOp9W1quAts9tWMJfi9e m/LI=; b=lGs/BYsKF1lpGHFoOyszl5SF6/nHv56WeWWgdQXjizaVJbn/w5qU7g0 48KkYuf1pBDRWQDddRiE3dZ8mVZefSbcv552ck4dThLp0zApqDBLLCB4Oai5dOmb QwNAqVpEz+3yN6y3AY3c2yriDb6hCsd8J0WY+qTqc11RwpFCtZVw= Received: (qmail 12132 invoked by alias); 11 Jul 2014 17:47:55 -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 11797 invoked by uid 89); 11 Jul 2014 17:47:51 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.0 required=5.0 tests=AWL, BAYES_99, RCVD_IN_DNSWL_LOW, RP_MATCHES_RCVD autolearn=no 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, 11 Jul 2014 17:47:45 +0000 Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id 9C609543B54; Fri, 11 Jul 2014 19:47:41 +0200 (CEST) Date: Fri, 11 Jul 2014 19:47:41 +0200 From: Jan Hubicka To: Jan Hubicka Cc: Richard Biener , gcc-patches@gcc.gnu.org Subject: Re: Use separate sections to stream non-trivial constructors Message-ID: <20140711174741.GA27781@kam.mff.cuni.cz> References: <20140711091810.GC30037@kam.mff.cuni.cz> <20140711115320.GA27809@atrey.karlin.mff.cuni.cz> <20140711120855.GD11760@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20140711120855.GD11760@kam.mff.cuni.cz> User-Agent: Mutt/1.5.21 (2010-09-15) Hi, this is the variant of patch I comitted. I noticed that partitioning actually calls ctor_for_folding just to figure out if the constant value may be used that drags in every readonly variable ctor into memory at WPA. So now we have separate predicate varpool_ctor_useable_for_folding_p to check if ctor can be used and ctor_for_folding to drag in the actual value. This actually happens too late to show in LTO report. In followup patch I will add timevar for the delayed streaming so we have some idea how often it triggers and how much memory it takes. Bootstrapped/regtested x86_64-linux and comitted. Honza * vapool.c: Include tree-ssa-alias.h, gimple.h and lto-streamer.h (varpool_get_constructor): New function. (varpool_ctor_useable_for_folding_p): Break out from ... (ctor_for_folding): ... here; use varpool_get_constructor. (varpool_assemble_decl): Likewise. * lto-streamer.h (struct output_block): Turn cgraph_node to symbol filed. (lto_input_variable_constructor): Declare. * ipa-visibility.c (function_and_variable_visibility): Use varpool_get_constructor. * cgraph.h (varpool_get_constructor): Declare. (varpool_ctor_useable_for_folding_p): New function. * lto-streamer-out.c (get_symbol_initial_value): Take encoder parameter; return error_mark_node for non-trivial constructors. (lto_write_tree_1, DFS_write_tree): UPdate use of get_symbol_initial_value. (output_function): Update initialization of symbol. (output_constructor): New function. (copy_function): Rename to .. (copy_function_or_variable): ... this one; handle vars too. (lto_output): Output variable sections. * lto-streamer-in.c (input_constructor): New function. (lto_read_body): Rename from ... (lto_read_body_or_constructor): ... this one; handle vars too. (lto_input_variable_constructor): New function. * ipa-prop.c (ipa_prop_write_jump_functions, ipa_prop_write_all_agg_replacement): Update. * lto-cgraph.c (compute_ltrans_boundary): Use it. (output_cgraph_opt_summary): Set symbol to NULL. * lto-partition.c (add_references_to_partition): Use varpool_ctor_useable_for_folding_p. * lto.c (lto_read_in_decl_state): Update sanity check. Index: ipa-visibility.c =================================================================== --- ipa-visibility.c (revision 212457) +++ ipa-visibility.c (working copy) @@ -686,6 +686,8 @@ function_and_variable_visibility (bool w if (found) { struct pointer_set_t *visited_nodes = pointer_set_create (); + + varpool_get_constructor (vnode); walk_tree (&DECL_INITIAL (vnode->decl), update_vtable_references, NULL, visited_nodes); pointer_set_destroy (visited_nodes); Index: lto/lto.c =================================================================== --- lto/lto.c (revision 212457) +++ lto/lto.c (working copy) @@ -236,7 +236,7 @@ lto_read_in_decl_state (struct data_in * ix = *data++; decl = streamer_tree_cache_get_tree (data_in->reader_cache, ix); - if (TREE_CODE (decl) != FUNCTION_DECL) + if (!VAR_OR_FUNCTION_DECL_P (decl)) { gcc_assert (decl == void_type_node); decl = NULL_TREE; Index: lto/lto-partition.c =================================================================== --- lto/lto-partition.c (revision 212457) +++ lto/lto-partition.c (working copy) @@ -96,7 +96,7 @@ add_references_to_partition (ltrans_part Recursively look into the initializers of the constant variable and add references, too. */ else if (is_a (ref->referred) - && ctor_for_folding (ref->referred->decl) != error_mark_node + && varpool_ctor_useable_for_folding_p (varpool (ref->referred)) && !lto_symtab_encoder_in_partition_p (part->encoder, ref->referred)) { if (!part->initializers_visited) Index: lto-cgraph.c =================================================================== --- lto-cgraph.c (revision 212457) +++ lto-cgraph.c (working copy) @@ -867,7 +867,7 @@ compute_ltrans_boundary (lto_symtab_enco { if (!lto_symtab_encoder_encode_initializer_p (encoder, vnode) - && ctor_for_folding (vnode->decl) != error_mark_node) + && varpool_ctor_useable_for_folding_p (vnode)) { lto_set_symtab_encoder_encode_initializer (encoder, vnode); add_references (encoder, vnode); @@ -1808,7 +1808,7 @@ output_cgraph_opt_summary (void) struct output_block *ob = create_output_block (LTO_section_cgraph_opt_sum); unsigned count = 0; - ob->cgraph_node = NULL; + ob->symbol = NULL; encoder = ob->decl_state->symtab_node_encoder; n_nodes = lto_symtab_encoder_size (encoder); for (i = 0; i < n_nodes; i++) Index: ipa-prop.c =================================================================== --- ipa-prop.c (revision 212466) +++ ipa-prop.c (working copy) @@ -4848,7 +4848,7 @@ ipa_prop_write_jump_functions (void) ob = create_output_block (LTO_section_jump_functions); encoder = ob->decl_state->symtab_node_encoder; - ob->cgraph_node = NULL; + ob->symbol = NULL; for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei); lsei_next_function_in_partition (&lsei)) { @@ -5024,7 +5024,7 @@ ipa_prop_write_all_agg_replacement (void ob = create_output_block (LTO_section_ipcp_transform); encoder = ob->decl_state->symtab_node_encoder; - ob->cgraph_node = NULL; + ob->symbol = NULL; for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei); lsei_next_function_in_partition (&lsei)) { Index: cgraph.h =================================================================== --- cgraph.h (revision 212457) +++ cgraph.h (working copy) @@ -1134,6 +1134,7 @@ void varpool_analyze_node (varpool_node varpool_node * varpool_extra_name_alias (tree, tree); varpool_node * varpool_create_variable_alias (tree, tree); void varpool_reset_queue (void); +bool varpool_ctor_useable_for_folding_p (varpool_node *); tree ctor_for_folding (tree); bool varpool_for_node_and_aliases (varpool_node *, bool (*) (varpool_node *, void *), @@ -1142,6 +1143,7 @@ void varpool_add_new_variable (tree); void symtab_initialize_asm_name_hash (void); void symtab_prevail_in_asm_name_hash (symtab_node *node); void varpool_remove_initializer (varpool_node *); +tree varpool_get_constructor (struct varpool_node *node); /* In cgraph.c */ extern void change_decl_assembler_name (tree, tree); Index: lto-streamer.h =================================================================== --- lto-streamer.h (revision 212457) +++ lto-streamer.h (working copy) @@ -685,9 +685,9 @@ struct output_block far and the indexes assigned to them. */ hash_table *string_hash_table; - /* The current cgraph_node that we are currently serializing. Null + /* The current symbol that we are currently serializing. Null if we are serializing something else. */ - struct cgraph_node *cgraph_node; + struct symtab_node *symbol; /* These are the last file and line that were seen in the stream. If the current node differs from these, it needs to insert @@ -830,6 +830,9 @@ extern void lto_reader_init (void); extern void lto_input_function_body (struct lto_file_decl_data *, struct cgraph_node *, const char *); +extern void lto_input_variable_constructor (struct lto_file_decl_data *, + struct varpool_node *, + const char *); extern void lto_input_constructors_and_inits (struct lto_file_decl_data *, const char *); extern void lto_input_toplevel_asms (struct lto_file_decl_data *, int); Index: varpool.c =================================================================== --- varpool.c (revision 212457) +++ varpool.c (working copy) @@ -35,6 +35,9 @@ along with GCC; see the file COPYING3. #include "gimple-expr.h" #include "flags.h" #include "pointer-set.h" +#include "tree-ssa-alias.h" +#include "gimple.h" +#include "lto-streamer.h" const char * const tls_model_names[]={"none", "tls-emulated", "tls-real", "tls-global-dynamic", "tls-local-dynamic", @@ -163,19 +166,17 @@ varpool_node_for_decl (tree decl) void varpool_remove_node (varpool_node *node) { - tree init; varpool_call_node_removal_hooks (node); symtab_unregister_node (node); - /* Because we remove references from external functions before final compilation, - we may end up removing useful constructors. - FIXME: We probably want to trace boundaries better. */ + /* When streaming we can have multiple nodes associated with decl. */ if (cgraph_state == CGRAPH_LTO_STREAMING) ; - else if ((init = ctor_for_folding (node->decl)) == error_mark_node) + /* Keep constructor when it may be used for folding. We remove + references to external variables before final compilation. */ + else if (DECL_INITIAL (node->decl) && DECL_INITIAL (node->decl) != error_mark_node + && !varpool_ctor_useable_for_folding_p (node)) varpool_remove_initializer (node); - else - DECL_INITIAL (node->decl) = init; ggc_free (node); } @@ -215,7 +216,7 @@ dump_varpool_node (FILE *f, varpool_node fprintf (f, " used-by-single-function"); if (TREE_READONLY (node->decl)) fprintf (f, " read-only"); - if (ctor_for_folding (node->decl) != error_mark_node) + if (varpool_ctor_useable_for_folding_p (node)) fprintf (f, " const-value-known"); if (node->writeonly) fprintf (f, " write-only"); @@ -253,9 +254,101 @@ varpool_node_for_asm (tree asmname) return NULL; } -/* Return if DECL is constant and its initial value is known (so we can do - constant folding using DECL_INITIAL (decl)). - Return ERROR_MARK_NODE when value is unknown. */ +/* When doing LTO, read NODE's constructor from disk if it is not already present. */ + +tree +varpool_get_constructor (struct varpool_node *node) +{ + struct lto_file_decl_data *file_data; + const char *data, *name; + size_t len; + tree decl = node->decl; + + if (DECL_INITIAL (node->decl) != error_mark_node + || !in_lto_p) + return DECL_INITIAL (node->decl); + + file_data = node->lto_file_data; + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + + /* We may have renamed the declaration, e.g., a static function. */ + name = lto_get_decl_name_mapping (file_data, name); + + data = lto_get_section_data (file_data, LTO_section_function_body, + name, &len); + if (!data) + fatal_error ("%s: section %s is missing", + file_data->file_name, + name); + + lto_input_variable_constructor (file_data, node, data); + lto_stats.num_function_bodies++; + lto_free_section_data (file_data, LTO_section_function_body, name, + data, len); + lto_free_function_in_decl_state_for_node (node); + return DECL_INITIAL (node->decl); +} + +/* Return ture if NODE has constructor that can be used for folding. */ + +bool +varpool_ctor_useable_for_folding_p (varpool_node *node) +{ + varpool_node *real_node = node; + + if (real_node->alias && real_node->definition) + real_node = varpool_variable_node (node); + + if (TREE_CODE (node->decl) == CONST_DECL + || DECL_IN_CONSTANT_POOL (node->decl)) + return true; + if (TREE_THIS_VOLATILE (node->decl)) + return false; + + /* If we do not have a constructor, we can't use it. */ + if (DECL_INITIAL (real_node->decl) == error_mark_node + && !real_node->lto_file_data) + return false; + + /* Vtables are defined by their types and must match no matter of interposition + rules. */ + if (DECL_VIRTUAL_P (node->decl)) + { + /* The C++ front end creates VAR_DECLs for vtables of typeinfo + classes not defined in the current TU so that it can refer + to them from typeinfo objects. Avoid returning NULL_TREE. */ + return DECL_INITIAL (real_node->decl) != NULL; + } + + /* Alias of readonly variable is also readonly, since the variable is stored + in readonly memory. We also accept readonly aliases of non-readonly + locations assuming that user knows what he is asking for. */ + if (!TREE_READONLY (node->decl) && !TREE_READONLY (real_node->decl)) + return false; + + /* Variables declared 'const' without an initializer + have zero as the initializer if they may not be + overridden at link or run time. */ + if (!DECL_INITIAL (real_node->decl) + && (DECL_EXTERNAL (node->decl) || decl_replaceable_p (node->decl))) + return false; + + /* Variables declared `const' with an initializer are considered + to not be overwritable with different initializer by default. + + ??? Previously we behaved so for scalar variables but not for array + accesses. */ + return true; +} + +/* If DECL is constant variable and its initial value is known (so we can + do constant folding), return its constructor (DECL_INITIAL). This may + be an expression or NULL when DECL is initialized to 0. + Return ERROR_MARK_NODE otherwise. + + In LTO this may actually trigger reading the constructor from disk. + For this reason varpool_ctor_useable_for_folding_p should be used when + the actual constructor value is not needed. */ tree ctor_for_folding (tree decl) @@ -284,7 +377,7 @@ ctor_for_folding (tree decl) gcc_assert (TREE_CODE (decl) == VAR_DECL); - node = varpool_get_node (decl); + real_node = node = varpool_get_node (decl); if (node) { real_node = varpool_variable_node (node); @@ -302,54 +395,25 @@ ctor_for_folding (tree decl) { gcc_assert (!DECL_INITIAL (decl) || DECL_INITIAL (decl) == error_mark_node); - if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))) + if (node->weakref) { node = varpool_alias_target (node); decl = node->decl; } } - /* Vtables are defined by their types and must match no matter of interposition - rules. */ - if (DECL_VIRTUAL_P (real_decl)) - { - gcc_checking_assert (TREE_READONLY (real_decl)); - if (DECL_INITIAL (real_decl)) - return DECL_INITIAL (real_decl); - else - { - /* The C++ front end creates VAR_DECLs for vtables of typeinfo - classes not defined in the current TU so that it can refer - to them from typeinfo objects. Avoid returning NULL_TREE. */ - gcc_checking_assert (!COMPLETE_TYPE_P (DECL_CONTEXT (real_decl))); - return error_mark_node; - } - } - - /* If there is no constructor, we have nothing to do. */ - if (DECL_INITIAL (real_decl) == error_mark_node) - return error_mark_node; - - /* Non-readonly alias of readonly variable is also de-facto readonly, - because the variable itself is in readonly section. - We also honnor READONLY flag on alias assuming that user knows - what he is doing. */ - if (!TREE_READONLY (decl) && !TREE_READONLY (real_decl)) - return error_mark_node; - - /* Variables declared 'const' without an initializer - have zero as the initializer if they may not be - overridden at link or run time. */ - if (!DECL_INITIAL (real_decl) - && (DECL_EXTERNAL (decl) || decl_replaceable_p (decl))) + if ((!DECL_VIRTUAL_P (real_decl) + || DECL_INITIAL (real_decl) == error_mark_node + || !DECL_INITIAL (real_decl)) + && (!node || !varpool_ctor_useable_for_folding_p (node))) return error_mark_node; - /* Variables declared `const' with an initializer are considered - to not be overwritable with different initializer by default. - - ??? Previously we behaved so for scalar variables but not for array - accesses. */ - return DECL_INITIAL (real_decl); + /* OK, we can return constructor. See if we need to fetch it from disk + in LTO mode. */ + if (DECL_INITIAL (real_decl) != error_mark_node + || !in_lto_p) + return DECL_INITIAL (real_decl); + return varpool_get_constructor (real_node); } /* Add the variable DECL to the varpool. @@ -471,6 +535,7 @@ varpool_assemble_decl (varpool_node *nod if (!node->in_other_partition && !DECL_EXTERNAL (decl)) { + varpool_get_constructor (node); assemble_variable (decl, 0, 1, 0); gcc_assert (TREE_ASM_WRITTEN (decl)); node->definition = true; Index: lto-streamer-in.c =================================================================== --- lto-streamer-in.c (revision 212457) +++ lto-streamer-in.c (working copy) @@ -1029,6 +1029,15 @@ input_function (tree fn_decl, struct dat pop_cfun (); } +/* Read the body of function FN_DECL from DATA_IN using input block IB. */ + +static void +input_constructor (tree var, struct data_in *data_in, + struct lto_input_block *ib) +{ + DECL_INITIAL (var) = stream_read_tree (ib, data_in); +} + /* Read the body from DATA for function NODE and fill it in. FILE_DATA are the global decls and types. SECTION_TYPE is either @@ -1037,8 +1046,8 @@ input_function (tree fn_decl, struct dat that function. */ static void -lto_read_body (struct lto_file_decl_data *file_data, struct cgraph_node *node, - const char *data, enum lto_section_type section_type) +lto_read_body_or_constructor (struct lto_file_decl_data *file_data, struct symtab_node *node, + const char *data, enum lto_section_type section_type) { const struct lto_function_header *header; struct data_in *data_in; @@ -1050,19 +1059,32 @@ lto_read_body (struct lto_file_decl_data tree fn_decl = node->decl; header = (const struct lto_function_header *) data; - cfg_offset = sizeof (struct lto_function_header); - main_offset = cfg_offset + header->cfg_size; - string_offset = main_offset + header->main_size; - - LTO_INIT_INPUT_BLOCK (ib_cfg, - data + cfg_offset, - 0, - header->cfg_size); - - LTO_INIT_INPUT_BLOCK (ib_main, - data + main_offset, - 0, - header->main_size); + if (TREE_CODE (node->decl) == FUNCTION_DECL) + { + cfg_offset = sizeof (struct lto_function_header); + main_offset = cfg_offset + header->cfg_size; + string_offset = main_offset + header->main_size; + + LTO_INIT_INPUT_BLOCK (ib_cfg, + data + cfg_offset, + 0, + header->cfg_size); + + LTO_INIT_INPUT_BLOCK (ib_main, + data + main_offset, + 0, + header->main_size); + } + else + { + main_offset = sizeof (struct lto_function_header); + string_offset = main_offset + header->main_size; + + LTO_INIT_INPUT_BLOCK (ib_main, + data + main_offset, + 0, + header->main_size); + } data_in = lto_data_in_create (file_data, data + string_offset, header->string_size, vNULL); @@ -1082,7 +1104,10 @@ lto_read_body (struct lto_file_decl_data /* Set up the struct function. */ from = data_in->reader_cache->nodes.length (); - input_function (fn_decl, data_in, &ib_main, &ib_cfg); + if (TREE_CODE (node->decl) == FUNCTION_DECL) + input_function (fn_decl, data_in, &ib_main, &ib_cfg); + else + input_constructor (fn_decl, data_in, &ib_main); /* And fixup types we streamed locally. */ { struct streamer_tree_cache_d *cache = data_in->reader_cache; @@ -1124,7 +1149,17 @@ void lto_input_function_body (struct lto_file_decl_data *file_data, struct cgraph_node *node, const char *data) { - lto_read_body (file_data, node, data, LTO_section_function_body); + lto_read_body_or_constructor (file_data, node, data, LTO_section_function_body); +} + +/* Read the body of NODE using DATA. FILE_DATA holds the global + decls and types. */ + +void +lto_input_variable_constructor (struct lto_file_decl_data *file_data, + struct varpool_node *node, const char *data) +{ + lto_read_body_or_constructor (file_data, node, data, LTO_section_function_body); } Index: lto-streamer-out.c =================================================================== --- lto-streamer-out.c (revision 212457) +++ lto-streamer-out.c (working copy) @@ -318,7 +318,7 @@ lto_is_streamable (tree expr) /* For EXPR lookup and return what we want to stream to OB as DECL_INITIAL. */ static tree -get_symbol_initial_value (struct output_block *ob, tree expr) +get_symbol_initial_value (lto_symtab_encoder_t encoder, tree expr) { gcc_checking_assert (DECL_P (expr) && TREE_CODE (expr) != FUNCTION_DECL @@ -331,15 +331,13 @@ get_symbol_initial_value (struct output_ && !DECL_IN_CONSTANT_POOL (expr) && initial) { - lto_symtab_encoder_t encoder; varpool_node *vnode; - - encoder = ob->decl_state->symtab_node_encoder; - vnode = varpool_get_node (expr); - if (!vnode - || !lto_symtab_encoder_encode_initializer_p (encoder, - vnode)) - initial = error_mark_node; + /* Extra section needs about 30 bytes; do not produce it for simple + scalar values. */ + if (TREE_CODE (DECL_INITIAL (expr)) == CONSTRUCTOR + || !(vnode = varpool_get_node (expr)) + || !lto_symtab_encoder_encode_initializer_p (encoder, vnode)) + initial = error_mark_node; } return initial; @@ -369,7 +367,8 @@ lto_write_tree_1 (struct output_block *o && TREE_CODE (expr) != TRANSLATION_UNIT_DECL) { /* Handle DECL_INITIAL for symbols. */ - tree initial = get_symbol_initial_value (ob, expr); + tree initial = get_symbol_initial_value + (ob->decl_state->symtab_node_encoder, expr); stream_write_tree (ob, initial, ref_p); } } @@ -1195,7 +1194,8 @@ DFS_write_tree (struct output_block *ob, && TREE_CODE (expr) != TRANSLATION_UNIT_DECL) { /* Handle DECL_INITIAL for symbols. */ - tree initial = get_symbol_initial_value (ob, expr); + tree initial = get_symbol_initial_value (ob->decl_state->symtab_node_encoder, + expr); DFS_write_tree (ob, cstate, initial, ref_p, ref_p); } } @@ -1808,7 +1808,7 @@ output_function (struct cgraph_node *nod ob = create_output_block (LTO_section_function_body); clear_line_info (ob); - ob->cgraph_node = node; + ob->symbol = node; gcc_assert (current_function_decl == NULL_TREE && cfun == NULL); @@ -1899,6 +1899,32 @@ output_function (struct cgraph_node *nod destroy_output_block (ob); } +/* Output the body of function NODE->DECL. */ + +static void +output_constructor (struct varpool_node *node) +{ + tree var = node->decl; + struct output_block *ob; + + ob = create_output_block (LTO_section_function_body); + + clear_line_info (ob); + ob->symbol = node; + + /* Make string 0 be a NULL string. */ + streamer_write_char_stream (ob->string_stream, 0); + + /* Output DECL_INITIAL for the function, which contains the tree of + lexical scopes. */ + stream_write_tree (ob, DECL_INITIAL (var), true); + + /* Create a section to hold the pickled output of this function. */ + produce_asm (ob, var); + + destroy_output_block (ob); +} + /* Emit toplevel asms. */ @@ -1957,10 +1983,10 @@ lto_output_toplevel_asms (void) } -/* Copy the function body of NODE without deserializing. */ +/* Copy the function body or variable constructor of NODE without deserializing. */ static void -copy_function (struct cgraph_node *node) +copy_function_or_variable (struct symtab_node *node) { tree function = node->decl; struct lto_file_decl_data *file_data = node->lto_file_data; @@ -2072,7 +2098,7 @@ lto_output (void) if (gimple_has_body_p (node->decl) || !flag_wpa) output_function (node); else - copy_function (node); + copy_function_or_variable (node); gcc_assert (lto_get_out_decl_state () == decl_state); lto_pop_out_decl_state (); lto_record_function_out_decl_state (node->decl, decl_state); @@ -2085,6 +2111,25 @@ lto_output (void) tree ctor = DECL_INITIAL (node->decl); if (ctor && !in_lto_p) walk_tree (&ctor, wrap_refs, NULL, NULL); + if (get_symbol_initial_value (encoder, node->decl) == error_mark_node + && lto_symtab_encoder_encode_initializer_p (encoder, node) + && !node->alias) + { +#ifdef ENABLE_CHECKING + gcc_assert (!bitmap_bit_p (output, DECL_UID (node->decl))); + bitmap_set_bit (output, DECL_UID (node->decl)); +#endif + decl_state = lto_new_out_decl_state (); + lto_push_out_decl_state (decl_state); + if (DECL_INITIAL (node->decl) != error_mark_node + || !flag_wpa) + output_constructor (node); + else + copy_function_or_variable (node); + gcc_assert (lto_get_out_decl_state () == decl_state); + lto_pop_out_decl_state (); + lto_record_function_out_decl_state (node->decl, decl_state); + } } }