Commit b34fd25c by Jan Hubicka Committed by Jan Hubicka

cgraph.h (struct varpool_node): Add aux.


	* cgraph.h (struct varpool_node): Add aux.
	* varasm.c (find_decl_and_mark_needed): Force output of varpool nodes.
	* varpool.c (varpool_remove_node): Do not remove initializer.
	(varpool_reset_queue): Export.
	(varpool_finalize_decl): Volatile vars are forced to be output.
	* lto-symtab.c (lto_varpool_replace_node): Clear out initializer of
	replaced decl.
	* ipa.c (enqueue_cgraph_node, enqueue_varpool_node,
	process_references, varpool_can_remove_if_no_refs): New functions.
	(cgraph_remove_unreachable_nodes): Handle variables too.

From-SVN: r159321
parent 49f19b1c
2010-05-12 Jan Hubicka <jh@suse.cz>
* cgraph.h (struct varpool_node): Add aux.
* varasm.c (find_decl_and_mark_needed): Force output of varpool nodes.
* varpool.c (varpool_remove_node): Do not remove initializer.
(varpool_reset_queue): Export.
(varpool_finalize_decl): Volatile vars are forced to be output.
* lto-symtab.c (lto_varpool_replace_node): Clear out initializer of
replaced decl.
* ipa.c (enqueue_cgraph_node, enqueue_varpool_node,
process_references, varpool_can_remove_if_no_refs): New functions.
(cgraph_remove_unreachable_nodes): Handle variables too.
2010-05-12 H.J. Lu <hongjiu.lu@intel.com> 2010-05-12 H.J. Lu <hongjiu.lu@intel.com>
PR target/44088 PR target/44088
......
...@@ -2387,7 +2387,7 @@ cgraph_add_new_function (tree fndecl, bool lowered) ...@@ -2387,7 +2387,7 @@ cgraph_add_new_function (tree fndecl, bool lowered)
bool bool
cgraph_node_can_be_local_p (struct cgraph_node *node) cgraph_node_can_be_local_p (struct cgraph_node *node)
{ {
return (!node->needed return (!node->needed && !node->address_taken
&& ((DECL_COMDAT (node->decl) && !node->same_comdat_group) && ((DECL_COMDAT (node->decl) && !node->same_comdat_group)
|| !node->local.externally_visible)); || !node->local.externally_visible));
} }
......
...@@ -439,6 +439,7 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.prev"))) varpool_node { ...@@ -439,6 +439,7 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.prev"))) varpool_node {
nodes a pointer to the normal node. */ nodes a pointer to the normal node. */
struct varpool_node *extra_name; struct varpool_node *extra_name;
struct ipa_ref_list ref_list; struct ipa_ref_list ref_list;
PTR GTY ((skip)) aux;
/* Ordering of all cgraph nodes. */ /* Ordering of all cgraph nodes. */
int order; int order;
...@@ -673,6 +674,7 @@ void varpool_remove_unreferenced_decls (void); ...@@ -673,6 +674,7 @@ void varpool_remove_unreferenced_decls (void);
void varpool_empty_needed_queue (void); void varpool_empty_needed_queue (void);
bool varpool_extra_name_alias (tree, tree); bool varpool_extra_name_alias (tree, tree);
const char * varpool_node_name (struct varpool_node *node); const char * varpool_node_name (struct varpool_node *node);
void varpool_reset_queue (void);
/* Walk all reachable static variables. */ /* Walk all reachable static variables. */
#define FOR_EACH_STATIC_VARIABLE(node) \ #define FOR_EACH_STATIC_VARIABLE(node) \
......
...@@ -118,6 +118,69 @@ update_inlined_to_pointer (struct cgraph_node *node, struct cgraph_node *inlined ...@@ -118,6 +118,69 @@ update_inlined_to_pointer (struct cgraph_node *node, struct cgraph_node *inlined
} }
} }
/* Add cgraph NODE to queue starting at FIRST. */
static void
enqueue_cgraph_node (struct cgraph_node *node, struct cgraph_node **first)
{
node->aux = *first;
*first = node;
}
/* Add varpool NODE to queue starting at FIRST. */
static void
enqueue_varpool_node (struct varpool_node *node, struct varpool_node **first)
{
node->aux = *first;
*first = node;
}
/* Process references. */
static void
process_references (struct ipa_ref_list *list,
struct cgraph_node **first,
struct varpool_node **first_varpool,
bool before_inlining_p)
{
int i;
struct ipa_ref *ref;
for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++)
{
if (ref->refered_type == IPA_REF_CGRAPH)
{
struct cgraph_node *node = ipa_ref_node (ref);
if (!node->reachable
&& (!DECL_EXTERNAL (node->decl)
|| before_inlining_p))
{
node->reachable = true;
enqueue_cgraph_node (node, first);
}
}
else
{
struct varpool_node *node = ipa_ref_varpool_node (ref);
if (!node->needed)
{
varpool_mark_needed_node (node);
enqueue_varpool_node (node, first_varpool);
}
}
}
}
/* Return true when function NODE can be removed from callgraph
if all direct calls are eliminated. */
static inline bool
varpool_can_remove_if_no_refs (struct varpool_node *node)
{
return (!node->force_output && !node->used_from_other_partition
&& (DECL_COMDAT (node->decl) || !node->externally_visible));
}
/* Perform reachability analysis and reclaim all unreachable nodes. /* Perform reachability analysis and reclaim all unreachable nodes.
If BEFORE_INLINING_P is true this function is called before inlining If BEFORE_INLINING_P is true this function is called before inlining
decisions has been made. If BEFORE_INLINING_P is false this function also decisions has been made. If BEFORE_INLINING_P is false this function also
...@@ -127,8 +190,10 @@ bool ...@@ -127,8 +190,10 @@ bool
cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
{ {
struct cgraph_node *first = (struct cgraph_node *) (void *) 1; struct cgraph_node *first = (struct cgraph_node *) (void *) 1;
struct varpool_node *first_varpool = (struct varpool_node *) (void *) 1;
struct cgraph_node *processed = (struct cgraph_node *) (void *) 2; struct cgraph_node *processed = (struct cgraph_node *) (void *) 2;
struct cgraph_node *node, *next; struct cgraph_node *node, *next;
struct varpool_node *vnode, *vnext;
bool changed = false; bool changed = false;
#ifdef ENABLE_CHECKING #ifdef ENABLE_CHECKING
...@@ -140,15 +205,14 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) ...@@ -140,15 +205,14 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
for (node = cgraph_nodes; node; node = node->next) for (node = cgraph_nodes; node; node = node->next)
gcc_assert (!node->aux); gcc_assert (!node->aux);
#endif #endif
varpool_reset_queue ();
for (node = cgraph_nodes; node; node = node->next) for (node = cgraph_nodes; node; node = node->next)
if (!cgraph_can_remove_if_no_direct_calls_p (node) if (!cgraph_can_remove_if_no_direct_calls_p (node)
&& ((!DECL_EXTERNAL (node->decl)) && ((!DECL_EXTERNAL (node->decl))
|| !node->analyzed
|| before_inlining_p)) || before_inlining_p))
{ {
gcc_assert (!node->global.inlined_to); gcc_assert (!node->global.inlined_to);
node->aux = first; enqueue_cgraph_node (node, &first);
first = node;
node->reachable = true; node->reachable = true;
} }
else else
...@@ -156,68 +220,92 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) ...@@ -156,68 +220,92 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
gcc_assert (!node->aux); gcc_assert (!node->aux);
node->reachable = false; node->reachable = false;
} }
for (vnode = varpool_nodes; vnode; vnode = vnode->next)
{
vnode->next_needed = NULL;
vnode->prev_needed = NULL;
if (!varpool_can_remove_if_no_refs (vnode))
{
vnode->needed = false;
varpool_mark_needed_node (vnode);
enqueue_varpool_node (vnode, &first_varpool);
}
else
vnode->needed = false;
}
/* Perform reachability analysis. As a special case do not consider /* Perform reachability analysis. As a special case do not consider
extern inline functions not inlined as live because we won't output extern inline functions not inlined as live because we won't output
them at all. */ them at all. */
while (first != (void *) 1) while (first != (struct cgraph_node *) (void *) 1
|| first_varpool != (struct varpool_node *) (void *) 1)
{ {
struct cgraph_edge *e; if (first != (struct cgraph_node *) (void *) 1)
node = first; {
first = (struct cgraph_node *) first->aux; struct cgraph_edge *e;
node->aux = processed; node = first;
first = (struct cgraph_node *) first->aux;
if (node->reachable) node->aux = processed;
for (e = node->callees; e; e = e->next_callee)
if (!e->callee->reachable if (node->reachable)
&& node->analyzed for (e = node->callees; e; e = e->next_callee)
&& (!e->inline_failed || !e->callee->analyzed if (!e->callee->reachable
|| (!DECL_EXTERNAL (e->callee->decl)) && node->analyzed
|| before_inlining_p)) && (!e->inline_failed || !e->callee->analyzed
|| (!DECL_EXTERNAL (e->callee->decl))
|| before_inlining_p))
{
bool prev_reachable = e->callee->reachable;
e->callee->reachable |= node->reachable;
if (!e->callee->aux
|| (e->callee->aux == processed
&& prev_reachable != e->callee->reachable))
{
e->callee->aux = first;
first = e->callee;
}
}
/* If any function in a comdat group is reachable, force
all other functions in the same comdat group to be
also reachable. */
if (node->same_comdat_group
&& node->reachable
&& !node->global.inlined_to)
{ {
bool prev_reachable = e->callee->reachable; for (next = node->same_comdat_group;
e->callee->reachable |= node->reachable; next != node;
if (!e->callee->aux next = next->same_comdat_group)
|| (e->callee->aux == processed if (!next->reachable)
&& prev_reachable != e->callee->reachable)) {
{ next->aux = first;
e->callee->aux = first; first = next;
first = e->callee; next->reachable = true;
} }
} }
/* If any function in a comdat group is reachable, force /* We can freely remove inline clones even if they are cloned, however if
all other functions in the same comdat group to be function is clone of real clone, we must keep it around in order to
also reachable. */ make materialize_clones produce function body with the changes
if (node->same_comdat_group applied. */
&& node->reachable while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
&& !node->global.inlined_to)
{
for (next = node->same_comdat_group;
next != node;
next = next->same_comdat_group)
if (!next->reachable)
{
next->aux = first;
first = next;
next->reachable = true;
}
}
/* We can freely remove inline clones even if they are cloned, however if
function is clone of real clone, we must keep it around in order to
make materialize_clones produce function body with the changes
applied. */
while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
{
bool noninline = node->clone_of->decl != node->decl;
node = node->clone_of;
if (noninline)
{ {
node->aux = first; bool noninline = node->clone_of->decl != node->decl;
first = node; node = node->clone_of;
break; if (noninline)
{
enqueue_cgraph_node (node, &first);
break;
}
} }
process_references (&node->ref_list, &first, &first_varpool, before_inlining_p);
}
if (first_varpool != (struct varpool_node *) (void *) 1)
{
vnode = first_varpool;
first_varpool = (struct varpool_node *)first_varpool->aux;
vnode->aux = NULL;
process_references (&vnode->ref_list, &first, &first_varpool, before_inlining_p);
} }
} }
...@@ -274,6 +362,7 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) ...@@ -274,6 +362,7 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
else else
gcc_assert (!clone->in_other_partition); gcc_assert (!clone->in_other_partition);
cgraph_node_remove_callees (node); cgraph_node_remove_callees (node);
ipa_remove_all_references (&node->ref_list);
if (node->prev_sibling_clone) if (node->prev_sibling_clone)
node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone; node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
else if (node->clone_of) else if (node->clone_of)
...@@ -304,6 +393,19 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) ...@@ -304,6 +393,19 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
} }
node->aux = NULL; node->aux = NULL;
} }
if (file)
fprintf (file, "\nReclaiming variables:");
for (vnode = varpool_nodes; vnode; vnode = vnext)
{
vnext = vnode->next;
if (!vnode->needed)
{
if (file)
fprintf (file, " %s", varpool_node_name (vnode));
varpool_remove_node (vnode);
}
}
#ifdef ENABLE_CHECKING #ifdef ENABLE_CHECKING
verify_cgraph (); verify_cgraph ();
#endif #endif
......
...@@ -291,6 +291,9 @@ lto_varpool_replace_node (struct varpool_node *vnode, ...@@ -291,6 +291,9 @@ lto_varpool_replace_node (struct varpool_node *vnode,
prevailing_node = prevailing_node->extra_name; prevailing_node = prevailing_node->extra_name;
ipa_clone_refering (NULL, prevailing_node, &vnode->ref_list); ipa_clone_refering (NULL, prevailing_node, &vnode->ref_list);
/* Be sure we can garbage collect the initializer. */
if (DECL_INITIAL (vnode->decl))
DECL_INITIAL (vnode->decl) = error_mark_node;
/* Finally remove the replaced node. */ /* Finally remove the replaced node. */
varpool_remove_node (vnode); varpool_remove_node (vnode);
} }
......
...@@ -688,7 +688,7 @@ copy_bind_expr (tree *tp, int *walk_subtrees, copy_body_data *id) ...@@ -688,7 +688,7 @@ copy_bind_expr (tree *tp, int *walk_subtrees, copy_body_data *id)
/* Create a new gimple_seq by remapping all the statements in BODY /* Create a new gimple_seq by remapping all the statements in BODY
using the inlining information in ID. */ using the inlining information in ID. */
gimple_seq static gimple_seq
remap_gimple_seq (gimple_seq body, copy_body_data *id) remap_gimple_seq (gimple_seq body, copy_body_data *id)
{ {
gimple_stmt_iterator si; gimple_stmt_iterator si;
......
...@@ -174,7 +174,6 @@ tree maybe_inline_call_in_expr (tree); ...@@ -174,7 +174,6 @@ tree maybe_inline_call_in_expr (tree);
bool tree_inlinable_function_p (tree); bool tree_inlinable_function_p (tree);
tree copy_tree_r (tree *, int *, void *); tree copy_tree_r (tree *, int *, void *);
tree copy_decl_no_change (tree decl, copy_body_data *id); tree copy_decl_no_change (tree decl, copy_body_data *id);
void save_body (tree, tree *, tree *);
int estimate_move_cost (tree type); int estimate_move_cost (tree type);
int estimate_num_insns (gimple, eni_weights *); int estimate_num_insns (gimple, eni_weights *);
int estimate_num_insns_fn (tree, eni_weights *); int estimate_num_insns_fn (tree, eni_weights *);
...@@ -182,7 +181,6 @@ int count_insns_seq (gimple_seq, eni_weights *); ...@@ -182,7 +181,6 @@ int count_insns_seq (gimple_seq, eni_weights *);
bool tree_versionable_function_p (tree); bool tree_versionable_function_p (tree);
bool tree_can_inline_p (struct cgraph_edge *e); bool tree_can_inline_p (struct cgraph_edge *e);
extern gimple_seq remap_gimple_seq (gimple_seq, copy_body_data *);
extern tree remap_decl (tree decl, copy_body_data *id); extern tree remap_decl (tree decl, copy_body_data *id);
extern tree remap_type (tree type, copy_body_data *id); extern tree remap_type (tree type, copy_body_data *id);
extern gimple_seq copy_gimple_seq_and_replace_locals (gimple_seq seq); extern gimple_seq copy_gimple_seq_and_replace_locals (gimple_seq seq);
......
...@@ -5650,6 +5650,7 @@ find_decl_and_mark_needed (tree decl, tree target) ...@@ -5650,6 +5650,7 @@ find_decl_and_mark_needed (tree decl, tree target)
else if (vnode) else if (vnode)
{ {
varpool_mark_needed_node (vnode); varpool_mark_needed_node (vnode);
vnode->force_output = 1;
return vnode->decl; return vnode->decl;
} }
else else
......
...@@ -196,8 +196,6 @@ varpool_remove_node (struct varpool_node *node) ...@@ -196,8 +196,6 @@ varpool_remove_node (struct varpool_node *node)
} }
ipa_remove_all_references (&node->ref_list); ipa_remove_all_references (&node->ref_list);
ipa_remove_all_refering (&node->ref_list); ipa_remove_all_refering (&node->ref_list);
if (DECL_INITIAL (node->decl))
DECL_INITIAL (node->decl) = error_mark_node;
ggc_free (node); ggc_free (node);
} }
...@@ -302,7 +300,7 @@ varpool_mark_needed_node (struct varpool_node *node) ...@@ -302,7 +300,7 @@ varpool_mark_needed_node (struct varpool_node *node)
} }
/* Reset the queue of needed nodes. */ /* Reset the queue of needed nodes. */
static void void
varpool_reset_queue (void) varpool_reset_queue (void)
{ {
varpool_last_needed_node = NULL; varpool_last_needed_node = NULL;
...@@ -383,6 +381,8 @@ varpool_finalize_decl (tree decl) ...@@ -383,6 +381,8 @@ varpool_finalize_decl (tree decl)
if (node->needed) if (node->needed)
varpool_enqueue_needed_node (node); varpool_enqueue_needed_node (node);
node->finalized = true; node->finalized = true;
if (TREE_THIS_VOLATILE (decl))
node->force_output = true;
if (decide_is_variable_needed (node, decl)) if (decide_is_variable_needed (node, decl))
varpool_mark_needed_node (node); varpool_mark_needed_node (node);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment