From 0e3776dbeef569670b356754e9c38bcc9474a090 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Mon, 16 Nov 2009 14:26:40 +0100 Subject: [PATCH] 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 --- gcc/ChangeLog | 23 +++++++++++++++++++ gcc/cgraph.c | 4 +++- gcc/cgraph.h | 21 ++++++++++++++---- gcc/cgraphunit.c | 6 +++-- gcc/function.h | 5 ----- gcc/ipa.c | 51 ++++++++++++++++++++++++++++++++----------- gcc/lto-streamer-in.c | 9 -------- gcc/lto/ChangeLog | 4 ++++ gcc/lto/lto.c | 16 +++++++++++--- gcc/passes.c | 32 +++++++++++++-------------- gcc/tree-inline.c | 26 +++++++++++++++++----- 11 files changed, 139 insertions(+), 58 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 + + * 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 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; + 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); 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 + + * lto.c (read_cgraph_and_symbols): Set also ipa_transforms_to_apply. + 2009-11-12 Rafael Avila de Espindola * 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