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:
parent
f04e40afc1
commit
660584689a
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
25
gcc/cgraph.c
25
gcc/cgraph.c
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
119
gcc/cgraph.h
119
gcc/cgraph.h
|
@ -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 *
|
||||
|
|
|
@ -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);
|
||||
|
|
377
gcc/cgraphunit.c
377
gcc/cgraphunit.c
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
31
gcc/ipa.c
31
gcc/ipa.c
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
395
gcc/varpool.c
395
gcc/varpool.c
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue