summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog23
-rw-r--r--gcc/cgraph.c4
-rw-r--r--gcc/cgraph.h21
-rw-r--r--gcc/cgraphunit.c6
-rw-r--r--gcc/function.h5
-rw-r--r--gcc/ipa.c53
-rw-r--r--gcc/lto-streamer-in.c9
-rw-r--r--gcc/lto/ChangeLog4
-rw-r--r--gcc/lto/lto.c16
-rw-r--r--gcc/passes.c32
-rw-r--r--gcc/tree-inline.c26
11 files changed, 140 insertions, 59 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0ee4395b163..9796fa09ce9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 167e8a8e7b4..840cf297bb5 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -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.
*/
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 46fee67e6e3..33eb821dd5d 100644
--- a/gcc/cgraph.h
+++ b/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;
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 377e4353fdb..1c13f955cfa 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -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);
}
diff --git a/gcc/function.h b/gcc/function.h
index 4825d16cf7f..ad203ba195e 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -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. */
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 6234e662e5e..4d52ed404f3 100644
--- a/gcc/ipa.c
+++ b/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;
-
- 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;
- }
+ node->aux = processed;
+
+ 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);
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index 59784a42f63..dcc92fde13d 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -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
diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog
index 6cb9ff43732..963319980a0 100644
--- a/gcc/lto/ChangeLog
+++ b/gcc/lto/ChangeLog
@@ -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.
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 323f6b34006..40f3c30fb64 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -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);
diff --git a/gcc/passes.c b/gcc/passes.c
index fb0dd832708..e92d0860bd9 100644
--- a/gcc/passes.c
+++ b/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 ();
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index f0ed4ba73a7..629ccfb524f 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -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