Commit 0b83e688 by Jan Hubicka Committed by Jan Hubicka

vapool.c: Include tree-ssa-alias.h, gimple.h and lto-streamer.h


	* 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.

From-SVN: r212467
parent 01a92e70
2014-07-11 Jan Hubicka <hubicka@ucw.cz> 2014-07-11 Jan Hubicka <hubicka@ucw.cz>
* 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.
2014-07-11 Jan Hubicka <hubicka@ucw.cz>
* ipa-prop.c (ipa_binfo_from_known_type_jfunc): In LTO do not walk * ipa-prop.c (ipa_binfo_from_known_type_jfunc): In LTO do not walk
non-polymorphic types. non-polymorphic types.
* ipa-cp.c (ipa_get_jf_ancestor_result): Likewise. * ipa-cp.c (ipa_get_jf_ancestor_result): Likewise.
......
...@@ -1134,6 +1134,7 @@ void varpool_analyze_node (varpool_node *); ...@@ -1134,6 +1134,7 @@ void varpool_analyze_node (varpool_node *);
varpool_node * varpool_extra_name_alias (tree, tree); varpool_node * varpool_extra_name_alias (tree, tree);
varpool_node * varpool_create_variable_alias (tree, tree); varpool_node * varpool_create_variable_alias (tree, tree);
void varpool_reset_queue (void); void varpool_reset_queue (void);
bool varpool_ctor_useable_for_folding_p (varpool_node *);
tree ctor_for_folding (tree); tree ctor_for_folding (tree);
bool varpool_for_node_and_aliases (varpool_node *, bool varpool_for_node_and_aliases (varpool_node *,
bool (*) (varpool_node *, void *), bool (*) (varpool_node *, void *),
...@@ -1142,6 +1143,7 @@ void varpool_add_new_variable (tree); ...@@ -1142,6 +1143,7 @@ void varpool_add_new_variable (tree);
void symtab_initialize_asm_name_hash (void); void symtab_initialize_asm_name_hash (void);
void symtab_prevail_in_asm_name_hash (symtab_node *node); void symtab_prevail_in_asm_name_hash (symtab_node *node);
void varpool_remove_initializer (varpool_node *); void varpool_remove_initializer (varpool_node *);
tree varpool_get_constructor (struct varpool_node *node);
/* In cgraph.c */ /* In cgraph.c */
extern void change_decl_assembler_name (tree, tree); extern void change_decl_assembler_name (tree, tree);
......
...@@ -4848,7 +4848,7 @@ ipa_prop_write_jump_functions (void) ...@@ -4848,7 +4848,7 @@ ipa_prop_write_jump_functions (void)
ob = create_output_block (LTO_section_jump_functions); ob = create_output_block (LTO_section_jump_functions);
encoder = ob->decl_state->symtab_node_encoder; 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); for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei);
lsei_next_function_in_partition (&lsei)) lsei_next_function_in_partition (&lsei))
{ {
...@@ -5024,7 +5024,7 @@ ipa_prop_write_all_agg_replacement (void) ...@@ -5024,7 +5024,7 @@ ipa_prop_write_all_agg_replacement (void)
ob = create_output_block (LTO_section_ipcp_transform); ob = create_output_block (LTO_section_ipcp_transform);
encoder = ob->decl_state->symtab_node_encoder; 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); for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei);
lsei_next_function_in_partition (&lsei)) lsei_next_function_in_partition (&lsei))
{ {
......
...@@ -686,6 +686,8 @@ function_and_variable_visibility (bool whole_program) ...@@ -686,6 +686,8 @@ function_and_variable_visibility (bool whole_program)
if (found) if (found)
{ {
struct pointer_set_t *visited_nodes = pointer_set_create (); struct pointer_set_t *visited_nodes = pointer_set_create ();
varpool_get_constructor (vnode);
walk_tree (&DECL_INITIAL (vnode->decl), walk_tree (&DECL_INITIAL (vnode->decl),
update_vtable_references, NULL, visited_nodes); update_vtable_references, NULL, visited_nodes);
pointer_set_destroy (visited_nodes); pointer_set_destroy (visited_nodes);
......
...@@ -867,7 +867,7 @@ compute_ltrans_boundary (lto_symtab_encoder_t in_encoder) ...@@ -867,7 +867,7 @@ compute_ltrans_boundary (lto_symtab_encoder_t in_encoder)
{ {
if (!lto_symtab_encoder_encode_initializer_p (encoder, if (!lto_symtab_encoder_encode_initializer_p (encoder,
vnode) vnode)
&& ctor_for_folding (vnode->decl) != error_mark_node) && varpool_ctor_useable_for_folding_p (vnode))
{ {
lto_set_symtab_encoder_encode_initializer (encoder, vnode); lto_set_symtab_encoder_encode_initializer (encoder, vnode);
add_references (encoder, vnode); add_references (encoder, vnode);
...@@ -1808,7 +1808,7 @@ output_cgraph_opt_summary (void) ...@@ -1808,7 +1808,7 @@ output_cgraph_opt_summary (void)
struct output_block *ob = create_output_block (LTO_section_cgraph_opt_sum); struct output_block *ob = create_output_block (LTO_section_cgraph_opt_sum);
unsigned count = 0; unsigned count = 0;
ob->cgraph_node = NULL; ob->symbol = NULL;
encoder = ob->decl_state->symtab_node_encoder; encoder = ob->decl_state->symtab_node_encoder;
n_nodes = lto_symtab_encoder_size (encoder); n_nodes = lto_symtab_encoder_size (encoder);
for (i = 0; i < n_nodes; i++) for (i = 0; i < n_nodes; i++)
......
...@@ -1029,6 +1029,15 @@ input_function (tree fn_decl, struct data_in *data_in, ...@@ -1029,6 +1029,15 @@ input_function (tree fn_decl, struct data_in *data_in,
pop_cfun (); 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. /* Read the body from DATA for function NODE and fill it in.
FILE_DATA are the global decls and types. SECTION_TYPE is either FILE_DATA are the global decls and types. SECTION_TYPE is either
...@@ -1037,8 +1046,8 @@ input_function (tree fn_decl, struct data_in *data_in, ...@@ -1037,8 +1046,8 @@ input_function (tree fn_decl, struct data_in *data_in,
that function. */ that function. */
static void static void
lto_read_body (struct lto_file_decl_data *file_data, struct cgraph_node *node, 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 char *data, enum lto_section_type section_type)
{ {
const struct lto_function_header *header; const struct lto_function_header *header;
struct data_in *data_in; struct data_in *data_in;
...@@ -1050,19 +1059,32 @@ lto_read_body (struct lto_file_decl_data *file_data, struct cgraph_node *node, ...@@ -1050,19 +1059,32 @@ lto_read_body (struct lto_file_decl_data *file_data, struct cgraph_node *node,
tree fn_decl = node->decl; tree fn_decl = node->decl;
header = (const struct lto_function_header *) data; header = (const struct lto_function_header *) data;
cfg_offset = sizeof (struct lto_function_header); if (TREE_CODE (node->decl) == FUNCTION_DECL)
main_offset = cfg_offset + header->cfg_size; {
string_offset = main_offset + header->main_size; cfg_offset = sizeof (struct lto_function_header);
main_offset = cfg_offset + header->cfg_size;
LTO_INIT_INPUT_BLOCK (ib_cfg, string_offset = main_offset + header->main_size;
data + cfg_offset,
0, LTO_INIT_INPUT_BLOCK (ib_cfg,
header->cfg_size); 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, LTO_INIT_INPUT_BLOCK (ib_main,
data + main_offset, data + main_offset,
0, 0,
header->main_size); header->main_size);
}
data_in = lto_data_in_create (file_data, data + string_offset, data_in = lto_data_in_create (file_data, data + string_offset,
header->string_size, vNULL); header->string_size, vNULL);
...@@ -1082,7 +1104,10 @@ lto_read_body (struct lto_file_decl_data *file_data, struct cgraph_node *node, ...@@ -1082,7 +1104,10 @@ lto_read_body (struct lto_file_decl_data *file_data, struct cgraph_node *node,
/* Set up the struct function. */ /* Set up the struct function. */
from = data_in->reader_cache->nodes.length (); 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. */ /* And fixup types we streamed locally. */
{ {
struct streamer_tree_cache_d *cache = data_in->reader_cache; struct streamer_tree_cache_d *cache = data_in->reader_cache;
...@@ -1124,7 +1149,17 @@ void ...@@ -1124,7 +1149,17 @@ void
lto_input_function_body (struct lto_file_decl_data *file_data, lto_input_function_body (struct lto_file_decl_data *file_data,
struct cgraph_node *node, const char *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);
} }
......
...@@ -318,7 +318,7 @@ lto_is_streamable (tree expr) ...@@ -318,7 +318,7 @@ lto_is_streamable (tree expr)
/* For EXPR lookup and return what we want to stream to OB as DECL_INITIAL. */ /* For EXPR lookup and return what we want to stream to OB as DECL_INITIAL. */
static tree 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) gcc_checking_assert (DECL_P (expr)
&& TREE_CODE (expr) != FUNCTION_DECL && TREE_CODE (expr) != FUNCTION_DECL
...@@ -331,15 +331,13 @@ get_symbol_initial_value (struct output_block *ob, tree expr) ...@@ -331,15 +331,13 @@ get_symbol_initial_value (struct output_block *ob, tree expr)
&& !DECL_IN_CONSTANT_POOL (expr) && !DECL_IN_CONSTANT_POOL (expr)
&& initial) && initial)
{ {
lto_symtab_encoder_t encoder;
varpool_node *vnode; varpool_node *vnode;
/* Extra section needs about 30 bytes; do not produce it for simple
encoder = ob->decl_state->symtab_node_encoder; scalar values. */
vnode = varpool_get_node (expr); if (TREE_CODE (DECL_INITIAL (expr)) == CONSTRUCTOR
if (!vnode || !(vnode = varpool_get_node (expr))
|| !lto_symtab_encoder_encode_initializer_p (encoder, || !lto_symtab_encoder_encode_initializer_p (encoder, vnode))
vnode)) initial = error_mark_node;
initial = error_mark_node;
} }
return initial; return initial;
...@@ -369,7 +367,8 @@ lto_write_tree_1 (struct output_block *ob, tree expr, bool ref_p) ...@@ -369,7 +367,8 @@ lto_write_tree_1 (struct output_block *ob, tree expr, bool ref_p)
&& TREE_CODE (expr) != TRANSLATION_UNIT_DECL) && TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
{ {
/* Handle DECL_INITIAL for symbols. */ /* 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); stream_write_tree (ob, initial, ref_p);
} }
} }
...@@ -1195,7 +1194,8 @@ DFS_write_tree (struct output_block *ob, sccs *from_state, ...@@ -1195,7 +1194,8 @@ DFS_write_tree (struct output_block *ob, sccs *from_state,
&& TREE_CODE (expr) != TRANSLATION_UNIT_DECL) && TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
{ {
/* Handle DECL_INITIAL for symbols. */ /* 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); DFS_write_tree (ob, cstate, initial, ref_p, ref_p);
} }
} }
...@@ -1808,7 +1808,7 @@ output_function (struct cgraph_node *node) ...@@ -1808,7 +1808,7 @@ output_function (struct cgraph_node *node)
ob = create_output_block (LTO_section_function_body); ob = create_output_block (LTO_section_function_body);
clear_line_info (ob); clear_line_info (ob);
ob->cgraph_node = node; ob->symbol = node;
gcc_assert (current_function_decl == NULL_TREE && cfun == NULL); gcc_assert (current_function_decl == NULL_TREE && cfun == NULL);
...@@ -1899,6 +1899,32 @@ output_function (struct cgraph_node *node) ...@@ -1899,6 +1899,32 @@ output_function (struct cgraph_node *node)
destroy_output_block (ob); 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. */ /* Emit toplevel asms. */
...@@ -1957,10 +1983,10 @@ lto_output_toplevel_asms (void) ...@@ -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 static void
copy_function (struct cgraph_node *node) copy_function_or_variable (struct symtab_node *node)
{ {
tree function = node->decl; tree function = node->decl;
struct lto_file_decl_data *file_data = node->lto_file_data; struct lto_file_decl_data *file_data = node->lto_file_data;
...@@ -2072,7 +2098,7 @@ lto_output (void) ...@@ -2072,7 +2098,7 @@ lto_output (void)
if (gimple_has_body_p (node->decl) || !flag_wpa) if (gimple_has_body_p (node->decl) || !flag_wpa)
output_function (node); output_function (node);
else else
copy_function (node); copy_function_or_variable (node);
gcc_assert (lto_get_out_decl_state () == decl_state); gcc_assert (lto_get_out_decl_state () == decl_state);
lto_pop_out_decl_state (); lto_pop_out_decl_state ();
lto_record_function_out_decl_state (node->decl, decl_state); lto_record_function_out_decl_state (node->decl, decl_state);
...@@ -2085,6 +2111,25 @@ lto_output (void) ...@@ -2085,6 +2111,25 @@ lto_output (void)
tree ctor = DECL_INITIAL (node->decl); tree ctor = DECL_INITIAL (node->decl);
if (ctor && !in_lto_p) if (ctor && !in_lto_p)
walk_tree (&ctor, wrap_refs, NULL, NULL); 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);
}
} }
} }
......
...@@ -685,9 +685,9 @@ struct output_block ...@@ -685,9 +685,9 @@ struct output_block
far and the indexes assigned to them. */ far and the indexes assigned to them. */
hash_table<string_slot_hasher> *string_hash_table; hash_table<string_slot_hasher> *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. */ 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. /* These are the last file and line that were seen in the stream.
If the current node differs from these, it needs to insert If the current node differs from these, it needs to insert
...@@ -830,6 +830,9 @@ extern void lto_reader_init (void); ...@@ -830,6 +830,9 @@ extern void lto_reader_init (void);
extern void lto_input_function_body (struct lto_file_decl_data *, extern void lto_input_function_body (struct lto_file_decl_data *,
struct cgraph_node *, struct cgraph_node *,
const char *); 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 *, extern void lto_input_constructors_and_inits (struct lto_file_decl_data *,
const char *); const char *);
extern void lto_input_toplevel_asms (struct lto_file_decl_data *, int); extern void lto_input_toplevel_asms (struct lto_file_decl_data *, int);
......
2014-07-11 Jan Hubicka <hubicka@ucw.cz>
* lto-partition.c (add_references_to_partition): Use
varpool_ctor_useable_for_folding_p.
* lto.c (lto_read_in_decl_state): Update sanity check.
2014-07-01 Martin Liska <mliska@suse.cz> 2014-07-01 Martin Liska <mliska@suse.cz>
IPA REF alias refactoring IPA REF alias refactoring
......
...@@ -96,7 +96,7 @@ add_references_to_partition (ltrans_partition part, symtab_node *node) ...@@ -96,7 +96,7 @@ add_references_to_partition (ltrans_partition part, symtab_node *node)
Recursively look into the initializers of the constant variable and add Recursively look into the initializers of the constant variable and add
references, too. */ references, too. */
else if (is_a <varpool_node *> (ref->referred) else if (is_a <varpool_node *> (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)) && !lto_symtab_encoder_in_partition_p (part->encoder, ref->referred))
{ {
if (!part->initializers_visited) if (!part->initializers_visited)
......
...@@ -236,7 +236,7 @@ lto_read_in_decl_state (struct data_in *data_in, const uint32_t *data, ...@@ -236,7 +236,7 @@ lto_read_in_decl_state (struct data_in *data_in, const uint32_t *data,
ix = *data++; ix = *data++;
decl = streamer_tree_cache_get_tree (data_in->reader_cache, ix); 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); gcc_assert (decl == void_type_node);
decl = NULL_TREE; decl = NULL_TREE;
......
...@@ -35,6 +35,9 @@ along with GCC; see the file COPYING3. If not see ...@@ -35,6 +35,9 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-expr.h" #include "gimple-expr.h"
#include "flags.h" #include "flags.h"
#include "pointer-set.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", const char * const tls_model_names[]={"none", "tls-emulated", "tls-real",
"tls-global-dynamic", "tls-local-dynamic", "tls-global-dynamic", "tls-local-dynamic",
...@@ -163,19 +166,17 @@ varpool_node_for_decl (tree decl) ...@@ -163,19 +166,17 @@ varpool_node_for_decl (tree decl)
void void
varpool_remove_node (varpool_node *node) varpool_remove_node (varpool_node *node)
{ {
tree init;
varpool_call_node_removal_hooks (node); varpool_call_node_removal_hooks (node);
symtab_unregister_node (node); symtab_unregister_node (node);
/* Because we remove references from external functions before final compilation, /* When streaming we can have multiple nodes associated with decl. */
we may end up removing useful constructors.
FIXME: We probably want to trace boundaries better. */
if (cgraph_state == CGRAPH_LTO_STREAMING) 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); varpool_remove_initializer (node);
else
DECL_INITIAL (node->decl) = init;
ggc_free (node); ggc_free (node);
} }
...@@ -215,7 +216,7 @@ dump_varpool_node (FILE *f, varpool_node *node) ...@@ -215,7 +216,7 @@ dump_varpool_node (FILE *f, varpool_node *node)
fprintf (f, " used-by-single-function"); fprintf (f, " used-by-single-function");
if (TREE_READONLY (node->decl)) if (TREE_READONLY (node->decl))
fprintf (f, " read-only"); 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"); fprintf (f, " const-value-known");
if (node->writeonly) if (node->writeonly)
fprintf (f, " write-only"); fprintf (f, " write-only");
...@@ -253,9 +254,101 @@ varpool_node_for_asm (tree asmname) ...@@ -253,9 +254,101 @@ varpool_node_for_asm (tree asmname)
return NULL; return NULL;
} }
/* Return if DECL is constant and its initial value is known (so we can do /* When doing LTO, read NODE's constructor from disk if it is not already present. */
constant folding using DECL_INITIAL (decl)).
Return ERROR_MARK_NODE when value is unknown. */ 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 tree
ctor_for_folding (tree decl) ctor_for_folding (tree decl)
...@@ -284,7 +377,7 @@ ctor_for_folding (tree decl) ...@@ -284,7 +377,7 @@ ctor_for_folding (tree decl)
gcc_assert (TREE_CODE (decl) == VAR_DECL); gcc_assert (TREE_CODE (decl) == VAR_DECL);
node = varpool_get_node (decl); real_node = node = varpool_get_node (decl);
if (node) if (node)
{ {
real_node = varpool_variable_node (node); real_node = varpool_variable_node (node);
...@@ -302,54 +395,25 @@ ctor_for_folding (tree decl) ...@@ -302,54 +395,25 @@ ctor_for_folding (tree decl)
{ {
gcc_assert (!DECL_INITIAL (decl) gcc_assert (!DECL_INITIAL (decl)
|| DECL_INITIAL (decl) == error_mark_node); || DECL_INITIAL (decl) == error_mark_node);
if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))) if (node->weakref)
{ {
node = varpool_alias_target (node); node = varpool_alias_target (node);
decl = node->decl; decl = node->decl;
} }
} }
/* Vtables are defined by their types and must match no matter of interposition if ((!DECL_VIRTUAL_P (real_decl)
rules. */ || DECL_INITIAL (real_decl) == error_mark_node
if (DECL_VIRTUAL_P (real_decl)) || !DECL_INITIAL (real_decl))
{ && (!node || !varpool_ctor_useable_for_folding_p (node)))
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)))
return error_mark_node; return error_mark_node;
/* Variables declared `const' with an initializer are considered /* OK, we can return constructor. See if we need to fetch it from disk
to not be overwritable with different initializer by default. in LTO mode. */
if (DECL_INITIAL (real_decl) != error_mark_node
??? Previously we behaved so for scalar variables but not for array || !in_lto_p)
accesses. */ return DECL_INITIAL (real_decl);
return DECL_INITIAL (real_decl); return varpool_get_constructor (real_node);
} }
/* Add the variable DECL to the varpool. /* Add the variable DECL to the varpool.
...@@ -471,6 +535,7 @@ varpool_assemble_decl (varpool_node *node) ...@@ -471,6 +535,7 @@ varpool_assemble_decl (varpool_node *node)
if (!node->in_other_partition if (!node->in_other_partition
&& !DECL_EXTERNAL (decl)) && !DECL_EXTERNAL (decl))
{ {
varpool_get_constructor (node);
assemble_variable (decl, 0, 1, 0); assemble_variable (decl, 0, 1, 0);
gcc_assert (TREE_ASM_WRITTEN (decl)); gcc_assert (TREE_ASM_WRITTEN (decl));
node->definition = true; node->definition = true;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment