From 17653c00b9d77f94272588e58400de197005b3a6 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Thu, 1 May 2008 18:08:15 +0200 Subject: [PATCH] tree-pass.h (opt_pass): Add IPA_PASS. * tree-pass.h (opt_pass): Add IPA_PASS. (varpool_node, cgraph_node): Forward declare. (ipa_opt_pass): Define. (pass_ipa_inline): Turn into ipa_opt_pass. (pass_apply_inline): Remove. * ipa-inline.c (pass_ipa_inline): Turn into ipa_opt_pass. (apply_inline): Turn into .... (inline_transform): ... this one. (inline_generate_summary): New function. (pass_apply_inline): Remove. * function.h (ipa_opt_pass): Forward declare structure; typedef; vector. (struct function): Add ipa_transforms_to_apply. * passes.c (register_one_dump_file): Work on IPA_PASS. (init_optimization_passes): Remove pass_inline_parameters and pass_apply_inline. (pass_init_dump_file, pass_fini_dump_file): Break out from .... (execute_one_pass) ... here; apply transforms when possible. (add_ipa_transform_pass, execute_ipa_summary_asses, execute_one_ipa_transform_pass): New. (execute_ipa_pass_list): Update for IPA_PASS type. From-SVN: r134859 --- gcc/ChangeLog | 24 ++++++ gcc/function.h | 9 +++ gcc/ipa-inline.c | 62 +++++++-------- gcc/passes.c | 203 +++++++++++++++++++++++++++++++++++++---------- gcc/tree-pass.h | 40 ++++++++-- 5 files changed, 259 insertions(+), 79 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 525bdd313f7..fe9d9c4cb23 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2008-05-01 Jan Hubicka + + * tree-pass.h (opt_pass): Add IPA_PASS. + (varpool_node, cgraph_node): Forward declare. + (ipa_opt_pass): Define. + (pass_ipa_inline): Turn into ipa_opt_pass. + (pass_apply_inline): Remove. + * ipa-inline.c (pass_ipa_inline): Turn into ipa_opt_pass. + (apply_inline): Turn into .... + (inline_transform): ... this one. + (inline_generate_summary): New function. + (pass_apply_inline): Remove. + * function.h (ipa_opt_pass): Forward declare structure; typedef; + vector. + (struct function): Add ipa_transforms_to_apply. + * passes.c (register_one_dump_file): Work on IPA_PASS. + (init_optimization_passes): Remove pass_inline_parameters and + pass_apply_inline. + (pass_init_dump_file, pass_fini_dump_file): Break out from .... + (execute_one_pass) ... here; apply transforms when possible. + (add_ipa_transform_pass, execute_ipa_summary_asses, + execute_one_ipa_transform_pass): New. + (execute_ipa_pass_list): Update for IPA_PASS type. + 2008-05-01 H.J. Lu * config/i386/i386.c (ix86_builtin_type): Add diff --git a/gcc/function.h b/gcc/function.h index 2e88f97ad7f..fcfd3b65f43 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -179,6 +179,11 @@ struct call_site_record; DEF_VEC_P(temp_slot_p); DEF_VEC_ALLOC_P(temp_slot_p,gc); +struct ipa_opt_pass; +typedef struct ipa_opt_pass *ipa_opt_pass; + +DEF_VEC_P(ipa_opt_pass); +DEF_VEC_ALLOC_P(ipa_opt_pass,heap); enum function_frequency { /* This function most likely won't be executed at all. @@ -466,6 +471,10 @@ struct function GTY(()) /* Properties used by the pass manager. */ 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; /* Collected bit flags. */ diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index f251fbebe30..f0a7819cacf 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -1426,26 +1426,6 @@ cgraph_gate_inlining (void) return flag_inline_trees; } -struct simple_ipa_opt_pass pass_ipa_inline = -{ - { - SIMPLE_IPA_PASS, - "inline", /* name */ - cgraph_gate_inlining, /* gate */ - cgraph_decide_inlining, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_INLINE_HEURISTICS, /* tv_id */ - 0, /* properties_required */ - PROP_cfg, /* properties_provided */ - 0, /* properties_destroyed */ - TODO_remove_functions, /* todo_flags_finish */ - TODO_dump_cgraph | TODO_dump_func - | TODO_remove_functions /* todo_flags_finish */ - } -}; - /* Because inlining might remove no-longer reachable nodes, we need to keep the array visible to garbage collector to avoid reading collected out nodes. */ @@ -1579,13 +1559,20 @@ struct gimple_opt_pass pass_inline_parameters = } }; -/* Apply inline plan to the function. */ -static unsigned int -apply_inline (void) +/* Note function body size. */ +void +inline_generate_summary (struct cgraph_node *node ATTRIBUTE_UNUSED) +{ + compute_inline_parameters (); + return; +} + +/* Apply inline plan to function. */ +int +inline_transform (struct cgraph_node *node) { unsigned int todo = 0; struct cgraph_edge *e; - struct cgraph_node *node = cgraph_node (current_function_decl); /* Even when not optimizing, ensure that always_inline functions get inlined. */ @@ -1617,13 +1604,13 @@ apply_inline (void) return todo | execute_fixup_cfg (); } -struct gimple_opt_pass pass_apply_inline = +struct ipa_opt_pass pass_ipa_inline = { { - GIMPLE_PASS, - "apply_inline", /* name */ - NULL, /* gate */ - apply_inline, /* execute */ + IPA_PASS, + "inline", /* name */ + cgraph_gate_inlining, /* gate */ + cgraph_decide_inlining, /* execute */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ @@ -1631,10 +1618,19 @@ struct gimple_opt_pass pass_apply_inline = 0, /* properties_required */ PROP_cfg, /* properties_provided */ 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_dump_func | TODO_verify_flow - | TODO_verify_stmts /* todo_flags_finish */ - } + TODO_remove_functions, /* todo_flags_finish */ + TODO_dump_cgraph | TODO_dump_func + | TODO_remove_functions /* todo_flags_finish */ + }, + inline_generate_summary, /* function_generate_summary */ + NULL, /* variable_generate_summary */ + NULL, /* function_write_summary */ + NULL, /* variable_write_summary */ + NULL, /* function_read_summary */ + NULL, /* variable_read_summary */ + 0, /* TODOs */ + inline_transform, /* function_transform */ + NULL, /* variable_transform */ }; #include "gt-ipa-inline.h" diff --git a/gcc/passes.c b/gcc/passes.c index 42f456c7f83..196e5a70a71 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -352,7 +352,7 @@ register_one_dump_file (struct opt_pass *pass) ? 1 : pass->static_pass_number)); dot_name = concat (".", pass->name, num, NULL); - if (pass->type == SIMPLE_IPA_PASS) + if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS) prefix = "ipa-", flags = TDF_IPA; else if (pass->type == GIMPLE_PASS) prefix = "tree-", flags = TDF_TREE; @@ -538,7 +538,6 @@ init_optimization_passes (void) NEXT_PASS (pass_release_ssa_names); } NEXT_PASS (pass_rebuild_cgraph_edges); - NEXT_PASS (pass_inline_parameters); } NEXT_PASS (pass_ipa_increase_alignment); NEXT_PASS (pass_ipa_matrix_reorg); @@ -554,7 +553,6 @@ init_optimization_passes (void) /* These passes are run after IPA passes on every function that is being output to the assembler file. */ p = &all_passes; - NEXT_PASS (pass_apply_inline); NEXT_PASS (pass_all_optimizations); { struct opt_pass **p = &pass_all_optimizations.pass.sub; @@ -1054,8 +1052,58 @@ verify_curr_properties (void *data) } #endif +/* Initialize pass dump file. */ + +static bool +pass_init_dump_file (struct opt_pass *pass) +{ + /* If a dump file name is present, open it if enabled. */ + if (pass->static_pass_number != -1) + { + bool initializing_dump = !dump_initialized_p (pass->static_pass_number); + dump_file_name = get_dump_file_name (pass->static_pass_number); + dump_file = dump_begin (pass->static_pass_number, &dump_flags); + if (dump_file && current_function_decl) + { + const char *dname, *aname; + dname = lang_hooks.decl_printable_name (current_function_decl, 2); + aname = (IDENTIFIER_POINTER + (DECL_ASSEMBLER_NAME (current_function_decl))); + fprintf (dump_file, "\n;; Apply transform to function %s (%s)%s\n\n", dname, aname, + cfun->function_frequency == FUNCTION_FREQUENCY_HOT + ? " (hot)" + : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED + ? " (unlikely executed)" + : ""); + } + return initializing_dump; + } + else + return false; +} + +/* Flush PASS dump file. */ + +static void +pass_fini_dump_file (struct opt_pass *pass) +{ + /* Flush and close dump file. */ + if (dump_file_name) + { + free (CONST_CAST (char *, dump_file_name)); + dump_file_name = NULL; + } + + if (dump_file) + { + dump_end (pass->static_pass_number, dump_file); + dump_file = NULL; + } +} + /* After executing the pass, apply expected changes to the function properties. */ + static void update_properties_after_pass (void *data) { @@ -1064,6 +1112,80 @@ 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 *ipa_pass = (struct ipa_opt_pass *) data; + VEC_safe_push (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply, ipa_pass); +} + +/* Execute IPA pass function summary generation. DATA is pointer to + pass list to execute. */ + +static void +execute_ipa_summary_passes (void *data) +{ + struct ipa_opt_pass *ipa_pass = (struct ipa_opt_pass *)data; + struct cgraph_node *node = cgraph_node (cfun->decl); + while (ipa_pass && ipa_pass->pass.type == IPA_PASS) + { + struct opt_pass *pass = &ipa_pass->pass; + if (!pass->gate || pass->gate ()) + { + pass_init_dump_file (pass); + ipa_pass->function_generate_summary (node); + pass_fini_dump_file (pass); + } + ipa_pass = (struct ipa_opt_pass *)ipa_pass->pass.next; + } +} + +/* Execute IPA_PASS function transform on NODE. */ + +static void +execute_one_ipa_transform_pass (struct cgraph_node *node, + struct ipa_opt_pass *ipa_pass) +{ + struct opt_pass *pass = &ipa_pass->pass; + unsigned int todo_after = 0; + + current_pass = pass; + if (!ipa_pass->function_transform) + return; + + /* Note that the folders should only create gimple expressions. + This is a hack until the new folder is ready. */ + in_gimple_form = (cfun && (cfun->curr_properties & PROP_trees)) != 0; + + pass_init_dump_file (pass); + + /* Run pre-pass verification. */ + execute_todo (pass->todo_flags_start); + + /* If a timevar is present, start it. */ + if (pass->tv_id) + timevar_push (pass->tv_id); + + /* Do it! */ + todo_after = ipa_pass->function_transform (node); + + /* Stop timevar. */ + if (pass->tv_id) + timevar_pop (pass->tv_id); + + /* Run post-pass cleanup and verification. */ + execute_todo (todo_after); + verify_interpass_invariants (); + + pass_fini_dump_file (pass); + + current_pass = NULL; + /* Reset in_gimple_form to not break non-unit-at-a-time mode. */ + in_gimple_form = false; +} + static bool execute_one_pass (struct opt_pass *pass) { @@ -1072,11 +1194,26 @@ execute_one_pass (struct opt_pass *pass) /* IPA passes are executed on whole program, so cfun should be NULL. Ohter passes needs function context set. */ - if (pass->type == SIMPLE_IPA_PASS) + if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS) gcc_assert (!cfun && !current_function_decl); else gcc_assert (cfun && current_function_decl); + if (cfun && cfun->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); + i++) + execute_one_ipa_transform_pass (node, + VEC_index (ipa_opt_pass, + cfun->ipa_transforms_to_apply, + i)); + VEC_free (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply); + cfun->ipa_transforms_to_apply = NULL; + } + current_pass = pass; /* See if we're supposed to run this pass. */ if (pass->gate && !pass->gate ()) @@ -1100,28 +1237,7 @@ execute_one_pass (struct opt_pass *pass) (void *)(size_t)pass->properties_required); #endif - /* If a dump file name is present, open it if enabled. */ - if (pass->static_pass_number != -1) - { - initializing_dump = !dump_initialized_p (pass->static_pass_number); - dump_file_name = get_dump_file_name (pass->static_pass_number); - dump_file = dump_begin (pass->static_pass_number, &dump_flags); - if (dump_file && current_function_decl) - { - const char *dname, *aname; - dname = lang_hooks.decl_printable_name (current_function_decl, 2); - aname = (IDENTIFIER_POINTER - (DECL_ASSEMBLER_NAME (current_function_decl))); - fprintf (dump_file, "\n;; Function %s (%s)%s\n\n", dname, aname, - cfun->function_frequency == FUNCTION_FREQUENCY_HOT - ? " (hot)" - : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED - ? " (unlikely executed)" - : ""); - } - } - else - initializing_dump = false; + initializing_dump = pass_init_dump_file (pass); /* If a timevar is present, start it. */ if (pass->tv_id) @@ -1154,24 +1270,15 @@ execute_one_pass (struct opt_pass *pass) /* Run post-pass cleanup and verification. */ execute_todo (todo_after | pass->todo_flags_finish); verify_interpass_invariants (); + if (pass->type == IPA_PASS) + do_per_function (add_ipa_transform_pass, pass); if (!current_function_decl) cgraph_process_new_functions (); - /* Flush and close dump file. */ - if (dump_file_name) - { - free (CONST_CAST (char *, dump_file_name)); - dump_file_name = NULL; - } - - if (dump_file) - { - dump_end (pass->static_pass_number, dump_file); - dump_file = NULL; - } + pass_fini_dump_file (pass); - if (pass->type != SIMPLE_IPA_PASS) + if (pass->type != SIMPLE_IPA_PASS && pass->type != IPA_PASS) gcc_assert (!(cfun->curr_properties & PROP_trees) || pass->type != RTL_PASS); @@ -1201,17 +1308,31 @@ execute_pass_list (struct opt_pass *pass) void execute_ipa_pass_list (struct opt_pass *pass) { + bool summaries_generated = false; do { gcc_assert (!current_function_decl); gcc_assert (!cfun); - gcc_assert (pass->type == SIMPLE_IPA_PASS); + gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS); + if (pass->type == IPA_PASS && (!pass->gate || pass->gate ())) + { + if (!summaries_generated) + { + if (!quiet_flag && !cfun) + fprintf (stderr, " "); + do_per_function_toporder (execute_ipa_summary_passes, pass); + } + summaries_generated = true; + } + else + summaries_generated = false; if (execute_one_pass (pass) && pass->sub) { if (pass->sub->type == GIMPLE_PASS) do_per_function_toporder ((void (*)(void *))execute_pass_list, pass->sub); - else if (pass->sub->type == SIMPLE_IPA_PASS) + else if (pass->sub->type == SIMPLE_IPA_PASS + || pass->sub->type == IPA_PASS) execute_ipa_pass_list (pass->sub); else gcc_unreachable (); diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index f391c52c374..4d16ed697d4 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -96,7 +96,8 @@ struct opt_pass enum opt_pass_type { GIMPLE_PASS, RTL_PASS, - SIMPLE_IPA_PASS + SIMPLE_IPA_PASS, + IPA_PASS } type; /* Terse name of the pass used as a fragment of the dump file name. */ const char *name; @@ -133,7 +134,7 @@ struct opt_pass unsigned int todo_flags_finish; }; -/* Description or GIMPLE pass. */ +/* Description of GIMPLE pass. */ struct gimple_opt_pass { struct opt_pass pass; @@ -145,7 +146,36 @@ struct rtl_opt_pass struct opt_pass pass; }; -/* Description if simple IPA pass. Simple IPA passes have just one execute +struct varpool_node; +struct cgraph_node; + +/* Description of IPA pass with generate summary, write, execute, read and + transform stages. */ +struct ipa_opt_pass +{ + struct opt_pass pass; + + /* IPA passes can analyze function body and variable initializers using this + hook and produce summary. */ + void (*function_generate_summary) (struct cgraph_node *); + void (*variable_generate_summary) (struct varpool_node *); + + /* These hooks will be used to serialize IPA summaries on disk. For a moment + they are just placeholders. */ + void (*function_write_summary) (struct cgraph_node *); + void (*variable_write_summary) (struct varpool_node *); + void (*function_read_summary) (struct cgraph_node *); + void (*variable_read_summary) (struct varpool_node *); + + /* Results of interprocedural propagation of an IPA pass is applied to + function body via this hook. */ + unsigned int function_transform_todo_flags_start; + unsigned int (*function_transform) (struct cgraph_node *); + void (*variable_transform) (struct varpool_node *); + +}; + +/* Description of simple IPA pass. Simple IPA passes have just one execute hook. */ struct simple_ipa_opt_pass { @@ -353,9 +383,10 @@ extern struct gimple_opt_pass pass_build_cgraph_edges; extern struct gimple_opt_pass pass_reset_cc_flags; /* IPA Passes */ +extern struct ipa_opt_pass pass_ipa_inline; + extern struct simple_ipa_opt_pass pass_ipa_matrix_reorg; extern struct simple_ipa_opt_pass pass_ipa_cp; -extern struct simple_ipa_opt_pass pass_ipa_inline; extern struct simple_ipa_opt_pass pass_ipa_early_inline; extern struct simple_ipa_opt_pass pass_ipa_reference; extern struct simple_ipa_opt_pass pass_ipa_pure_const; @@ -471,7 +502,6 @@ extern struct rtl_opt_pass pass_rtl_seqabstr; extern struct gimple_opt_pass pass_release_ssa_names; extern struct gimple_opt_pass pass_early_inline; extern struct gimple_opt_pass pass_inline_parameters; -extern struct gimple_opt_pass pass_apply_inline; extern struct gimple_opt_pass pass_all_early_optimizations; extern struct gimple_opt_pass pass_update_address_taken; -- 2.30.2