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:
parent
0229b692f4
commit
0e3776dbee
11 changed files with 139 additions and 58 deletions
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
21
gcc/cgraph.h
21
gcc/cgraph.h
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
|
51
gcc/ipa.c
51
gcc/ipa.c
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
32
gcc/passes.c
32
gcc/passes.c
|
@ -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 ();
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue