lto-symtab.c (lto_varpool_replace_node): Do not merge needed flags.

* lto-symtab.c (lto_varpool_replace_node): Do not merge needed flags.
	* cgraphbuild.c (record_reference, record_type_list, mark_address,
	mark_load, mark_store): Do not mark varpool nodes as needed.
	* cgraph.c (cgraph_new_nodes): Remove.
	(cgraph_create_function_alias): Do not mark nodes as reachable.
	(cgraph_add_thunk): Likewise.
	(cgraph_mark_reachable_node): Do not manage the queue.
	* cgraph.h (cgraph_node): Remove next_needed.
	(varpool_nodes_queue): Remove next_needed and prev_needed.
	(x_cgraph_nodes_queue, x_cgraph_nodes_queue, cgraph_new_nodes): Remove.
	(cgraph_new_nodes): Declare.
	(x_varpool_nodes_queue, varpool_nodes_queue); Remove.
	(varpool_analyze_pending_decls): Remove.
	(varpool_analyze_node): New.
	(varpool_mark_needed_node): Remove.
	(varpool_first_variable, varpool_next_variable): New inlines.
	(varpool_first_static_initializer, varpool_next_static_initializer): Update.
	(FOR_EACH_STATIC_VARIABLE): Remove unused walker.
	(varpool_first_defined_variable): New inline.
	(varpool_next_defined_variable): New inline
	(FOR_EACH_VARIABLE): Reimplement.
	(FOR_EACH_DEFINED_VARIABLE): Reimplement.
	* toplev.c (wrapup_global_declaration_2): Use analyzed instead of
	needed flag.
	* cgraphunit.c (cgraph_new_nodes): Declare here.
	(enqueue_node): New function.
	(cgraph_process_new_functions): update for new
	node set; when constructing cgraph enqueue node for processing.
	(cgraph_add_new_function): Use new node set.
	(process_function_and_variable_attributes): Do not set varpool needed
	flags.
	(referred_to_p): New function.
	(varpool_finalize_decl): Move here from varpool.c; enqueue needed node
	when varpool is in construction.
	(cgraph_analyze_functions): Rewrite.
	(cgraph_expand_all_functions): Update.
	(cgraph_output_in_order): Do not analyze pending decls; do not set needed flags.
	(cgraph_optimize): Do not analyze pending decls.
	* lto-cgraph.c (input_varpool_node): Clear analyzed flag for objects in other
	partition; do not mark node as needed.
	* dwarf2out.c (reference_to_unused): Use analyzed flag.
	(premark_types_used_by_global_vars_helper): Likewise.
	* ipa.c (process_references): Do not call varpool_mark_needed_node.
	(cgraph_remove_unreachable_nodes): Do not rely on varpool and
	cgrpah queues.
	(function_and_variable_visibility): Do not mark node as needed.
	(whole_program_function_and_variable_visibility): Likewise.
	* Makefile.in (gt-varpool.h): No longer needed.
	* passes.c (execute_one_pass, execute_ipa_pass_list): Update.
	(ipa_write_summaries): Do not use needed flag.
	* varpool.c: Do not include gt-varpool.h
	(x_varpool_nodes_queue, x_varpool_last_needed_node,
	x_varpool_last_needed_node, x_varpool_first_unanalyzed_node,
	x_varpool_first_unanalyzed_node, varpool_assembled_nodes_queue):
	Remove.
	(varpool_remove_node): Do not update the lists.
	(dump_varpool_node): Do not dump needed flag.
	(varpool_enqueue_needed_node): Remove.
	(varpool_mark_needed_node): Remove.
	(varpool_reset_queue): Remove.
	(varpool_finalize_decl): Move to cgraphunit.c
	(varpool_analyze_node): New functions based on former
	varpool_analyze_pending_decls.
	(varpool_analyze_pending_decls): Remove.
	(varpool_assemble_decl): Do not update the lists.
	(enqueue_node): New function.
	(varpool_remove_unreferenced_decls): Rewrite.
	(varpool_empty_needed_queue): Remove.
	(add_new_static_var): Do not mark node as needed.
	(varpool_create_variable_alias): Handle expansion state
	creation.
	* except.c (output_ttype): Do not mark node as needed.
	* varasm.c (mark_decl_referenced): Do not use mark_needed_node.
	* tree-profile.c (init_ic_make_global_vars, init_ic_make_global_vars):
	Likewise.
	* tree-switch-conversion.c (build_one_array): Likewise.

	* class.c (build_utf8_ref): Do not mark varpool node as needed.

	* gcc-interface/utils.c (gnat_write_global_declarations): Do not mark
	needed node.

	* lto-partition.c (partition_varpool_node_p): Do not use needed flag.

	* decl2.c (maybe_make_one_only): Mark keyed COMDATs as USED so they
	gets finalized.

From-SVN: r186687
This commit is contained in:
Jan Hubicka 2012-04-22 23:28:07 +02:00 committed by Jan Hubicka
parent f04e40afc1
commit 660584689a
25 changed files with 542 additions and 553 deletions

View File

@ -1,3 +1,82 @@
2012-04-22 Jan Hubicka <jh@suse.cz>
* lto-symtab.c (lto_varpool_replace_node): Do not merge needed flags.
* cgraphbuild.c (record_reference, record_type_list, mark_address,
mark_load, mark_store): Do not mark varpool nodes as needed.
* cgraph.c (cgraph_new_nodes): Remove.
(cgraph_create_function_alias): Do not mark nodes as reachable.
(cgraph_add_thunk): Likewise.
(cgraph_mark_reachable_node): Do not manage the queue.
* cgraph.h (cgraph_node): Remove next_needed.
(varpool_nodes_queue): Remove next_needed and prev_needed.
(x_cgraph_nodes_queue, x_cgraph_nodes_queue, cgraph_new_nodes): Remove.
(cgraph_new_nodes): Declare.
(x_varpool_nodes_queue, varpool_nodes_queue); Remove.
(varpool_analyze_pending_decls): Remove.
(varpool_analyze_node): New.
(varpool_mark_needed_node): Remove.
(varpool_first_variable, varpool_next_variable): New inlines.
(varpool_first_static_initializer, varpool_next_static_initializer): Update.
(FOR_EACH_STATIC_VARIABLE): Remove unused walker.
(varpool_first_defined_variable): New inline.
(varpool_next_defined_variable): New inline
(FOR_EACH_VARIABLE): Reimplement.
(FOR_EACH_DEFINED_VARIABLE): Reimplement.
* toplev.c (wrapup_global_declaration_2): Use analyzed instead of
needed flag.
* cgraphunit.c (cgraph_new_nodes): Declare here.
(enqueue_node): New function.
(cgraph_process_new_functions): update for new
node set; when constructing cgraph enqueue node for processing.
(cgraph_add_new_function): Use new node set.
(process_function_and_variable_attributes): Do not set varpool needed
flags.
(referred_to_p): New function.
(varpool_finalize_decl): Move here from varpool.c; enqueue needed node
when varpool is in construction.
(cgraph_analyze_functions): Rewrite.
(cgraph_expand_all_functions): Update.
(cgraph_output_in_order): Do not analyze pending decls; do not set needed flags.
(cgraph_optimize): Do not analyze pending decls.
* lto-cgraph.c (input_varpool_node): Clear analyzed flag for objects in other
partition; do not mark node as needed.
* dwarf2out.c (reference_to_unused): Use analyzed flag.
(premark_types_used_by_global_vars_helper): Likewise.
* ipa.c (process_references): Do not call varpool_mark_needed_node.
(cgraph_remove_unreachable_nodes): Do not rely on varpool and
cgrpah queues.
(function_and_variable_visibility): Do not mark node as needed.
(whole_program_function_and_variable_visibility): Likewise.
* Makefile.in (gt-varpool.h): No longer needed.
* passes.c (execute_one_pass, execute_ipa_pass_list): Update.
(ipa_write_summaries): Do not use needed flag.
* varpool.c: Do not include gt-varpool.h
(x_varpool_nodes_queue, x_varpool_last_needed_node,
x_varpool_last_needed_node, x_varpool_first_unanalyzed_node,
x_varpool_first_unanalyzed_node, varpool_assembled_nodes_queue):
Remove.
(varpool_remove_node): Do not update the lists.
(dump_varpool_node): Do not dump needed flag.
(varpool_enqueue_needed_node): Remove.
(varpool_mark_needed_node): Remove.
(varpool_reset_queue): Remove.
(varpool_finalize_decl): Move to cgraphunit.c
(varpool_analyze_node): New functions based on former
varpool_analyze_pending_decls.
(varpool_analyze_pending_decls): Remove.
(varpool_assemble_decl): Do not update the lists.
(enqueue_node): New function.
(varpool_remove_unreferenced_decls): Rewrite.
(varpool_empty_needed_queue): Remove.
(add_new_static_var): Do not mark node as needed.
(varpool_create_variable_alias): Handle expansion state
creation.
* except.c (output_ttype): Do not mark node as needed.
* varasm.c (mark_decl_referenced): Do not use mark_needed_node.
* tree-profile.c (init_ic_make_global_vars, init_ic_make_global_vars):
Likewise.
* tree-switch-conversion.c (build_one_array): Likewise.
2012-04-22 Manuel López-Ibáñez <manu@gcc.gnu.org>
PR c/44774

View File

@ -2934,7 +2934,7 @@ cgraphbuild.o : cgraphbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
varpool.o : varpool.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) $(CGRAPH_H) langhooks.h $(DIAGNOSTIC_CORE_H) $(HASHTAB_H) \
$(GGC_H) $(TIMEVAR_H) debug.h $(TARGET_H) output.h $(GIMPLE_H) \
$(TREE_FLOW_H) gt-varpool.h
$(TREE_FLOW_H)
ipa.o : ipa.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRAPH_H) \
$(TREE_PASS_H) $(TIMEVAR_H) $(GIMPLE_H) $(GGC_H) pointer-set.h \
$(IPA_UTILS_H)
@ -3719,7 +3719,6 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/tree-scalar-evolution.c \
$(srcdir)/tree-ssa-operands.h \
$(srcdir)/tree-profile.c $(srcdir)/tree-nested.c \
$(srcdir)/varpool.c \
$(srcdir)/tree-parloops.c \
$(srcdir)/omp-low.c \
$(srcdir)/targhooks.c $(out_file) $(srcdir)/passes.c $(srcdir)/cgraphunit.c \

View File

@ -1,3 +1,8 @@
2012-04-22 Jan Hubicka <jh@suse.cz>
* gcc-interface/utils.c (gnat_write_global_declarations): Do not mark
needed node.
2012-04-20 Jan Hubicka <jh@suse.cz>
* gcc-interface/utils.c (gnat_write_global_declarations): Update for new

View File

@ -4860,7 +4860,6 @@ gnat_write_global_declarations (void)
TREE_ASM_WRITTEN (dummy_global) = 1;
node = varpool_node (dummy_global);
node->symbol.force_output = 1;
varpool_mark_needed_node (node);
while (!VEC_empty (tree, types_used_by_cur_var_decl))
{

View File

@ -123,11 +123,6 @@ static inline void cgraph_edge_remove_callee (struct cgraph_edge *e);
symtab_node x_cgraph_nodes_queue;
#define cgraph_nodes_queue ((struct cgraph_node *)x_cgraph_nodes_queue)
/* Queue of cgraph nodes scheduled to be added into cgraph. This is a
secondary queue used during optimization to accommodate passes that
may generate new functions that need to be optimized and expanded. */
struct cgraph_node *cgraph_new_nodes;
/* Number of nodes in existence. */
int cgraph_n_nodes;
@ -141,7 +136,7 @@ int cgraph_edge_max_uid;
bool cgraph_global_info_ready = false;
/* What state callgraph is in right now. */
enum cgraph_state cgraph_state = CGRAPH_STATE_CONSTRUCTION;
enum cgraph_state cgraph_state = CGRAPH_STATE_PARSING;
/* Set when the cgraph is fully build and the basic flags are computed. */
bool cgraph_function_flags_ready = false;
@ -499,11 +494,6 @@ cgraph_create_function_alias (tree alias, tree decl)
alias_node->thunk.alias = decl;
alias_node->local.finalized = true;
alias_node->alias = 1;
if ((TREE_PUBLIC (alias) && !DECL_COMDAT (alias) && !DECL_EXTERNAL (alias))
|| (DECL_VIRTUAL_P (alias)
&& (DECL_COMDAT (alias) || DECL_EXTERNAL (alias))))
cgraph_mark_reachable_node (alias_node);
return alias_node;
}
@ -539,7 +529,7 @@ cgraph_same_body_alias (struct cgraph_node *decl_node ATTRIBUTE_UNUSED, tree ali
struct cgraph_node *
cgraph_add_thunk (struct cgraph_node *decl_node ATTRIBUTE_UNUSED,
tree alias, tree decl,
tree alias, tree decl ATTRIBUTE_UNUSED,
bool this_adjusting,
HOST_WIDE_INT fixed_offset, HOST_WIDE_INT virtual_value,
tree virtual_offset,
@ -569,14 +559,6 @@ cgraph_add_thunk (struct cgraph_node *decl_node ATTRIBUTE_UNUSED,
node->thunk.thunk_p = true;
node->local.finalized = true;
if (cgraph_decide_is_function_needed (node, decl))
cgraph_mark_reachable_node (node);
if ((TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
|| (DECL_VIRTUAL_P (decl)
&& (DECL_COMDAT (decl) || DECL_EXTERNAL (decl))))
cgraph_mark_reachable_node (node);
return node;
}
@ -1508,9 +1490,6 @@ cgraph_mark_reachable_node (struct cgraph_node *node)
else
notice_global_symbol (node->symbol.decl);
node->reachable = 1;
node->next_needed = cgraph_nodes_queue;
x_cgraph_nodes_queue = (symtab_node)node;
}
}

View File

@ -215,10 +215,6 @@ struct GTY(()) cgraph_node {
struct cgraph_node *
GTY ((nested_ptr (union symtab_node_def, "(struct cgraph_node *)(%h)", "(symtab_node)%h")))
next_nested;
/* Pointer to the next function in cgraph_nodes_queue. */
struct cgraph_node *
GTY ((nested_ptr (union symtab_node_def, "(struct cgraph_node *)(%h)", "(symtab_node)%h")))
next_needed;
/* Pointer to the next clone. */
struct cgraph_node *next_sibling_clone;
struct cgraph_node *prev_sibling_clone;
@ -419,13 +415,6 @@ struct GTY(()) varpool_node {
struct symtab_node_base symbol;
/* For aliases points to declaration DECL is alias of. */
tree alias_of;
/* Pointer to the next function in varpool_nodes_queue. */
struct varpool_node *
GTY ((nested_ptr (union symtab_node_def, "(struct varpool_node *)(%h)", "(symtab_node)%h")))
next_needed;
struct varpool_node *
GTY ((nested_ptr (union symtab_node_def, "(struct varpool_node *)(%h)", "(symtab_node)%h")))
prev_needed;
/* Set when function must be output - it is externally visible
or its address is taken. */
@ -471,6 +460,8 @@ extern GTY(()) int cgraph_edge_max_uid;
extern bool cgraph_global_info_ready;
enum cgraph_state
{
/* Frontend is parsing and finalizing functions. */
CGRAPH_STATE_PARSING,
/* Callgraph is being constructed. It is safe to add new functions. */
CGRAPH_STATE_CONSTRUCTION,
/* Callgraph is built and IPA passes are being run. */
@ -484,9 +475,7 @@ enum cgraph_state
};
extern enum cgraph_state cgraph_state;
extern bool cgraph_function_flags_ready;
extern GTY(()) symtab_node x_cgraph_nodes_queue;
#define cgraph_nodes_queue ((struct cgraph_node *)x_cgraph_nodes_queue)
extern GTY(()) struct cgraph_node *cgraph_new_nodes;
extern cgraph_node_set cgraph_new_nodes;
extern GTY(()) struct cgraph_asm_node *cgraph_asm_nodes;
extern GTY(()) int symtab_order;
@ -687,9 +676,6 @@ bool cgraph_maybe_hot_edge_p (struct cgraph_edge *e);
bool cgraph_optimize_for_size_p (struct cgraph_node *);
/* In varpool.c */
extern GTY(()) symtab_node x_varpool_nodes_queue;
#define varpool_nodes_queue ((struct varpool_node *)x_varpool_nodes_queue)
struct varpool_node *varpool_node (tree);
struct varpool_node *varpool_node_for_asm (tree asmname);
void varpool_mark_needed_node (struct varpool_node *);
@ -709,9 +695,8 @@ void varpool_remove_node (struct varpool_node *node);
void varpool_finalize_named_section_flags (struct varpool_node *node);
bool varpool_assemble_pending_decls (void);
bool varpool_assemble_decl (struct varpool_node *node);
bool varpool_analyze_pending_decls (void);
void varpool_analyze_node (struct varpool_node *);
void varpool_remove_unreferenced_decls (void);
void varpool_empty_needed_queue (void);
struct varpool_node * varpool_extra_name_alias (tree, tree);
struct varpool_node * varpool_create_variable_alias (tree, tree);
void varpool_reset_queue (void);
@ -799,40 +784,6 @@ varpool_node_name(struct varpool_node *node)
#define FOR_EACH_SYMBOL(node) \
for ((node) = symtab_nodes; (node); (node) = (node)->symbol.next)
/* Return first reachable static variable with initializer. */
static inline struct varpool_node *
varpool_first_static_initializer (void)
{
struct varpool_node *node;
for (node = varpool_nodes_queue; node; node = node->next_needed)
{
gcc_checking_assert (TREE_CODE (node->symbol.decl) == VAR_DECL);
if (DECL_INITIAL (node->symbol.decl))
return node;
}
return NULL;
}
/* Return next reachable static variable with initializer after NODE. */
static inline struct varpool_node *
varpool_next_static_initializer (struct varpool_node *node)
{
for (node = node->next_needed; node; node = node->next_needed)
{
gcc_checking_assert (TREE_CODE (node->symbol.decl) == VAR_DECL);
if (DECL_INITIAL (node->symbol.decl))
return node;
}
return NULL;
}
/* Walk all reachable static variables. */
#define FOR_EACH_STATIC_VARIABLE(node) \
for ((node) = varpool_nodes_queue; (node); (node) = (node)->next_needed)
/* Walk all static variables with initializer set. */
#define FOR_EACH_STATIC_INITIALIZER(node) \
for ((node) = varpool_first_static_initializer (); (node); \
(node) = varpool_next_static_initializer (node))
/* Return first variable. */
static inline struct varpool_node *
@ -864,9 +815,69 @@ varpool_next_variable (struct varpool_node *node)
for ((node) = varpool_first_variable (); \
(node); \
(node) = varpool_next_variable ((node)))
/* Return first reachable static variable with initializer. */
static inline struct varpool_node *
varpool_first_static_initializer (void)
{
symtab_node node;
for (node = symtab_nodes; node; node = node->symbol.next)
{
if (symtab_variable_p (node)
&& DECL_INITIAL (node->symbol.decl))
return varpool (node);
}
return NULL;
}
/* Return next reachable static variable with initializer after NODE. */
static inline struct varpool_node *
varpool_next_static_initializer (struct varpool_node *node)
{
symtab_node node1 = (symtab_node) node->symbol.next;
for (; node1; node1 = node1->symbol.next)
{
if (symtab_variable_p (node1)
&& DECL_INITIAL (node1->symbol.decl))
return varpool (node1);
}
return NULL;
}
/* Walk all static variables with initializer set. */
#define FOR_EACH_STATIC_INITIALIZER(node) \
for ((node) = varpool_first_static_initializer (); (node); \
(node) = varpool_next_static_initializer (node))
/* Return first reachable static variable with initializer. */
static inline struct varpool_node *
varpool_first_defined_variable (void)
{
symtab_node node;
for (node = symtab_nodes; node; node = node->symbol.next)
{
if (symtab_variable_p (node) && varpool (node)->analyzed)
return varpool (node);
}
return NULL;
}
/* Return next reachable static variable with initializer after NODE. */
static inline struct varpool_node *
varpool_next_defined_variable (struct varpool_node *node)
{
symtab_node node1 = (symtab_node) node->symbol.next;
for (; node1; node1 = node1->symbol.next)
{
if (symtab_variable_p (node1) && varpool (node1)->analyzed)
return varpool (node1);
}
return NULL;
}
/* Walk all variables with definitions in current unit. */
#define FOR_EACH_DEFINED_VARIABLE(node) \
for ((node) = varpool_nodes_queue; (node); (node) = (node)->next_needed)
for ((node) = varpool_first_defined_variable (); (node); \
(node) = varpool_next_defined_variable (node))
/* Return first function with body defined. */
static inline struct cgraph_node *

View File

@ -87,7 +87,6 @@ record_reference (tree *tp, int *walk_subtrees, void *data)
struct varpool_node *vnode = varpool_node (decl);
if (lang_hooks.callgraph.analyze_expr)
lang_hooks.callgraph.analyze_expr (&decl, walk_subtrees);
varpool_mark_needed_node (vnode);
ipa_record_reference ((symtab_node)ctx->varpool_node,
(symtab_node)vnode,
IPA_REF_ADDR, NULL);
@ -130,7 +129,6 @@ record_type_list (struct cgraph_node *node, tree list)
if (TREE_CODE (type) == VAR_DECL)
{
struct varpool_node *vnode = varpool_node (type);
varpool_mark_needed_node (vnode);
ipa_record_reference ((symtab_node)node,
(symtab_node)vnode,
IPA_REF_ADDR, NULL);
@ -245,7 +243,6 @@ mark_address (gimple stmt, tree addr, void *data)
if (lang_hooks.callgraph.analyze_expr)
lang_hooks.callgraph.analyze_expr (&addr, &walk_subtrees);
varpool_mark_needed_node (vnode);
ipa_record_reference ((symtab_node)data,
(symtab_node)vnode,
IPA_REF_ADDR, stmt);
@ -278,7 +275,6 @@ mark_load (gimple stmt, tree t, void *data)
if (lang_hooks.callgraph.analyze_expr)
lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees);
varpool_mark_needed_node (vnode);
ipa_record_reference ((symtab_node)data,
(symtab_node)vnode,
IPA_REF_LOAD, stmt);
@ -300,7 +296,6 @@ mark_store (gimple stmt, tree t, void *data)
if (lang_hooks.callgraph.analyze_expr)
lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees);
varpool_mark_needed_node (vnode);
ipa_record_reference ((symtab_node)data,
(symtab_node)vnode,
IPA_REF_STORE, stmt);

View File

@ -145,6 +145,11 @@ along with GCC; see the file COPYING3. If not see
#include "except.h"
#include "regset.h" /* FIXME: For reg_obstack. */
/* Queue of cgraph nodes scheduled to be added into cgraph. This is a
secondary queue used during optimization to accommodate passes that
may generate new functions that need to be optimized and expanded. */
cgraph_node_set cgraph_new_nodes;
static void cgraph_expand_all_functions (void);
static void cgraph_mark_functions_to_output (void);
static void cgraph_expand_function (struct cgraph_node *);
@ -192,6 +197,23 @@ cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl)
return false;
}
/* Head of the queue of nodes to be processed while building callgraph */
static symtab_node first = (symtab_node)(void *)1;
/* Add NODE to queue starting at FIRST.
The queue is linked via AUX pointers and terminated by pointer to 1. */
static void
enqueue_node (symtab_node node)
{
if (node->symbol.aux)
return;
gcc_checking_assert (first);
node->symbol.aux = first;
first = node;
}
/* Process CGRAPH_NEW_FUNCTIONS and perform actions necessary to add these
functions into callgraph in a way so they look like ordinary reachable
functions inserted into callgraph already at construction time. */
@ -202,26 +224,26 @@ cgraph_process_new_functions (void)
bool output = false;
tree fndecl;
struct cgraph_node *node;
cgraph_node_set_iterator csi;
varpool_analyze_pending_decls ();
if (!cgraph_new_nodes)
return false;
/* Note that this queue may grow as its being processed, as the new
functions may generate new ones. */
while (cgraph_new_nodes)
for (csi = csi_start (cgraph_new_nodes); !csi_end_p (csi); csi_next (&csi))
{
node = cgraph_new_nodes;
node = csi_node (csi);
fndecl = node->symbol.decl;
cgraph_new_nodes = cgraph_new_nodes->next_needed;
switch (cgraph_state)
{
case CGRAPH_STATE_CONSTRUCTION:
/* At construction time we just need to finalize function and move
it into reachable functions list. */
node->next_needed = NULL;
cgraph_finalize_function (fndecl, false);
cgraph_mark_reachable_node (node);
output = true;
cgraph_call_function_insertion_hooks (node);
enqueue_node ((symtab_node) node);
break;
case CGRAPH_STATE_IPA:
@ -262,8 +284,9 @@ cgraph_process_new_functions (void)
gcc_unreachable ();
break;
}
varpool_analyze_pending_decls ();
}
free_cgraph_node_set (cgraph_new_nodes);
cgraph_new_nodes = NULL;
return output;
}
@ -372,13 +395,17 @@ cgraph_add_new_function (tree fndecl, bool lowered)
struct cgraph_node *node;
switch (cgraph_state)
{
case CGRAPH_STATE_PARSING:
cgraph_finalize_function (fndecl, false);
break;
case CGRAPH_STATE_CONSTRUCTION:
/* Just enqueue function to be processed at nearest occurrence. */
node = cgraph_create_node (fndecl);
node->next_needed = cgraph_new_nodes;
if (lowered)
node->lowered = true;
cgraph_new_nodes = node;
if (!cgraph_new_nodes)
cgraph_new_nodes = cgraph_node_set_new ();
cgraph_node_set_add (cgraph_new_nodes, node);
break;
case CGRAPH_STATE_IPA:
@ -406,8 +433,9 @@ cgraph_add_new_function (tree fndecl, bool lowered)
}
if (lowered)
node->lowered = true;
node->next_needed = cgraph_new_nodes;
cgraph_new_nodes = node;
if (!cgraph_new_nodes)
cgraph_new_nodes = cgraph_node_set_new ();
cgraph_node_set_add (cgraph_new_nodes, node);
break;
case CGRAPH_STATE_FINISHED:
@ -1091,26 +1119,13 @@ process_function_and_variable_attributes (struct cgraph_node *first,
{
tree decl = vnode->symbol.decl;
if (DECL_PRESERVE_P (decl))
{
vnode->symbol.force_output = true;
if (vnode->finalized)
varpool_mark_needed_node (vnode);
}
if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
&& lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl))
&& TREE_PUBLIC (vnode->symbol.decl))
{
if (vnode->finalized)
varpool_mark_needed_node (vnode);
}
vnode->symbol.force_output = true;
else if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl)))
{
if (! TREE_PUBLIC (vnode->symbol.decl))
warning_at (DECL_SOURCE_LOCATION (vnode->symbol.decl), OPT_Wattributes,
"%<externally_visible%>"
" attribute have effect only on public objects");
else if (vnode->finalized)
varpool_mark_needed_node (vnode);
}
if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
&& vnode->finalized
@ -1127,10 +1142,54 @@ process_function_and_variable_attributes (struct cgraph_node *first,
}
}
/* Process CGRAPH_NODES_NEEDED queue, analyze each function (and transitively
each reachable functions) and build cgraph.
The function can be called multiple times after inserting new nodes
into beginning of queue. Just the new part of queue is re-scanned then. */
/* Return true when there are references to NODE. */
static bool
referred_to_p (symtab_node node)
{
int i;
struct ipa_ref *ref;
for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, i, ref);
i++)
return true;
if (symtab_function_p (node) && cgraph (node)->callers)
return true;
return false;
}
/* Mark DECL as finalized. By finalizing the declaration, frontend instruct the
middle end to output the variable to asm file, if needed or externally
visible. */
void
varpool_finalize_decl (tree decl)
{
struct varpool_node *node = varpool_node (decl);
gcc_assert (TREE_STATIC (decl));
if (node->finalized)
return;
notice_global_symbol (decl);
node->finalized = true;
if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl)
/* Traditionally we do not eliminate static variables when not
optimizing and when not doing toplevel reoder. */
|| (!flag_toplevel_reorder && !DECL_COMDAT (node->symbol.decl)
&& !DECL_ARTIFICIAL (node->symbol.decl)))
node->symbol.force_output = true;
if (cgraph_state == CGRAPH_STATE_CONSTRUCTION
&& (decide_is_variable_needed (node, decl)
|| referred_to_p ((symtab_node)node)))
enqueue_node ((symtab_node)node);
if (cgraph_state >= CGRAPH_STATE_IPA_SSA)
varpool_analyze_node (node);
}
/* Discover all functions and variables that are trivially needed, analyze
them as well as all functions and variables referred by them */
static void
cgraph_analyze_functions (void)
@ -1138,140 +1197,176 @@ cgraph_analyze_functions (void)
/* Keep track of already processed nodes when called multiple times for
intermodule optimization. */
static struct cgraph_node *first_analyzed;
struct cgraph_node *first_processed = first_analyzed;
struct cgraph_node *first_handled = first_analyzed;
static struct varpool_node *first_analyzed_var;
struct cgraph_node *node, *next;
struct varpool_node *first_handled_var = first_analyzed_var;
symtab_node node, next;
int i;
struct ipa_ref *ref;
bool changed = true;
bitmap_obstack_initialize (NULL);
process_function_and_variable_attributes (first_processed,
first_analyzed_var);
first_processed = cgraph_first_function ();
first_analyzed_var = varpool_first_variable ();
varpool_analyze_pending_decls ();
if (cgraph_dump_file)
cgraph_state = CGRAPH_STATE_CONSTRUCTION;
/* Analysis adds static variables that in turn adds references to new functions.
So we need to iterate the process until it stabilize. */
while (changed)
{
fprintf (cgraph_dump_file, "Initial entry points:");
for (node = cgraph_first_function (); node != first_analyzed;
node = cgraph_next_function (node))
if (cgraph_decide_is_function_needed (node, node->symbol.decl))
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
fprintf (cgraph_dump_file, "\n");
}
cgraph_process_new_functions ();
/* Propagate reachability flag and lower representation of all reachable
functions. In the future, lowering will introduce new functions and
new entry points on the way (by template instantiation and virtual
method table generation for instance). */
while (cgraph_nodes_queue)
{
struct cgraph_edge *edge;
tree decl = cgraph_nodes_queue->symbol.decl;
node = cgraph_nodes_queue;
x_cgraph_nodes_queue = (symtab_node)cgraph_nodes_queue->next_needed;
node->next_needed = NULL;
/* ??? It is possible to create extern inline function and later using
weak alias attribute to kill its body. See
gcc.c-torture/compile/20011119-1.c */
if (!DECL_STRUCT_FUNCTION (decl)
&& (!node->alias || !node->thunk.alias)
&& !node->thunk.thunk_p)
{
cgraph_reset_node (node);
node->local.redefined_extern_inline = true;
continue;
}
if (!node->analyzed)
cgraph_analyze_function (node);
for (edge = node->callees; edge; edge = edge->next_callee)
if (!edge->callee->reachable)
cgraph_mark_reachable_node (edge->callee);
for (edge = node->callers; edge; edge = edge->next_caller)
if (!edge->caller->reachable && edge->caller->thunk.thunk_p)
cgraph_mark_reachable_node (edge->caller);
if (node->symbol.same_comdat_group)
{
for (next = cgraph (node->symbol.same_comdat_group);
next != node;
next = cgraph (next->symbol.same_comdat_group))
cgraph_mark_reachable_node (next);
}
/* If decl is a clone of an abstract function, mark that abstract
function so that we don't release its body. The DECL_INITIAL() of that
abstract function declaration will be later needed to output debug
info. */
if (DECL_ABSTRACT_ORIGIN (decl))
{
struct cgraph_node *origin_node;
origin_node = cgraph_get_node (DECL_ABSTRACT_ORIGIN (decl));
origin_node->abstract_and_needed = true;
}
/* We finalize local static variables during constructing callgraph
edges. Process their attributes too. */
process_function_and_variable_attributes (first_processed,
changed = false;
process_function_and_variable_attributes (first_analyzed,
first_analyzed_var);
first_processed = cgraph_first_function ();
first_analyzed_var = varpool_first_variable ();
varpool_analyze_pending_decls ();
/* First identify the trivially needed symbols. */
for (node = symtab_nodes;
node != (symtab_node)first_analyzed
&& node != (symtab_node)first_analyzed_var; node = node->symbol.next)
{
if ((symtab_function_p (node)
&& cgraph (node)->local.finalized
&& cgraph_decide_is_function_needed (cgraph (node), node->symbol.decl))
|| (symtab_variable_p (node)
&& varpool (node)->finalized
&& !DECL_EXTERNAL (node->symbol.decl)
&& decide_is_variable_needed (varpool (node), node->symbol.decl)))
{
enqueue_node (node);
if (!changed && cgraph_dump_file)
fprintf (cgraph_dump_file, "Trivially needed symbols:");
changed = true;
if (cgraph_dump_file)
fprintf (cgraph_dump_file, " %s", symtab_node_asm_name (node));
}
if (node == (symtab_node)first_analyzed
|| node == (symtab_node)first_analyzed_var)
break;
}
cgraph_process_new_functions ();
first_analyzed_var = varpool_first_variable ();
first_analyzed = cgraph_first_function ();
if (changed && dump_file)
fprintf (cgraph_dump_file, "\n");
/* Lower representation, build callgraph edges and references for all trivially
needed symbols and all symbols referred by them. */
while (first != (symtab_node)(void *)1)
{
changed = true;
node = first;
first = (symtab_node)first->symbol.aux;
if (symtab_function_p (node) && cgraph (node)->local.finalized)
{
struct cgraph_edge *edge;
struct cgraph_node *cnode;
tree decl;
cnode = cgraph (node);
decl = cnode->symbol.decl;
/* ??? It is possible to create extern inline function and later using
weak alias attribute to kill its body. See
gcc.c-torture/compile/20011119-1.c */
if (!DECL_STRUCT_FUNCTION (decl)
&& (!cnode->alias || !cnode->thunk.alias)
&& !cnode->thunk.thunk_p)
{
cgraph_reset_node (cnode);
cnode->local.redefined_extern_inline = true;
continue;
}
if (!cnode->analyzed)
cgraph_analyze_function (cnode);
for (edge = cnode->callees; edge; edge = edge->next_callee)
{
cgraph_mark_reachable_node (edge->callee);
if (edge->callee->local.finalized)
enqueue_node ((symtab_node)edge->callee);
}
/* If decl is a clone of an abstract function, mark that abstract
function so that we don't release its body. The DECL_INITIAL() of that
abstract function declaration will be later needed to output debug
info. */
if (DECL_ABSTRACT_ORIGIN (decl))
{
struct cgraph_node *origin_node;
origin_node = cgraph_get_node (DECL_ABSTRACT_ORIGIN (decl));
origin_node->abstract_and_needed = true;
}
}
else if (symtab_variable_p (node)
&& varpool (node)->finalized)
{
varpool_analyze_node (varpool (node));
}
if (node->symbol.same_comdat_group)
{
symtab_node next;
for (next = node->symbol.same_comdat_group;
next != node;
next = next->symbol.same_comdat_group)
enqueue_node (next);
}
for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, i, ref); i++)
if ((symtab_function_p (ref->referred) && cgraph (ref->referred)->local.finalized)
|| (symtab_variable_p (ref->referred) && varpool (ref->referred)->finalized))
enqueue_node (ref->referred);
cgraph_process_new_functions ();
}
}
/* Collect entry points to the unit. */
if (cgraph_dump_file)
{
fprintf (cgraph_dump_file, "Unit entry points:");
for (node = cgraph_first_function (); node != first_analyzed;
node = cgraph_next_function (node))
if (cgraph_decide_is_function_needed (node, node->symbol.decl))
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
fprintf (cgraph_dump_file, "\n\nInitial ");
dump_symtab (cgraph_dump_file);
}
if (cgraph_dump_file)
fprintf (cgraph_dump_file, "\nReclaiming functions:");
fprintf (cgraph_dump_file, "\nRemoving unused symbols:");
for (node = cgraph_first_function (); node != first_analyzed;
node = next)
for (node = symtab_nodes;
node != (symtab_node)first_handled
&& node != (symtab_node)first_handled_var; node = next)
{
tree decl = node->symbol.decl;
next = cgraph_next_function (node);
if (node->local.finalized && !gimple_has_body_p (decl)
&& (!node->alias || !node->thunk.alias)
&& !node->thunk.thunk_p)
cgraph_reset_node (node);
if (!node->reachable
&& (gimple_has_body_p (decl) || node->thunk.thunk_p
|| (node->alias && node->thunk.alias)))
next = node->symbol.next;
if (!node->symbol.aux && !referred_to_p (node))
{
if (cgraph_dump_file)
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
cgraph_remove_node (node);
fprintf (cgraph_dump_file, " %s", symtab_node_name (node));
symtab_remove_node (node);
continue;
}
else
node->next_needed = NULL;
gcc_assert (!node->local.finalized || node->thunk.thunk_p
|| node->alias
|| gimple_has_body_p (decl));
gcc_assert (node->analyzed == node->local.finalized);
if (symtab_function_p (node))
{
tree decl = node->symbol.decl;
struct cgraph_node *cnode = cgraph (node);
if (cnode->local.finalized && !gimple_has_body_p (decl)
&& (!cnode->alias || !cnode->thunk.alias)
&& !cnode->thunk.thunk_p)
cgraph_reset_node (cnode);
gcc_assert (!cnode->local.finalized || cnode->thunk.thunk_p
|| cnode->alias
|| gimple_has_body_p (decl));
gcc_assert (cnode->analyzed == cnode->local.finalized);
}
node->symbol.aux = NULL;
}
first_analyzed = cgraph_first_function ();
first_analyzed_var = varpool_first_variable ();
if (cgraph_dump_file)
{
fprintf (cgraph_dump_file, "\n\nReclaimed ");
dump_symtab (cgraph_dump_file);
}
bitmap_obstack_release (NULL);
first_analyzed = cgraph_first_function ();
ggc_collect ();
}
@ -2041,8 +2136,6 @@ cgraph_output_in_order (void)
max = symtab_order;
nodes = XCNEWVEC (struct cgraph_order_sort, max);
varpool_analyze_pending_decls ();
FOR_EACH_DEFINED_FUNCTION (pf)
{
if (pf->process && !pf->thunk.thunk_p && !pf->alias)
@ -2071,14 +2164,6 @@ cgraph_output_in_order (void)
}
/* In toplevel reorder mode we output all statics; mark them as needed. */
for (i = 0; i < max; ++i)
{
if (nodes[i].kind == ORDER_VAR)
{
varpool_mark_needed_node (nodes[i].u.v);
}
}
varpool_empty_needed_queue ();
for (i = 0; i < max; ++i)
if (nodes[i].kind == ORDER_VAR)
@ -2614,10 +2699,6 @@ cgraph_optimize (void)
verify_symtab ();
#endif
/* Frontend may output common variables after the unit has been finalized.
It is safe to deal with them here as they are always zero initialized. */
varpool_analyze_pending_decls ();
timevar_push (TV_CGRAPHOPT);
if (pre_ipa_mem_report)
{

View File

@ -1,3 +1,8 @@
2012-04-22 Jan Hubicka <jh@suse.cz>
* decl2.c (maybe_make_one_only): Mark keyed COMDATs as USED so they
gets finalized.
2012-04-22 Manuel López-Ibáñez <manu@gcc.gnu.org>
PR c/44774

View File

@ -1677,6 +1677,7 @@ maybe_make_one_only (tree decl)
DECL_COMDAT (decl) = 1;
/* Mark it needed so we don't forget to emit it. */
mark_decl_referenced (decl);
TREE_USED (decl) = 1;
}
}
}

View File

@ -14572,7 +14572,7 @@ reference_to_unused (tree * tp, int * walk_subtrees,
else if (TREE_CODE (*tp) == VAR_DECL)
{
struct varpool_node *node = varpool_get_node (*tp);
if (!node || !node->needed)
if (!node || !node->analyzed)
return *tp;
}
else if (TREE_CODE (*tp) == FUNCTION_DECL
@ -17057,7 +17057,7 @@ premark_types_used_by_global_vars_helper (void **slot,
/* Ask cgraph if the global variable really is to be emitted.
If yes, then we'll keep the DIE of ENTRY->TYPE. */
struct varpool_node *node = varpool_get_node (entry->var_decl);
if (node && node->needed)
if (node && node->analyzed)
{
die->die_perennial_p = 1;
/* Keep the parent DIEs as well. */

View File

@ -2814,8 +2814,6 @@ output_ttype (tree type, int tt_format, int tt_format_size)
value = const0_rtx;
else
{
struct varpool_node *node;
/* FIXME lto. pass_ipa_free_lang_data changes all types to
runtime types so TYPE should already be a runtime type
reference. When pass_ipa_free_lang data is made a default
@ -2834,12 +2832,7 @@ output_ttype (tree type, int tt_format, int tt_format_size)
{
type = TREE_OPERAND (type, 0);
if (TREE_CODE (type) == VAR_DECL)
{
node = varpool_node (type);
if (node)
varpool_mark_needed_node (node);
is_public = TREE_PUBLIC (type);
}
is_public = TREE_PUBLIC (type);
}
else
gcc_assert (TREE_CODE (type) == INTEGER_CST);

View File

@ -107,7 +107,7 @@ process_references (struct ipa_ref_list *list,
struct varpool_node *node = ipa_ref_varpool_node (ref);
if (!node->needed)
{
varpool_mark_needed_node (node);
node->needed = true;
enqueue_varpool_node (node, first_varpool);
}
}
@ -187,7 +187,6 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
FOR_EACH_VARIABLE (vnode)
gcc_assert (!vnode->symbol.aux);
#endif
varpool_reset_queue ();
/* Mark functions whose bodies are obviously needed.
This is mostly when they can be referenced externally. Inline clones
are special since their declarations are shared with master clone and thus
@ -213,13 +212,10 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
/* Mark variables that are obviously needed. */
FOR_EACH_VARIABLE (vnode)
{
vnode->next_needed = NULL;
vnode->prev_needed = NULL;
if ((vnode->analyzed || vnode->symbol.force_output)
&& !varpool_can_remove_if_no_refs (vnode))
{
vnode->needed = false;
varpool_mark_needed_node (vnode);
vnode->needed = true;
enqueue_varpool_node (vnode, &first_varpool);
}
else
@ -315,7 +311,7 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
next = varpool (next->symbol.same_comdat_group))
if (!next->needed)
{
varpool_mark_needed_node (next);
next->needed = true;
enqueue_varpool_node (next, &first_varpool);
}
}
@ -794,8 +790,6 @@ function_and_variable_visibility (bool whole_program)
&& !DECL_EXTERNAL (vnode->symbol.decl))
{
vnode->symbol.force_output = 1;
varpool_mark_needed_node (vnode);
gcc_assert (vnode->needed);
pointer_set_insert (aliased_vnodes, vnode);
if (dump_file)
fprintf (dump_file, " varpool node %s",
@ -933,10 +927,9 @@ function_and_variable_visibility (bool whole_program)
{
if (!vnode->finalized)
continue;
if (vnode->needed
&& varpool_externally_visible_p
(vnode,
pointer_set_contains (aliased_vnodes, vnode)))
if (varpool_externally_visible_p
(vnode,
pointer_set_contains (aliased_vnodes, vnode)))
vnode->symbol.externally_visible = true;
else
vnode->symbol.externally_visible = false;
@ -1018,7 +1011,6 @@ static unsigned int
whole_program_function_and_variable_visibility (void)
{
struct cgraph_node *node;
struct varpool_node *vnode;
function_and_variable_visibility (flag_whole_program);
@ -1026,17 +1018,6 @@ whole_program_function_and_variable_visibility (void)
if ((node->symbol.externally_visible && !DECL_COMDAT (node->symbol.decl))
&& node->local.finalized)
cgraph_mark_reachable_node (node);
FOR_EACH_DEFINED_VARIABLE (vnode)
if (vnode->symbol.externally_visible && !DECL_COMDAT (vnode->symbol.decl))
varpool_mark_needed_node (vnode);
if (dump_file)
{
fprintf (dump_file, "\nNeeded variables:");
FOR_EACH_DEFINED_VARIABLE (vnode)
if (vnode->needed)
fprintf (dump_file, " %s", varpool_node_name (vnode));
fprintf (dump_file, "\n\n");
}
if (optimize)
ipa_discover_readonly_nonaddressable_vars ();
return 0;

View File

@ -1,3 +1,7 @@
2012-04-22 Jan Hubicka <jh@suse.cz>
* class.c (build_utf8_ref): Do not mark varpool node as needed.
2012-04-20 Jan Hubicka <jh@suse.cz>
* class.c (make_local_function_alias): Do not mark symbol referenced.

View File

@ -1001,7 +1001,6 @@ build_utf8_ref (tree name)
DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (ctype);
pushdecl (decl);
rest_of_decl_compilation (decl, global_bindings_p (), 0);
varpool_mark_needed_node (varpool_node (decl));
ref = build1 (ADDR_EXPR, utf8const_ptr_type, decl);
IDENTIFIER_UTF8_REF (name) = ref;
return ref;

View File

@ -571,7 +571,6 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node
bp_pack_value (&bp, node->alias, 1);
bp_pack_value (&bp, node->alias_of != NULL, 1);
gcc_assert (node->finalized || !node->analyzed);
gcc_assert (node->needed);
/* 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. */
@ -1079,16 +1078,14 @@ input_varpool_node (struct lto_file_decl_data *file_data,
node->finalized = bp_unpack_value (&bp, 1);
node->alias = bp_unpack_value (&bp, 1);
non_null_aliasof = bp_unpack_value (&bp, 1);
node->analyzed = node->finalized;
node->symbol.used_from_other_partition = bp_unpack_value (&bp, 1);
node->symbol.in_other_partition = bp_unpack_value (&bp, 1);
node->analyzed = (node->finalized && (!node->alias || !node->symbol.in_other_partition));
if (node->symbol.in_other_partition)
{
DECL_EXTERNAL (node->symbol.decl) = 1;
TREE_STATIC (node->symbol.decl) = 0;
}
if (node->finalized)
varpool_mark_needed_node (node);
if (non_null_aliasof)
{
decl_index = streamer_read_uhwi (ib);
@ -1457,6 +1454,8 @@ input_cgraph (void)
unsigned int j = 0;
struct cgraph_node *node;
cgraph_state = CGRAPH_STATE_IPA_SSA;
while ((file_data = file_data_vec[j++]))
{
const char *data;

View File

@ -262,12 +262,6 @@ static void
lto_varpool_replace_node (struct varpool_node *vnode,
struct varpool_node *prevailing_node)
{
/* Merge node flags. */
if (vnode->needed)
{
gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
varpool_mark_needed_node (prevailing_node);
}
gcc_assert (!vnode->finalized || prevailing_node->finalized);
gcc_assert (!vnode->analyzed || prevailing_node->analyzed);

View File

@ -283,7 +283,7 @@ partition_cgraph_node_p (struct cgraph_node *node)
static bool
partition_varpool_node_p (struct varpool_node *vnode)
{
if (vnode->alias || !vnode->needed)
if (vnode->alias || !vnode->analyzed)
return false;
/* Constant pool and comdat are always only in partitions they are needed. */
if (DECL_IN_CONSTANT_POOL (vnode->symbol.decl)

View File

@ -2342,8 +2342,8 @@ ipa_write_summaries (void)
}
vset = varpool_node_set_new ();
FOR_EACH_VARIABLE (vnode)
if (vnode->needed && (!vnode->alias || vnode->alias_of))
FOR_EACH_DEFINED_VARIABLE (vnode)
if ((!vnode->alias || vnode->alias_of))
varpool_node_set_add (vset, vnode);
ipa_write_summaries_1 (set, vset);

View File

@ -429,6 +429,11 @@ dump_symtab_base (FILE *f, symtab_node node)
if (node->symbol.address_taken)
fprintf (f, " Address is taken.\n");
if (node->symbol.aux)
{
fprintf (f, " Aux:");
dump_addr (f, " @", (void *)node->symbol.aux);
}
fprintf (f, " References: ");
ipa_dump_references (f, &node->symbol.ref_list);

View File

@ -413,7 +413,7 @@ wrapup_global_declaration_2 (tree decl)
&& (TREE_USED (decl)
|| TREE_USED (DECL_ASSEMBLER_NAME (decl))))
/* needed */;
else if (node && node->needed)
else if (node && node->analyzed)
/* needed */;
else if (DECL_COMDAT (decl))
needed = false;
@ -581,6 +581,7 @@ compile_file (void)
basically finished. */
if (in_lto_p || !flag_lto || flag_fat_lto_objects)
{
varpool_remove_unreferenced_decls ();
varpool_assemble_pending_decls ();
finish_aliases_2 ();

View File

@ -87,7 +87,6 @@ init_ic_make_global_vars (void)
decl_default_tls_model (ic_void_ptr_var);
varpool_finalize_decl (ic_void_ptr_var);
varpool_mark_needed_node (varpool_node (ic_void_ptr_var));
gcov_type_ptr = build_pointer_type (get_gcov_type ());
ic_gcov_type_ptr_var
@ -103,7 +102,6 @@ init_ic_make_global_vars (void)
decl_default_tls_model (ic_gcov_type_ptr_var);
varpool_finalize_decl (ic_gcov_type_ptr_var);
varpool_mark_needed_node (varpool_node (ic_gcov_type_ptr_var));
}
void

View File

@ -625,7 +625,6 @@ build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi,
TREE_CONSTANT (decl) = 1;
TREE_READONLY (decl) = 1;
add_referenced_var (decl);
varpool_mark_needed_node (varpool_node (decl));
varpool_finalize_decl (decl);
fetch = build4 (ARRAY_REF, value_type, decl, tidx, NULL_TREE,

View File

@ -2254,7 +2254,6 @@ mark_decl_referenced (tree decl)
else if (TREE_CODE (decl) == VAR_DECL)
{
struct varpool_node *node = varpool_node (decl);
varpool_mark_needed_node (node);
/* C++ frontend use mark_decl_references to force COMDAT variables
to be output that might appear dead otherwise. */
node->symbol.force_output = true;

View File

@ -1,5 +1,5 @@
/* Callgraph handling code.
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011, 2012
Free Software Foundation, Inc.
Contributed by Jan Hubicka
@ -48,32 +48,6 @@ along with GCC; see the file COPYING3. If not see
All variables supposed to be output into final file needs to be
explicitly marked by frontend via VARPOOL_FINALIZE_DECL function. */
/* Queue of cgraph nodes scheduled to be lowered and output.
The queue is maintained via mark_needed_node, linked via node->next_needed
pointer.
LAST_NEEDED_NODE points to the end of queue, so it can be
maintained in forward order. GTY is needed to make it friendly to
PCH.
During compilation we construct the queue of needed variables
twice: first time it is during cgraph construction, second time it is at the
end of compilation in VARPOOL_REMOVE_UNREFERENCED_DECLS so we can avoid
optimized out variables being output.
Each variable is thus first analyzed and then later possibly output.
FIRST_UNANALYZED_NODE points to first node in queue that was not analyzed
yet and is moved via VARPOOL_ANALYZE_PENDING_DECLS. */
symtab_node x_varpool_nodes_queue;
static GTY(()) symtab_node x_varpool_last_needed_node;
#define varpool_last_needed_node ((struct varpool_node *)x_varpool_last_needed_node)
static GTY(()) symtab_node x_varpool_first_unanalyzed_node;
#define varpool_first_unanalyzed_node ((struct varpool_node *)x_varpool_first_unanalyzed_node)
/* Lists all assembled variables to be sent to debugger output later on. */
static GTY(()) struct varpool_node *varpool_assembled_nodes_queue;
/* Return varpool node assigned to DECL. Create new one when needed. */
struct varpool_node *
varpool_node (tree decl)
@ -95,24 +69,7 @@ varpool_node (tree decl)
void
varpool_remove_node (struct varpool_node *node)
{
gcc_assert (!varpool_assembled_nodes_queue);
symtab_unregister_node ((symtab_node)node);
if (varpool_first_unanalyzed_node == node)
x_varpool_first_unanalyzed_node = (symtab_node)node->next_needed;
if (node->next_needed)
node->next_needed->prev_needed = node->prev_needed;
else if (node->prev_needed)
{
gcc_assert (varpool_last_needed_node);
x_varpool_last_needed_node = (symtab_node)node->prev_needed;
}
if (node->prev_needed)
node->prev_needed->next_needed = node->next_needed;
else if (node->next_needed)
{
gcc_assert (varpool_nodes_queue == node);
x_varpool_nodes_queue = (symtab_node)node->next_needed;
}
ggc_free (node);
}
@ -128,8 +85,6 @@ dump_varpool_node (FILE *f, struct varpool_node *node)
fprintf (f, " Varpool flags:");
if (DECL_INITIAL (node->symbol.decl))
fprintf (f, " initialized");
if (node->needed)
fprintf (f, " needed");
if (node->analyzed)
fprintf (f, " analyzed");
if (node->finalized)
@ -168,45 +123,6 @@ varpool_node_for_asm (tree asmname)
return NULL;
}
/* Helper function for finalization code - add node into lists so it will
be analyzed and compiled. */
static void
varpool_enqueue_needed_node (struct varpool_node *node)
{
if (varpool_last_needed_node)
{
varpool_last_needed_node->next_needed = node;
node->prev_needed = varpool_last_needed_node;
}
x_varpool_last_needed_node = (symtab_node)node;
node->next_needed = NULL;
if (!varpool_nodes_queue)
x_varpool_nodes_queue = (symtab_node)node;
if (!varpool_first_unanalyzed_node)
x_varpool_first_unanalyzed_node = (symtab_node)node;
notice_global_symbol (node->symbol.decl);
}
/* Notify finalize_compilation_unit that given node is reachable
or needed. */
void
varpool_mark_needed_node (struct varpool_node *node)
{
if (!node->needed && node->finalized
&& !TREE_ASM_WRITTEN (node->symbol.decl))
varpool_enqueue_needed_node (node);
node->needed = 1;
}
/* Reset the queue of needed nodes. */
void
varpool_reset_queue (void)
{
x_varpool_last_needed_node = NULL;
x_varpool_nodes_queue = NULL;
x_varpool_first_unanalyzed_node = NULL;
}
/* Determine if variable DECL is needed. That is, visible to something
either outside this translation unit, something magic in the system
configury */
@ -270,42 +186,6 @@ const_value_known_p (tree decl)
return true;
}
/* Mark DECL as finalized. By finalizing the declaration, frontend instruct the
middle end to output the variable to asm file, if needed or externally
visible. */
void
varpool_finalize_decl (tree decl)
{
struct varpool_node *node = varpool_node (decl);
gcc_assert (TREE_STATIC (decl));
/* The first declaration of a variable that comes through this function
decides whether it is global (in C, has external linkage)
or local (in C, has internal linkage). So do nothing more
if this function has already run. */
if (node->finalized)
{
if (cgraph_global_info_ready)
varpool_assemble_pending_decls ();
return;
}
if (node->needed)
varpool_enqueue_needed_node (node);
node->finalized = true;
if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl)
/* Traditionally we do not eliminate static variables when not
optimizing and when not doing toplevel reoder. */
|| (!flag_toplevel_reorder && !DECL_COMDAT (node->symbol.decl)
&& !DECL_ARTIFICIAL (node->symbol.decl)))
node->symbol.force_output = true;
if (decide_is_variable_needed (node, decl))
varpool_mark_needed_node (node);
if (cgraph_global_info_ready)
varpool_assemble_pending_decls ();
}
/* Add the variable DECL to the varpool.
Unlike varpool_finalize_decl function is intended to be used
by middle end and allows insertion of new variable at arbitrary point
@ -338,93 +218,69 @@ cgraph_variable_initializer_availability (struct varpool_node *node)
return AVAIL_AVAILABLE;
}
/* Walk the decls we marked as necessary and see if they reference new
variables or functions and add them into the worklists. */
bool
varpool_analyze_pending_decls (void)
void
varpool_analyze_node (struct varpool_node *node)
{
bool changed = false;
tree decl = node->symbol.decl;
timevar_push (TV_VARPOOL);
while (varpool_first_unanalyzed_node)
/* When reading back varpool at LTO time, we re-construct the queue in order
to have "needed" list right by inserting all needed nodes into varpool.
We however don't want to re-analyze already analyzed nodes. */
if (!node->analyzed)
{
struct varpool_node *node = varpool_first_unanalyzed_node, *next;
tree decl = node->symbol.decl;
bool analyzed = node->analyzed;
gcc_assert (!in_lto_p || cgraph_function_flags_ready);
/* Compute the alignment early so function body expanders are
already informed about increased alignment. */
align_variable (decl, 0);
}
if (node->alias && node->alias_of)
{
struct varpool_node *tgt = varpool_node (node->alias_of);
struct varpool_node *n;
varpool_first_unanalyzed_node->analyzed = true;
x_varpool_first_unanalyzed_node = (symtab_node)varpool_first_unanalyzed_node->next_needed;
/* When reading back varpool at LTO time, we re-construct the queue in order
to have "needed" list right by inserting all needed nodes into varpool.
We however don't want to re-analyze already analyzed nodes. */
if (!analyzed)
for (n = tgt; n && n->alias;
n = n->analyzed ? varpool_alias_aliased_node (n) : NULL)
if (n == node)
{
error ("variable %q+D part of alias cycle", node->symbol.decl);
node->alias = false;
continue;
}
if (!VEC_length (ipa_ref_t, node->symbol.ref_list.references))
ipa_record_reference ((symtab_node)node, (symtab_node)tgt, IPA_REF_ALIAS, NULL);
/* C++ FE sometimes change linkage flags after producing same body aliases. */
if (node->extra_name_alias)
{
gcc_assert (!in_lto_p || cgraph_function_flags_ready);
/* Compute the alignment early so function body expanders are
already informed about increased alignment. */
align_variable (decl, 0);
}
if (node->alias && node->alias_of)
{
struct varpool_node *tgt = varpool_node (node->alias_of);
struct varpool_node *n;
for (n = tgt; n && n->alias;
n = n->analyzed ? varpool_alias_aliased_node (n) : NULL)
if (n == node)
{
error ("variable %q+D part of alias cycle", node->symbol.decl);
node->alias = false;
continue;
}
if (!VEC_length (ipa_ref_t, node->symbol.ref_list.references))
ipa_record_reference ((symtab_node)node, (symtab_node)tgt, IPA_REF_ALIAS, NULL);
/* C++ FE sometimes change linkage flags after producing same body aliases. */
if (node->extra_name_alias)
DECL_WEAK (node->symbol.decl) = DECL_WEAK (node->alias_of);
TREE_PUBLIC (node->symbol.decl) = TREE_PUBLIC (node->alias_of);
DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (node->alias_of);
DECL_VISIBILITY (node->symbol.decl) = DECL_VISIBILITY (node->alias_of);
if (TREE_PUBLIC (node->symbol.decl))
{
DECL_WEAK (node->symbol.decl) = DECL_WEAK (node->alias_of);
TREE_PUBLIC (node->symbol.decl) = TREE_PUBLIC (node->alias_of);
DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (node->alias_of);
DECL_VISIBILITY (node->symbol.decl) = DECL_VISIBILITY (node->alias_of);
if (TREE_PUBLIC (node->symbol.decl))
DECL_COMDAT (node->symbol.decl) = DECL_COMDAT (node->alias_of);
DECL_COMDAT_GROUP (node->symbol.decl) = DECL_COMDAT_GROUP (node->alias_of);
if (DECL_ONE_ONLY (node->alias_of)
&& !node->symbol.same_comdat_group)
{
DECL_COMDAT (node->symbol.decl) = DECL_COMDAT (node->alias_of);
DECL_COMDAT_GROUP (node->symbol.decl) = DECL_COMDAT_GROUP (node->alias_of);
if (DECL_ONE_ONLY (node->alias_of)
&& !node->symbol.same_comdat_group)
node->symbol.same_comdat_group = (symtab_node)tgt;
if (!tgt->symbol.same_comdat_group)
tgt->symbol.same_comdat_group = (symtab_node)node;
else
{
node->symbol.same_comdat_group = (symtab_node)tgt;
if (!tgt->symbol.same_comdat_group)
tgt->symbol.same_comdat_group = (symtab_node)node;
else
{
symtab_node n;
for (n = tgt->symbol.same_comdat_group;
n->symbol.same_comdat_group != (symtab_node)tgt;
n = n->symbol.same_comdat_group)
;
n->symbol.same_comdat_group = (symtab_node)node;
}
symtab_node n;
for (n = tgt->symbol.same_comdat_group;
n->symbol.same_comdat_group != (symtab_node)tgt;
n = n->symbol.same_comdat_group)
;
n->symbol.same_comdat_group = (symtab_node)node;
}
}
}
varpool_mark_needed_node (tgt);
}
else if (DECL_INITIAL (decl))
record_references_in_initializer (decl, analyzed);
if (node->symbol.same_comdat_group)
{
for (next = varpool (node->symbol.same_comdat_group);
next != node;
next = varpool (next->symbol.same_comdat_group))
varpool_mark_needed_node (next);
}
changed = true;
}
timevar_pop (TV_VARPOOL);
return changed;
else if (DECL_INITIAL (decl))
record_references_in_initializer (decl, node->analyzed);
node->analyzed = true;
}
/* Assemble thunks and aliases asociated to NODE. */
@ -459,11 +315,6 @@ varpool_assemble_decl (struct varpool_node *node)
assemble_variable (decl, 0, 1, 0);
if (TREE_ASM_WRITTEN (decl))
{
node->next_needed = varpool_assembled_nodes_queue;
node->prev_needed = NULL;
if (varpool_assembled_nodes_queue)
varpool_assembled_nodes_queue->prev_needed = node;
varpool_assembled_nodes_queue = node;
node->finalized = 1;
assemble_aliases (node);
return true;
@ -473,40 +324,85 @@ varpool_assemble_decl (struct varpool_node *node)
return false;
}
/* Optimization of function bodies might've rendered some variables as
unnecessary so we want to avoid these from being compiled.
/* Add NODE to queue starting at FIRST.
The queue is linked via AUX pointers and terminated by pointer to 1. */
static void
enqueue_node (struct varpool_node *node, struct varpool_node **first)
{
if (node->symbol.aux)
return;
gcc_checking_assert (*first);
node->symbol.aux = *first;
*first = node;
}
/* Optimization of function bodies might've rendered some variables as
unnecessary so we want to avoid these from being compiled. Re-do
reachability starting from variables that are either externally visible
or was referred from the asm output routines. */
This is done by pruning the queue and keeping only the variables that
really appear needed (ie they are either externally visible or referenced
by compiled function). Re-doing the reachability analysis on variables
brings back the remaining variables referenced by these. */
void
varpool_remove_unreferenced_decls (void)
{
struct varpool_node *next, *node = varpool_nodes_queue;
varpool_reset_queue ();
struct varpool_node *next, *node;
struct varpool_node *first = (struct varpool_node *)(void *)1;
int i;
struct ipa_ref *ref;
if (seen_error ())
return;
while (node)
if (cgraph_dump_file)
fprintf (cgraph_dump_file, "Trivially needed variables:");
finish_aliases_1 ();
FOR_EACH_DEFINED_VARIABLE (node)
{
next = node->next_needed;
node->needed = 0;
if (node->analyzed
&& (!varpool_can_remove_if_no_refs (node)
/* We just expanded all function bodies. See if any of
them needed the variable. */
|| DECL_RTL_SET_P (node->symbol.decl)))
varpool_mark_needed_node (node);
node = next;
{
enqueue_node (node, &first);
if (cgraph_dump_file)
fprintf (cgraph_dump_file, " %s", varpool_node_asm_name (node));
}
}
/* Make sure we mark alias targets as used targets. */
finish_aliases_1 ();
varpool_analyze_pending_decls ();
while (first != (struct varpool_node *)(void *)1)
{
node = first;
first = (struct varpool_node *)first->symbol.aux;
if (node->symbol.same_comdat_group)
{
symtab_node next;
for (next = node->symbol.same_comdat_group;
next != (symtab_node)node;
next = next->symbol.same_comdat_group)
if (symtab_variable_p (next)
&& varpool (next)->analyzed)
enqueue_node (varpool (next), &first);
}
for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, i, ref); i++)
if (symtab_variable_p (ref->referred)
&& varpool (ref->referred)->analyzed)
enqueue_node (varpool (ref->referred), &first);
}
if (cgraph_dump_file)
fprintf (cgraph_dump_file, "\nRemoving variables:");
for (node = varpool_first_defined_variable (); node; node = next)
{
next = varpool_next_defined_variable (node);
if (!node->symbol.aux)
{
if (cgraph_dump_file)
fprintf (cgraph_dump_file, " %s", varpool_node_asm_name (node));
varpool_remove_node (node);
}
}
if (cgraph_dump_file)
fprintf (cgraph_dump_file, "\n");
}
/* For variables in named sections make sure get_variable_section
@ -537,55 +433,17 @@ varpool_assemble_pending_decls (void)
return false;
timevar_push (TV_VAROUT);
/* EH might mark decls as needed during expansion. This should be safe since
we don't create references to new function, but it should not be used
elsewhere. */
varpool_analyze_pending_decls ();
FOR_EACH_DEFINED_VARIABLE (node)
varpool_finalize_named_section_flags (node);
while (varpool_nodes_queue)
{
struct varpool_node *node = varpool_nodes_queue;
x_varpool_nodes_queue = (symtab_node)(varpool_nodes_queue->next_needed);
if (varpool_assemble_decl (node))
changed = true;
else
{
node->prev_needed = NULL;
node->next_needed = NULL;
}
}
/* varpool_nodes_queue is now empty, clear the pointer to the last element
in the queue. */
x_varpool_last_needed_node = NULL;
FOR_EACH_DEFINED_VARIABLE (node)
if (varpool_assemble_decl (node))
changed = true;
timevar_pop (TV_VAROUT);
return changed;
}
/* Remove all elements from the queue so we can re-use it for debug output. */
void
varpool_empty_needed_queue (void)
{
/* EH might mark decls as needed during expansion. This should be safe since
we don't create references to new function, but it should not be used
elsewhere. */
varpool_analyze_pending_decls ();
while (varpool_nodes_queue)
{
struct varpool_node *node = varpool_nodes_queue;
x_varpool_nodes_queue = (symtab_node)varpool_nodes_queue->next_needed;
node->next_needed = NULL;
node->prev_needed = NULL;
}
/* varpool_nodes_queue is now empty, clear the pointer to the last element
in the queue. */
x_varpool_last_needed_node = NULL;
}
/* Create a new global variable of type TYPE. */
tree
add_new_static_var (tree type)
@ -603,7 +461,6 @@ add_new_static_var (tree type)
lang_hooks.dup_lang_specific_decl (new_decl);
create_var_ann (new_decl);
new_node = varpool_node (new_decl);
varpool_mark_needed_node (new_node);
add_referenced_var (new_decl);
varpool_finalize_decl (new_decl);
@ -624,10 +481,17 @@ varpool_create_variable_alias (tree alias, tree decl)
alias_node->alias = 1;
alias_node->finalized = 1;
alias_node->alias_of = decl;
if ((!DECL_EXTERNAL (alias)
&& decide_is_variable_needed (alias_node, alias))
|| alias_node->needed)
varpool_mark_needed_node (alias_node);
/* Extra name alias mechanizm creates aliases really late
via DECL_ASSEMBLER_NAME mechanizm.
This is unfortunate because they are not going through the
standard channels. Ensure they get output. */
if (cgraph_state >= CGRAPH_STATE_IPA)
{
varpool_analyze_node (alias_node);
if (TREE_PUBLIC (alias))
alias_node->symbol.externally_visible = true;
}
return alias_node;
}
@ -688,4 +552,3 @@ varpool_for_node_and_aliases (struct varpool_node *node,
}
return false;
}
#include "gt-varpool.h"