* 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
+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
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)
$(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 \
+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
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))
{
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;
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;
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;
}
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,
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;
}
else
notice_global_symbol (node->symbol.decl);
node->reachable = 1;
-
- node->next_needed = cgraph_nodes_queue;
- x_cgraph_nodes_queue = (symtab_node)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;
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. */
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. */
};
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;
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 *);
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);
#define FOR_EACH_SYMBOL(node) \
for ((node) = symtab_nodes; (node); (node) = (node)->symbol.next)
+
+/* Return first variable. */
+static inline struct varpool_node *
+varpool_first_variable (void)
+{
+ symtab_node node;
+ for (node = symtab_nodes; node; node = node->symbol.next)
+ {
+ if (symtab_variable_p (node))
+ return varpool (node);
+ }
+ return NULL;
+}
+
+/* Return next variable after NODE. */
+static inline struct varpool_node *
+varpool_next_variable (struct varpool_node *node)
+{
+ symtab_node node1 = (symtab_node) node->symbol.next;
+ for (; node1; node1 = node1->symbol.next)
+ {
+ if (symtab_variable_p (node1))
+ return varpool (node1);
+ }
+ return NULL;
+}
+/* Walk all variables. */
+#define FOR_EACH_VARIABLE(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)
{
- struct varpool_node *node;
- for (node = varpool_nodes_queue; node; node = node->next_needed)
+ symtab_node node;
+ for (node = symtab_nodes; node; node = node->symbol.next)
{
- gcc_checking_assert (TREE_CODE (node->symbol.decl) == VAR_DECL);
- if (DECL_INITIAL (node->symbol.decl))
- return node;
+ if (symtab_variable_p (node)
+ && DECL_INITIAL (node->symbol.decl))
+ return varpool (node);
}
return NULL;
}
static inline struct varpool_node *
varpool_next_static_initializer (struct varpool_node *node)
{
- for (node = node->next_needed; node; node = node->next_needed)
+ symtab_node node1 = (symtab_node) node->symbol.next;
+ for (; node1; node1 = node1->symbol.next)
{
- gcc_checking_assert (TREE_CODE (node->symbol.decl) == VAR_DECL);
- if (DECL_INITIAL (node->symbol.decl))
- return node;
+ if (symtab_variable_p (node1)
+ && DECL_INITIAL (node1->symbol.decl))
+ return varpool (node1);
}
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. */
+/* Return first reachable static variable with initializer. */
static inline struct varpool_node *
-varpool_first_variable (void)
+varpool_first_defined_variable (void)
{
symtab_node node;
for (node = symtab_nodes; node; node = node->symbol.next)
{
- if (symtab_variable_p (node))
+ if (symtab_variable_p (node) && varpool (node)->analyzed)
return varpool (node);
}
return NULL;
}
-/* Return next variable after NODE. */
+/* Return next reachable static variable with initializer after NODE. */
static inline struct varpool_node *
-varpool_next_variable (struct varpool_node *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))
+ if (symtab_variable_p (node1) && varpool (node1)->analyzed)
return varpool (node1);
}
return NULL;
}
-/* Walk all variables. */
-#define FOR_EACH_VARIABLE(node) \
- for ((node) = varpool_first_variable (); \
- (node); \
- (node) = varpool_next_variable ((node)))
/* 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 *
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);
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);
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);
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);
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);
#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 *);
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. */
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:
gcc_unreachable ();
break;
}
- varpool_analyze_pending_decls ();
}
+ free_cgraph_node_set (cgraph_new_nodes);
+ cgraph_new_nodes = NULL;
return output;
}
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:
}
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:
{
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
}
}
-/* 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)
/* 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 ();
+ changed = false;
+ process_function_and_variable_attributes (first_analyzed,
+ first_analyzed_var);
- /* 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)
+ /* 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)
{
- cgraph_reset_node (node);
- node->local.redefined_extern_inline = true;
- continue;
+ 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 (!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 (changed && dump_file)
+ fprintf (cgraph_dump_file, "\n");
- if (node->symbol.same_comdat_group)
+ /* Lower representation, build callgraph edges and references for all trivially
+ needed symbols and all symbols referred by them. */
+ while (first != (symtab_node)(void *)1)
{
- for (next = cgraph (node->symbol.same_comdat_group);
- next != node;
- next = cgraph (next->symbol.same_comdat_group))
- cgraph_mark_reachable_node (next);
- }
+ 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 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;
- }
+ if (!cnode->analyzed)
+ cgraph_analyze_function (cnode);
- /* We finalize local static variables during constructing callgraph
- edges. Process their attributes too. */
- 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 ();
- cgraph_process_new_functions ();
+ 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 ();
}
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)
}
/* 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)
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)
{
+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
DECL_COMDAT (decl) = 1;
/* Mark it needed so we don't forget to emit it. */
mark_decl_referenced (decl);
+ TREE_USED (decl) = 1;
}
}
}
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
/* 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. */
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
{
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);
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);
}
}
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
/* 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
next = varpool (next->symbol.same_comdat_group))
if (!next->needed)
{
- varpool_mark_needed_node (next);
+ next->needed = true;
enqueue_varpool_node (next, &first_varpool);
}
}
&& !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",
{
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;
whole_program_function_and_variable_visibility (void)
{
struct cgraph_node *node;
- struct varpool_node *vnode;
function_and_variable_visibility (flag_whole_program);
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;
+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.
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;
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. */
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);
unsigned int j = 0;
struct cgraph_node *node;
+ cgraph_state = CGRAPH_STATE_IPA_SSA;
+
while ((file_data = file_data_vec[j++]))
{
const char *data;
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);
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)
}
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);
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);
&& (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;
basically finished. */
if (in_lto_p || !flag_lto || flag_fat_lto_objects)
{
+ varpool_remove_unreferenced_decls ();
varpool_assemble_pending_decls ();
finish_aliases_2 ();
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
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
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,
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;
/* 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
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)
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);
}
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)
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 */
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
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;
-
- 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)
- {
- 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)
+ 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)
{
- 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. */
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;
return false;
}
+/* 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.
+ 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);
+ {
+ enqueue_node (node, &first);
+ if (cgraph_dump_file)
+ fprintf (cgraph_dump_file, " %s", varpool_node_asm_name (node));
+ }
+ }
+ while (first != (struct varpool_node *)(void *)1)
+ {
+ node = first;
+ first = (struct varpool_node *)first->symbol.aux;
- node = next;
+ 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);
}
- /* Make sure we mark alias targets as used targets. */
- finish_aliases_1 ();
- varpool_analyze_pending_decls ();
+ 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
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)
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);
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;
}
}
return false;
}
-#include "gt-varpool.h"