diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cgraph.c | 15 | ||||
-rw-r--r-- | gcc/cgraph.h | 13 | ||||
-rw-r--r-- | gcc/cgraphclones.c | 137 | ||||
-rw-r--r-- | gcc/cgraphunit.c | 10 | ||||
-rw-r--r-- | gcc/ipa-inline-transform.c | 16 | ||||
-rw-r--r-- | gcc/ipa-param-manipulation.c | 7 | ||||
-rw-r--r-- | gcc/ipa.c | 40 | ||||
-rw-r--r-- | gcc/passes.c | 8 | ||||
-rw-r--r-- | gcc/passes.def | 1 | ||||
-rw-r--r-- | gcc/tree-pass.h | 2 | ||||
-rw-r--r-- | gcc/tree-ssa-structalias.c | 4 |
11 files changed, 94 insertions, 159 deletions
diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 9480935..067984d 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -3872,16 +3872,27 @@ cgraph_node::function_or_virtual_thunk_symbol } /* When doing LTO, read cgraph_node's body from disk if it is not already - present. */ + present. Also perform any necessary clone materializations. */ bool -cgraph_node::get_untransformed_body (void) +cgraph_node::get_untransformed_body () { lto_file_decl_data *file_data; const char *data, *name; size_t len; tree decl = this->decl; + /* See if there is clone to be materialized. + (inline clones does not need materialization, but we can be seeing + an inline clone of real clone). */ + cgraph_node *p = this; + for (cgraph_node *c = clone_of; c; c = c->clone_of) + { + if (c->decl != decl) + p->materialize_clone (); + p = c; + } + /* Check if body is already there. Either we have gimple body or the function is thunk and in that case we set DECL_ARGUMENTS. */ if (DECL_ARGUMENTS (decl) || gimple_has_body_p (decl)) diff --git a/gcc/cgraph.h b/gcc/cgraph.h index c953a1b..6c45034 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -1145,12 +1145,14 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node /* When doing LTO, read cgraph_node's body from disk if it is not already present. */ - bool get_untransformed_body (void); + bool get_untransformed_body (); /* Prepare function body. When doing LTO, read cgraph_node's body from disk if it is not already present. When some IPA transformations are scheduled, apply them. */ - bool get_body (void); + bool get_body (); + + void materialize_clone (void); /* Release memory used to represent body of function. Use this only for functions that are released before being translated to @@ -2286,13 +2288,6 @@ public: functions inserted into callgraph already at construction time. */ void process_new_functions (void); - /* Once all functions from compilation unit are in memory, produce all clones - and update all calls. We might also do this on demand if we don't want to - bring all functions to memory prior compilation, but current WHOPR - implementation does that and it is bit easier to keep everything right - in this order. */ - void materialize_all_clones (void); - /* Register a symbol NODE. */ inline void register_symbol (symtab_node *node); diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c index f920dcb..07a51a5 100644 --- a/gcc/cgraphclones.c +++ b/gcc/cgraphclones.c @@ -1083,114 +1083,57 @@ void cgraph_node::remove_from_clone_tree () /* Given virtual clone, turn it into actual clone. */ -static void -cgraph_materialize_clone (cgraph_node *node) -{ - bitmap_obstack_initialize (NULL); - node->former_clone_of = node->clone_of->decl; - if (node->clone_of->former_clone_of) - node->former_clone_of = node->clone_of->former_clone_of; - /* Copy the OLD_VERSION_NODE function tree to the new version. */ - tree_function_versioning (node->clone_of->decl, node->decl, - node->clone.tree_map, node->clone.param_adjustments, - true, NULL, NULL); - if (symtab->dump_file) - { - dump_function_to_file (node->clone_of->decl, symtab->dump_file, - dump_flags); - dump_function_to_file (node->decl, symtab->dump_file, dump_flags); - } - - cgraph_node *clone_of = node->clone_of; - /* Function is no longer clone. */ - node->remove_from_clone_tree (); - if (!clone_of->analyzed && !clone_of->clones) - { - clone_of->release_body (); - clone_of->remove_callees (); - clone_of->remove_all_references (); - } - bitmap_obstack_release (NULL); -} - -/* Once all functions from compilation unit are in memory, produce all clones - and update all calls. We might also do this on demand if we don't want to - bring all functions to memory prior compilation, but current WHOPR - implementation does that and it is a bit easier to keep everything right in - this order. */ - void -symbol_table::materialize_all_clones (void) +cgraph_node::materialize_clone () { - cgraph_node *node; - bool stabilized = false; - - + clone_of->get_untransformed_body (); + former_clone_of = clone_of->decl; + if (clone_of->former_clone_of) + former_clone_of = clone_of->former_clone_of; if (symtab->dump_file) - fprintf (symtab->dump_file, "Materializing clones\n"); - - cgraph_node::checking_verify_cgraph_nodes (); - - /* We can also do topological order, but number of iterations should be - bounded by number of IPA passes since single IPA pass is probably not - going to create clones of clones it created itself. */ - while (!stabilized) { - stabilized = true; - FOR_EACH_FUNCTION (node) + fprintf (symtab->dump_file, "cloning %s to %s\n", + clone_of->dump_name (), + dump_name ()); + if (clone.tree_map) { - if (node->clone_of && node->decl != node->clone_of->decl - && !gimple_has_body_p (node->decl)) + fprintf (symtab->dump_file, " replace map:"); + for (unsigned int i = 0; + i < vec_safe_length (clone.tree_map); + i++) { - if (!node->clone_of->clone_of) - node->clone_of->get_untransformed_body (); - if (gimple_has_body_p (node->clone_of->decl)) - { - if (symtab->dump_file) - { - fprintf (symtab->dump_file, "cloning %s to %s\n", - node->clone_of->dump_name (), - node->dump_name ()); - if (node->clone.tree_map) - { - unsigned int i; - fprintf (symtab->dump_file, " replace map:"); - for (i = 0; - i < vec_safe_length (node->clone.tree_map); - i++) - { - ipa_replace_map *replace_info; - replace_info = (*node->clone.tree_map)[i]; - fprintf (symtab->dump_file, "%s %i -> ", - i ? "," : "", replace_info->parm_num); - print_generic_expr (symtab->dump_file, - replace_info->new_tree); - } - fprintf (symtab->dump_file, "\n"); - } - if (node->clone.param_adjustments) - node->clone.param_adjustments->dump (symtab->dump_file); - } - cgraph_materialize_clone (node); - stabilized = false; - } + ipa_replace_map *replace_info; + replace_info = (*clone.tree_map)[i]; + fprintf (symtab->dump_file, "%s %i -> ", + i ? "," : "", replace_info->parm_num); + print_generic_expr (symtab->dump_file, + replace_info->new_tree); } + fprintf (symtab->dump_file, "\n"); } + if (clone.param_adjustments) + clone.param_adjustments->dump (symtab->dump_file); } - FOR_EACH_FUNCTION (node) - if (!node->analyzed && node->callees) - { - node->remove_callees (); - node->remove_all_references (); - } - else - node->clear_stmts_in_references (); + /* Copy the OLD_VERSION_NODE function tree to the new version. */ + tree_function_versioning (clone_of->decl, decl, + clone.tree_map, clone.param_adjustments, + true, NULL, NULL); if (symtab->dump_file) - fprintf (symtab->dump_file, "Materialization Call site updates done.\n"); - - cgraph_node::checking_verify_cgraph_nodes (); + { + dump_function_to_file (clone_of->decl, symtab->dump_file, + dump_flags); + dump_function_to_file (decl, symtab->dump_file, dump_flags); + } - symtab->remove_unreachable_nodes (symtab->dump_file); + cgraph_node *this_clone_of = clone_of; + /* Function is no longer clone. */ + remove_from_clone_tree (); + if (!this_clone_of->analyzed && !this_clone_of->clones) + { + this_clone_of->release_body (); + this_clone_of->remove_callees (); + this_clone_of->remove_all_references (); + } } #include "gt-cgraphclones.h" diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 05713c2..1e22627 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -1601,6 +1601,7 @@ mark_functions_to_output (void) FOR_EACH_FUNCTION (node) { tree decl = node->decl; + node->clear_stmts_in_references (); gcc_assert (!node->process || node->same_comdat_group); if (node->process) @@ -2274,6 +2275,9 @@ cgraph_node::expand (void) announce_function (decl); process = 0; gcc_assert (lowered); + + /* Initialize the default bitmap obstack. */ + bitmap_obstack_initialize (NULL); get_untransformed_body (); /* Generate RTL for the body of DECL. */ @@ -2282,9 +2286,6 @@ cgraph_node::expand (void) gcc_assert (symtab->global_info_ready); - /* Initialize the default bitmap obstack. */ - bitmap_obstack_initialize (NULL); - /* Initialize the RTL code for the function. */ saved_loc = input_location; input_location = DECL_SOURCE_LOCATION (decl); @@ -2298,7 +2299,8 @@ cgraph_node::expand (void) bitmap_obstack_initialize (®_obstack); /* FIXME, only at RTL generation*/ update_ssa (TODO_update_ssa_only_virtuals); - execute_all_ipa_transforms (false); + if (ipa_transforms_to_apply.exists ()) + execute_all_ipa_transforms (false); /* Perform all tree transforms and optimizations. */ diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c index af2c285..f419df0 100644 --- a/gcc/ipa-inline-transform.c +++ b/gcc/ipa-inline-transform.c @@ -644,16 +644,16 @@ save_inline_function_body (struct cgraph_node *node) tree_function_versioning (node->decl, first_clone->decl, NULL, NULL, true, NULL, NULL); - /* The function will be short lived and removed after we inline all the clones, - but make it internal so we won't confuse ourself. */ + /* The function will be short lived and removed after we inline all the + clones, but make it internal so we won't confuse ourself. */ DECL_EXTERNAL (first_clone->decl) = 0; TREE_PUBLIC (first_clone->decl) = 0; DECL_COMDAT (first_clone->decl) = 0; first_clone->ipa_transforms_to_apply.release (); /* When doing recursive inlining, the clone may become unnecessary. - This is possible i.e. in the case when the recursive function is proved to be - non-throwing and the recursion happens only in the EH landing pad. + This is possible i.e. in the case when the recursive function is proved to + be non-throwing and the recursion happens only in the EH landing pad. We cannot remove the clone until we are done with saving the body. Remove it now. */ if (!first_clone->callers) @@ -696,6 +696,14 @@ inline_transform (struct cgraph_node *node) if (cfun->after_inlining) return 0; + cgraph_node *next_clone; + for (cgraph_node *n = node->clones; n; n = next_clone) + { + next_clone = n->next_sibling_clone; + if (n->decl != node->decl) + n->materialize_clone (); + } + /* We might need the body of this function so that we can expand it inline somewhere else. */ if (preserve_function_body_p (node)) diff --git a/gcc/ipa-param-manipulation.c b/gcc/ipa-param-manipulation.c index 5fc0de5..438f4bd 100644 --- a/gcc/ipa-param-manipulation.c +++ b/gcc/ipa-param-manipulation.c @@ -783,6 +783,13 @@ ipa_param_adjustments::modify_call (gcall *stmt, { vec<tree, va_gc> **debug_args = NULL; unsigned i = 0; + cgraph_node *callee_node = cgraph_node::get (callee_decl); + + /* FIXME: we don't seem to be able to insert debug args before clone + is materialized. Materializing them early leads to extra memory + use. */ + if (callee_node->clone_of) + callee_node->get_untransformed_body (); for (tree old_parm = DECL_ARGUMENTS (old_decl); old_parm && i < old_nargs && ((int) i) < m_always_copy_start; old_parm = DECL_CHAIN (old_parm), i++) @@ -1386,43 +1386,3 @@ make_pass_ipa_single_use (gcc::context *ctxt) return new pass_ipa_single_use (ctxt); } -/* Materialize all clones. */ - -namespace { - -const pass_data pass_data_materialize_all_clones = -{ - SIMPLE_IPA_PASS, /* type */ - "materialize-all-clones", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - TV_IPA_OPT, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ -}; - -class pass_materialize_all_clones : public simple_ipa_opt_pass -{ -public: - pass_materialize_all_clones (gcc::context *ctxt) - : simple_ipa_opt_pass (pass_data_materialize_all_clones, ctxt) - {} - - /* opt_pass methods: */ - virtual unsigned int execute (function *) - { - symtab->materialize_all_clones (); - return 0; - } - -}; // class pass_materialize_all_clones - -} // anon namespace - -simple_ipa_opt_pass * -make_pass_materialize_all_clones (gcc::context *ctxt) -{ - return new pass_materialize_all_clones (ctxt); -} diff --git a/gcc/passes.c b/gcc/passes.c index 6ff31ec..1942b7c 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -2271,6 +2271,14 @@ execute_all_ipa_transforms (bool do_not_collect) return; node = cgraph_node::get (current_function_decl); + cgraph_node *next_clone; + for (cgraph_node *n = node->clones; n; n = next_clone) + { + next_clone = n->next_sibling_clone; + if (n->decl != node->decl) + n->materialize_clone (); + } + if (node->ipa_transforms_to_apply.exists ()) { unsigned int i; diff --git a/gcc/passes.def b/gcc/passes.def index f865bdc..cf15d8e 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -172,7 +172,6 @@ along with GCC; see the file COPYING3. If not see passes are executed after partitioning and thus see just parts of the compiled unit. */ INSERT_PASSES_AFTER (all_late_ipa_passes) - NEXT_PASS (pass_materialize_all_clones); NEXT_PASS (pass_ipa_pta); NEXT_PASS (pass_omp_simd_clone); TERMINATE_PASS_LIST (all_late_ipa_passes) diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 62e5b69..1e8badf 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -519,8 +519,6 @@ extern ipa_opt_pass_d *make_pass_ipa_cdtor_merge (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_single_use (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_comdats (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_modref (gcc::context *ctxt); -extern simple_ipa_opt_pass *make_pass_materialize_all_clones (gcc::context * - ctxt); extern gimple_opt_pass *make_pass_cleanup_cfg_post_optimizing (gcc::context *ctxt); diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index 30a8c93..ac29365 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -8138,6 +8138,10 @@ ipa_pta_execute (void) from = constraints.length (); } + /* FIXME: Clone materialization is not preserving stmt references. */ + FOR_EACH_DEFINED_FUNCTION (node) + node->clear_stmts_in_references (); + /* Build the constraints. */ FOR_EACH_DEFINED_FUNCTION (node) { |