+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
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));
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.
*/
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;
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;
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);
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);
}
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. */
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;
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
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;
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
{
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);
/* 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
+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.
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);
& ~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
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;
}
}
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 ();
/* 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,
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;
(*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;
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