cgraph.c (cgraph_release_function_body): Update use of ipa_transforms_to_apply.

* cgraph.c (cgraph_release_function_body): Update use of
	ipa_transforms_to_apply.
	(cgraph_remove_node): Remove ipa_transforms_to_apply.
	* cgraph.h (struct cgraph_node): Add ipa_transforms_to_apply.
	* cgraphunit.c (save_inline_function_body): Clear ipa_transforms for
	copied body.
	(cgraph_materialize_clone): Remove original if dead.
	* lto-streamer-in.c (lto_read_body): Remove FIXME and
	ipa_transforms_to_apply hack.
	* function.h (struct function): Add ipa_transforms_to_apply.
	* ipa.c (cgraph_remove_unreachable_nodes): Handle dead clone originals.
	* tree-inline.c (copy_bb): Update sanity check.
	(initialize_cfun): Do not copy ipa_transforms_to_apply.
	(expand_call_inline): remove dead clone originals.
	(tree_function_versioning): Merge transformation queues.
	* passes.c (add_ipa_transform_pass): Remove.
	(execute_one_ipa_transform_pass): Update ipa_transforms_to_apply
	tracking.
	(execute_all_ipa_transforms): Update.
	(execute_one_pass): Update.

	* lto.c (read_cgraph_and_symbols): Set also ipa_transforms_to_apply.

From-SVN: r154200
This commit is contained in:
Jan Hubicka 2009-11-16 14:26:40 +01:00 committed by Jan Hubicka
parent 0229b692f4
commit 0e3776dbee
11 changed files with 139 additions and 58 deletions

View file

@ -1,3 +1,26 @@
2009-11-14 Jan Hubicka <jh@suse.cz>
* cgraph.c (cgraph_release_function_body): Update use of
ipa_transforms_to_apply.
(cgraph_remove_node): Remove ipa_transforms_to_apply.
* cgraph.h (struct cgraph_node): Add ipa_transforms_to_apply.
* cgraphunit.c (save_inline_function_body): Clear ipa_transforms for
copied body.
(cgraph_materialize_clone): Remove original if dead.
* lto-streamer-in.c (lto_read_body): Remove FIXME and
ipa_transforms_to_apply hack.
* function.h (struct function): Add ipa_transforms_to_apply.
* ipa.c (cgraph_remove_unreachable_nodes): Handle dead clone originals.
* tree-inline.c (copy_bb): Update sanity check.
(initialize_cfun): Do not copy ipa_transforms_to_apply.
(expand_call_inline): remove dead clone originals.
(tree_function_versioning): Merge transformation queues.
* passes.c (add_ipa_transform_pass): Remove.
(execute_one_ipa_transform_pass): Update ipa_transforms_to_apply
tracking.
(execute_all_ipa_transforms): Update.
(execute_one_pass): Update.
2009-11-14 Andy Hutchinson <hutchinsonandy@gcc.gnu.org>
PR target/21078, 21080

View file

@ -1132,7 +1132,7 @@ cgraph_release_function_body (struct cgraph_node *node)
pop_cfun();
gimple_set_body (node->decl, NULL);
VEC_free (ipa_opt_pass, heap,
DECL_STRUCT_FUNCTION (node->decl)->ipa_transforms_to_apply);
node->ipa_transforms_to_apply);
/* Struct function hangs a lot of data that would leak if we didn't
removed all pointers to it. */
ggc_free (DECL_STRUCT_FUNCTION (node->decl));
@ -1159,6 +1159,8 @@ cgraph_remove_node (struct cgraph_node *node)
cgraph_call_node_removal_hooks (node);
cgraph_node_remove_callers (node);
cgraph_node_remove_callees (node);
VEC_free (ipa_opt_pass, heap,
node->ipa_transforms_to_apply);
/* Incremental inlining access removed nodes stored in the postorder list.
*/

View file

@ -190,6 +190,11 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
PTR GTY ((skip)) aux;
/* Interprocedural passes scheduled to have their transform functions
applied next time we execute local pass on them. We maintain it
per-function in order to allow IPA passes to introduce new functions. */
VEC(ipa_opt_pass,heap) * GTY((skip)) ipa_transforms_to_apply;
struct cgraph_local_info local;
struct cgraph_global_info global;
struct cgraph_rtl_info rtl;
@ -206,16 +211,24 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
number of cfg nodes with -fprofile-generate and -fprofile-use */
int pid;
/* Set when function must be output - it is externally visible
or its address is taken. */
/* Set when function must be output for some reason. The primary
use of this flag is to mark functions needed to be output for
non-standard reason. Functions that are externally visible
or reachable from functions needed to be output are marked
by specialized flags. */
unsigned needed : 1;
/* Set when function has address taken. */
/* Set when function has address taken.
In current implementation it imply needed flag. */
unsigned address_taken : 1;
/* Set when decl is an abstract function pointed to by the
ABSTRACT_DECL_ORIGIN of a reachable function. */
unsigned abstract_and_needed : 1;
/* Set when function is reachable by call from other function
that is either reachable or needed. */
that is either reachable or needed.
This flag is computed at original cgraph construction and then
updated in cgraph_remove_unreachable_nodes. Note that after
cgraph_remove_unreachable_nodes cgraph still can contain unreachable
nodes when they are needed for virtual clone instantiation. */
unsigned reachable : 1;
/* Set once the function is lowered (i.e. its CFG is built). */
unsigned lowered : 1;

View file

@ -1777,8 +1777,8 @@ save_inline_function_body (struct cgraph_node *node)
TREE_PUBLIC (first_clone->decl) = 0;
DECL_COMDAT (first_clone->decl) = 0;
VEC_free (ipa_opt_pass, heap,
DECL_STRUCT_FUNCTION (first_clone->decl)->ipa_transforms_to_apply);
DECL_STRUCT_FUNCTION (first_clone->decl)->ipa_transforms_to_apply = NULL;
first_clone->ipa_transforms_to_apply);
first_clone->ipa_transforms_to_apply = NULL;
#ifdef ENABLE_CHECKING
verify_cgraph_node (first_clone);
@ -1810,6 +1810,8 @@ cgraph_materialize_clone (struct cgraph_node *node)
node->clone_of->clones = node->next_sibling_clone;
node->next_sibling_clone = NULL;
node->prev_sibling_clone = NULL;
if (!node->clone_of->analyzed && !node->clone_of->clones)
cgraph_remove_node (node->clone_of);
node->clone_of = NULL;
bitmap_obstack_release (NULL);
}

View file

@ -522,11 +522,6 @@ struct GTY(()) function {
unsigned int curr_properties;
unsigned int last_verified;
/* Interprocedural passes scheduled to have their transform functions
applied next time we execute local pass on them. We maintain it
per-function in order to allow IPA passes to introduce new functions. */
VEC(ipa_opt_pass,heap) * GTY((skip)) ipa_transforms_to_apply;
/* Non-null if the function does something that would prevent it from
being copied; this applies to both versioning and inlining. Set to
a string describing the reason for failure. */

View file

@ -121,6 +121,7 @@ bool
cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
{
struct cgraph_node *first = (struct cgraph_node *) (void *) 1;
struct cgraph_node *processed = (struct cgraph_node *) (void *) 2;
struct cgraph_node *node, *next;
bool changed = false;
@ -142,9 +143,13 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
gcc_assert (!node->global.inlined_to);
node->aux = first;
first = node;
node->reachable = true;
}
else
gcc_assert (!node->aux);
{
gcc_assert (!node->aux);
node->reachable = false;
}
/* Perform reachability analysis. As a special case do not consider
extern inline functions not inlined as live because we won't output
@ -154,17 +159,26 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
struct cgraph_edge *e;
node = first;
first = (struct cgraph_node *) first->aux;
node->aux = processed;
for (e = node->callees; e; e = e->next_callee)
if (!e->callee->aux
&& node->analyzed
&& (!e->inline_failed || !e->callee->analyzed
|| (!DECL_EXTERNAL (e->callee->decl))
|| before_inlining_p))
{
e->callee->aux = first;
first = e->callee;
}
if (node->reachable)
for (e = node->callees; e; e = e->next_callee)
if (!e->callee->reachable
&& node->analyzed
&& (!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;
}
}
while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
{
node = node->clone_of;
@ -184,13 +198,18 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
for (node = cgraph_nodes; node; node = next)
{
next = node->next;
if (node->aux && !node->reachable)
{
cgraph_node_remove_callees (node);
node->analyzed = false;
node->local.inlinable = false;
}
if (!node->aux)
{
node->global.inlined_to = NULL;
if (file)
fprintf (file, " %s", cgraph_node_name (node));
if (!node->analyzed || !DECL_EXTERNAL (node->decl)
|| before_inlining_p)
if (!node->analyzed || !DECL_EXTERNAL (node->decl) || before_inlining_p)
cgraph_remove_node (node);
else
{
@ -219,6 +238,12 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
node->analyzed = false;
node->local.inlinable = false;
}
if (node->prev_sibling_clone)
node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
else if (node->clone_of)
node->clone_of->clones = node->next_sibling_clone;
if (node->next_sibling_clone)
node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
}
else
cgraph_remove_node (node);

View file

@ -1476,15 +1476,6 @@ lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl,
/* Restore decl state */
file_data->current_decl_state = file_data->global_decl_state;
/* FIXME: ipa_transforms_to_apply holds list of passes that have optimization
summaries computed and needs to apply changes. At the moment WHOPR only
supports inlining, so we can push it here by hand. In future we need to stream
this field into ltrans compilation. This will also need to move the field
from struct function into cgraph node where it belongs. */
if (flag_ltrans && !cgraph_node (fn_decl)->global.inlined_to)
VEC_safe_push (ipa_opt_pass, heap,
cfun->ipa_transforms_to_apply,
(ipa_opt_pass)&pass_ipa_inline);
pop_cfun ();
}
else

View file

@ -1,3 +1,7 @@
2009-11-14 Jan Hubicka <jh@suse.cz>
* lto.c (read_cgraph_and_symbols): Set also ipa_transforms_to_apply.
2009-11-12 Rafael Avila de Espindola <espindola@google.com>
* lang.opt (fresolution): Renamed from resolution.

View file

@ -1826,9 +1826,19 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
phase. */
if (flag_ltrans)
for (node = cgraph_nodes; node; node = node->next)
if (!node->global.inlined_to
&& cgraph_decide_is_function_needed (node, node->decl))
cgraph_mark_needed_node (node);
{
if (!node->global.inlined_to
&& cgraph_decide_is_function_needed (node, node->decl))
cgraph_mark_needed_node (node);
/* FIXME: ipa_transforms_to_apply holds list of passes that have optimization
summaries computed and needs to apply changes. At the moment WHOPR only
supports inlining, so we can push it here by hand. In future we need to stream
this field into ltrans compilation. */
if (node->analyzed)
VEC_safe_push (ipa_opt_pass, heap,
node->ipa_transforms_to_apply,
(ipa_opt_pass)&pass_ipa_inline);
}
timevar_push (TV_IPA_LTO_DECL_IO);

View file

@ -1376,15 +1376,6 @@ update_properties_after_pass (void *data)
& ~pass->properties_destroyed;
}
/* Schedule IPA transform pass DATA for CFUN. */
static void
add_ipa_transform_pass (void *data)
{
struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *) data;
VEC_safe_push (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply, ipa_pass);
}
/* Execute summary generation for all of the passes in IPA_PASS. */
void
@ -1464,19 +1455,22 @@ execute_one_ipa_transform_pass (struct cgraph_node *node,
void
execute_all_ipa_transforms (void)
{
if (cfun && cfun->ipa_transforms_to_apply)
struct cgraph_node *node;
if (!cfun)
return;
node = cgraph_node (current_function_decl);
if (node->ipa_transforms_to_apply)
{
unsigned int i;
struct cgraph_node *node = cgraph_node (current_function_decl);
for (i = 0; i < VEC_length (ipa_opt_pass, cfun->ipa_transforms_to_apply);
for (i = 0; i < VEC_length (ipa_opt_pass, node->ipa_transforms_to_apply);
i++)
execute_one_ipa_transform_pass (node,
VEC_index (ipa_opt_pass,
cfun->ipa_transforms_to_apply,
node->ipa_transforms_to_apply,
i));
VEC_free (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply);
cfun->ipa_transforms_to_apply = NULL;
VEC_free (ipa_opt_pass, heap, node->ipa_transforms_to_apply);
node->ipa_transforms_to_apply = NULL;
}
}
@ -1551,7 +1545,13 @@ execute_one_pass (struct opt_pass *pass)
execute_todo (todo_after | pass->todo_flags_finish);
verify_interpass_invariants ();
if (pass->type == IPA_PASS)
do_per_function (add_ipa_transform_pass, pass);
{
struct cgraph_node *node;
for (node = cgraph_nodes; node; node = node->next)
if (node->analyzed)
VEC_safe_push (ipa_opt_pass, heap, node->ipa_transforms_to_apply,
(struct ipa_opt_pass_d *)pass);
}
if (!current_function_decl)
cgraph_process_new_functions ();

View file

@ -1665,10 +1665,12 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
/* We have missing edge in the callgraph. This can happen
when previous inlining turned an indirect call into a
direct call by constant propagating arguments. In all
direct call by constant propagating arguments or we are
producing dead clone (for further clonning). In all
other cases we hit a bug (incorrect node sharing is the
most common reason for missing edges). */
gcc_assert (dest->needed || !dest->analyzed);
gcc_assert (dest->needed || !dest->analyzed
|| !id->src_node->analyzed);
if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES)
cgraph_create_edge_including_clones
(id->dst_node, dest, stmt, bb->count,
@ -1983,9 +1985,6 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
cfun->function_end_locus = src_cfun->function_end_locus;
cfun->curr_properties = src_cfun->curr_properties;
cfun->last_verified = src_cfun->last_verified;
if (src_cfun->ipa_transforms_to_apply)
cfun->ipa_transforms_to_apply = VEC_copy (ipa_opt_pass, heap,
src_cfun->ipa_transforms_to_apply);
cfun->va_list_gpr_size = src_cfun->va_list_gpr_size;
cfun->va_list_fpr_size = src_cfun->va_list_fpr_size;
cfun->function_frequency = src_cfun->function_frequency;
@ -3822,6 +3821,10 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
(*debug_hooks->outlining_inline_function) (cg_edge->callee->decl);
/* Update callgraph if needed. */
if (cg_edge->callee->clone_of
&& !cg_edge->callee->clone_of->next_sibling_clone
&& !cg_edge->callee->analyzed)
cgraph_remove_node (cg_edge->callee);
cgraph_remove_node (cg_edge->callee);
id->block = NULL_TREE;
@ -4848,6 +4851,19 @@ tree_function_versioning (tree old_decl, tree new_decl,
id.src_node = old_version_node;
id.dst_node = new_version_node;
id.src_cfun = DECL_STRUCT_FUNCTION (old_decl);
if (id.src_node->ipa_transforms_to_apply)
{
VEC(ipa_opt_pass,heap) * old_transforms_to_apply = id.dst_node->ipa_transforms_to_apply;
unsigned int i;
id.dst_node->ipa_transforms_to_apply = VEC_copy (ipa_opt_pass, heap,
id.src_node->ipa_transforms_to_apply);
for (i = 0; i < VEC_length (ipa_opt_pass, old_transforms_to_apply); i++)
VEC_safe_push (ipa_opt_pass, heap, id.dst_node->ipa_transforms_to_apply,
VEC_index (ipa_opt_pass,
old_transforms_to_apply,
i));
}
id.copy_decl = copy_decl_no_change;
id.transform_call_graph_edges