aboutsummaryrefslogtreecommitdiff
path: root/gcc/cgraphunit.c
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2012-04-22 21:28:07 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2012-04-22 21:28:07 +0000
commitff2a5adaa72fef87cac689a40c23258a30b304c8 (patch)
treea4cd93cef18f73580dc0226c3ce10cbae70f9f08 /gcc/cgraphunit.c
parent62c34bfbaa44da92a4c3cb45314370d19b0d324c (diff)
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@186687 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cgraphunit.c')
-rw-r--r--gcc/cgraphunit.c365
1 files changed, 223 insertions, 142 deletions
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 3e07e501013..409afa13da4 100644
--- a/gcc/cgraphunit.c
+++ b/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 ();
+ 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 ();
}
@@ -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)
{