diff options
Diffstat (limited to 'gcc/tree-optimize.c')
-rw-r--r-- | gcc/tree-optimize.c | 513 |
1 files changed, 9 insertions, 504 deletions
diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c index b8a50c7596c..4b23a82fbf0 100644 --- a/gcc/tree-optimize.c +++ b/gcc/tree-optimize.c @@ -50,12 +50,6 @@ Boston, MA 02110-1301, USA. */ #include "cfgloop.h" #include "except.h" -/* Global variables used to communicate with passes. */ -int dump_flags; -bool in_gimple_form; - -/* The root of the compilation pass tree, once constructed. */ -static struct tree_opt_pass *all_passes, *all_ipa_passes, *all_lowering_passes; /* Gate: execute, or not, all of the non-trivial optimizations. */ @@ -67,7 +61,7 @@ gate_all_optimizations (void) && !(errorcount || sorrycount)); } -static struct tree_opt_pass pass_all_optimizations = +struct tree_opt_pass pass_all_optimizations = { NULL, /* name */ gate_all_optimizations, /* gate */ @@ -84,7 +78,7 @@ static struct tree_opt_pass pass_all_optimizations = 0 /* letter */ }; -static struct tree_opt_pass pass_early_local_passes = +struct tree_opt_pass pass_early_local_passes = { NULL, /* name */ gate_all_optimizations, /* gate */ @@ -112,7 +106,7 @@ execute_cleanup_cfg_pre_ipa (void) cleanup_tree_cfg (); } -static struct tree_opt_pass pass_cleanup_cfg = +struct tree_opt_pass pass_cleanup_cfg = { "cleanup_cfg", /* name */ NULL, /* gate */ @@ -143,7 +137,7 @@ execute_cleanup_cfg_post_optimizing (void) group_case_labels (); } -static struct tree_opt_pass pass_cleanup_cfg_post_optimizing = +struct tree_opt_pass pass_cleanup_cfg_post_optimizing = { "final_cleanup", /* name */ NULL, /* gate */ @@ -176,7 +170,7 @@ execute_free_datastructures (void) delete_tree_ssa (); } -static struct tree_opt_pass pass_free_datastructures = +struct tree_opt_pass pass_free_datastructures = { NULL, /* name */ NULL, /* gate */ @@ -216,7 +210,7 @@ execute_free_cfg_annotations (void) delete_tree_cfg_annotations (); } -static struct tree_opt_pass pass_free_cfg_annotations = +struct tree_opt_pass pass_free_cfg_annotations = { NULL, /* name */ NULL, /* gate */ @@ -261,7 +255,7 @@ execute_fixup_cfg (void) cleanup_tree_cfg (); } -static struct tree_opt_pass pass_fixup_cfg = +struct tree_opt_pass pass_fixup_cfg = { NULL, /* name */ NULL, /* gate */ @@ -288,7 +282,7 @@ execute_init_datastructures (void) init_tree_ssa (); } -static struct tree_opt_pass pass_init_datastructures = +struct tree_opt_pass pass_init_datastructures = { NULL, /* name */ NULL, /* gate */ @@ -305,484 +299,7 @@ static struct tree_opt_pass pass_init_datastructures = 0 /* letter */ }; -/* Iterate over the pass tree allocating dump file numbers. We want - to do this depth first, and independent of whether the pass is - enabled or not. */ - -static void -register_one_dump_file (struct tree_opt_pass *pass, bool ipa, int n) -{ - char *dot_name, *flag_name, *glob_name; - char num[10]; - - /* See below in next_pass_1. */ - num[0] = '\0'; - if (pass->static_pass_number != -1) - sprintf (num, "%d", ((int) pass->static_pass_number < 0 - ? 1 : pass->static_pass_number)); - - dot_name = concat (".", pass->name, num, NULL); - if (ipa) - { - flag_name = concat ("ipa-", pass->name, num, NULL); - glob_name = concat ("ipa-", pass->name, NULL); - /* First IPA dump is cgraph that is dumped via separate channels. */ - pass->static_pass_number = dump_register (dot_name, flag_name, glob_name, - TDF_IPA, n + 1, 0); - } - else if (pass->properties_provided & PROP_trees) - { - flag_name = concat ("tree-", pass->name, num, NULL); - glob_name = concat ("tree-", pass->name, NULL); - pass->static_pass_number = dump_register (dot_name, flag_name, glob_name, - TDF_TREE, n + TDI_tree_all, 0); - } - else - { - flag_name = concat ("rtl-", pass->name, num, NULL); - glob_name = concat ("rtl-", pass->name, NULL); - pass->static_pass_number = dump_register (dot_name, flag_name, glob_name, - TDF_RTL, n, pass->letter); - } -} - -static int -register_dump_files (struct tree_opt_pass *pass, bool ipa, int properties) -{ - static int n = 0; - do - { - int new_properties; - int pass_number; - - pass->properties_required = properties; - new_properties = - (properties | pass->properties_provided) & ~pass->properties_destroyed; - - /* Reset the counter when we reach RTL-based passes. */ - if ((pass->properties_provided ^ pass->properties_required) & PROP_rtl) - n = 0; - - pass_number = n; - if (pass->name) - n++; - - if (pass->sub) - new_properties = register_dump_files (pass->sub, false, new_properties); - - /* If we have a gate, combine the properties that we could have with - and without the pass being examined. */ - if (pass->gate) - properties &= new_properties; - else - properties = new_properties; - - pass->properties_provided = properties; - if (pass->name) - register_one_dump_file (pass, ipa, pass_number); - - pass = pass->next; - } - while (pass); - - return properties; -} - -/* Add a pass to the pass list. Duplicate the pass if it's already - in the list. */ - -static struct tree_opt_pass ** -next_pass_1 (struct tree_opt_pass **list, struct tree_opt_pass *pass) -{ - - /* A nonzero static_pass_number indicates that the - pass is already in the list. */ - if (pass->static_pass_number) - { - struct tree_opt_pass *new; - - new = xmalloc (sizeof (*new)); - memcpy (new, pass, sizeof (*new)); - - /* Indicate to register_dump_files that this pass has duplicates, - and so it should rename the dump file. The first instance will - be -1, and be number of duplicates = -static_pass_number - 1. - Subsequent instances will be > 0 and just the duplicate number. */ - if (pass->name) - { - pass->static_pass_number -= 1; - new->static_pass_number = -pass->static_pass_number; - } - - *list = new; - } - else - { - pass->static_pass_number = -1; - *list = pass; - } - - return &(*list)->next; - -} - -/* Construct the pass tree. */ - -void -init_tree_optimization_passes (void) -{ - struct tree_opt_pass **p; - -#define NEXT_PASS(PASS) (p = next_pass_1 (p, &PASS)) - /* Interprocedural optimization passes. */ - p = &all_ipa_passes; - NEXT_PASS (pass_early_ipa_inline); - NEXT_PASS (pass_early_local_passes); - NEXT_PASS (pass_ipa_inline); - *p = NULL; - - /* All passes needed to lower the function into shape optimizers can operate - on. These passes are performed before interprocedural passes, unlike rest - of local passes (all_passes). */ - p = &all_lowering_passes; - NEXT_PASS (pass_remove_useless_stmts); - NEXT_PASS (pass_mudflap_1); - NEXT_PASS (pass_lower_cf); - NEXT_PASS (pass_lower_eh); - NEXT_PASS (pass_build_cfg); - NEXT_PASS (pass_lower_complex_O0); - NEXT_PASS (pass_lower_vector); - NEXT_PASS (pass_warn_function_return); - NEXT_PASS (pass_early_tree_profile); - *p = NULL; - - p = &pass_early_local_passes.sub; - NEXT_PASS (pass_tree_profile); - NEXT_PASS (pass_cleanup_cfg); - NEXT_PASS (pass_rebuild_cgraph_edges); - *p = NULL; - - p = &all_passes; - NEXT_PASS (pass_fixup_cfg); - NEXT_PASS (pass_init_datastructures); - NEXT_PASS (pass_all_optimizations); - NEXT_PASS (pass_warn_function_noreturn); - NEXT_PASS (pass_mudflap_2); - NEXT_PASS (pass_free_datastructures); - NEXT_PASS (pass_free_cfg_annotations); - NEXT_PASS (pass_expand); - NEXT_PASS (pass_rest_of_compilation); - *p = NULL; - - p = &pass_all_optimizations.sub; - NEXT_PASS (pass_referenced_vars); - NEXT_PASS (pass_create_structure_vars); - NEXT_PASS (pass_build_ssa); - NEXT_PASS (pass_build_pta); - NEXT_PASS (pass_may_alias); - NEXT_PASS (pass_return_slot); - NEXT_PASS (pass_del_pta); - NEXT_PASS (pass_rename_ssa_copies); - NEXT_PASS (pass_early_warn_uninitialized); - - /* Initial scalar cleanups. */ - NEXT_PASS (pass_ccp); - NEXT_PASS (pass_fre); - NEXT_PASS (pass_dce); - NEXT_PASS (pass_forwprop); - NEXT_PASS (pass_copy_prop); - NEXT_PASS (pass_vrp); - NEXT_PASS (pass_dce); - NEXT_PASS (pass_merge_phi); - NEXT_PASS (pass_dominator); - - NEXT_PASS (pass_phiopt); - NEXT_PASS (pass_build_pta); - NEXT_PASS (pass_may_alias); - NEXT_PASS (pass_del_pta); - NEXT_PASS (pass_tail_recursion); - NEXT_PASS (pass_profile); - NEXT_PASS (pass_ch); - NEXT_PASS (pass_stdarg); - NEXT_PASS (pass_lower_complex); - NEXT_PASS (pass_sra); - /* FIXME: SRA may generate arbitrary gimple code, exposing new - aliased and call-clobbered variables. As mentioned below, - pass_may_alias should be a TODO item. */ - NEXT_PASS (pass_may_alias); - NEXT_PASS (pass_rename_ssa_copies); - NEXT_PASS (pass_dominator); - NEXT_PASS (pass_copy_prop); - NEXT_PASS (pass_dce); - NEXT_PASS (pass_dse); - NEXT_PASS (pass_may_alias); - NEXT_PASS (pass_forwprop); - NEXT_PASS (pass_phiopt); - NEXT_PASS (pass_object_sizes); - NEXT_PASS (pass_store_ccp); - NEXT_PASS (pass_store_copy_prop); - NEXT_PASS (pass_fold_builtins); - /* FIXME: May alias should a TODO but for 4.0.0, - we add may_alias right after fold builtins - which can create arbitrary GIMPLE. */ - NEXT_PASS (pass_may_alias); - NEXT_PASS (pass_cse_reciprocals); - NEXT_PASS (pass_split_crit_edges); - NEXT_PASS (pass_reassoc); - NEXT_PASS (pass_pre); - NEXT_PASS (pass_sink_code); - NEXT_PASS (pass_loop); - NEXT_PASS (pass_dominator); - NEXT_PASS (pass_copy_prop); - NEXT_PASS (pass_cd_dce); - /* FIXME: If DCE is not run before checking for uninitialized uses, - we may get false warnings (e.g., testsuite/gcc.dg/uninit-5.c). - However, this also causes us to misdiagnose cases that should be - real warnings (e.g., testsuite/gcc.dg/pr18501.c). - - To fix the false positives in uninit-5.c, we would have to - account for the predicates protecting the set and the use of each - variable. Using a representation like Gated Single Assignment - may help. */ - NEXT_PASS (pass_late_warn_uninitialized); - NEXT_PASS (pass_dse); - NEXT_PASS (pass_forwprop); - NEXT_PASS (pass_phiopt); - NEXT_PASS (pass_tail_calls); - NEXT_PASS (pass_rename_ssa_copies); - NEXT_PASS (pass_uncprop); - NEXT_PASS (pass_del_ssa); - NEXT_PASS (pass_nrv); - NEXT_PASS (pass_remove_useless_vars); - NEXT_PASS (pass_mark_used_blocks); - NEXT_PASS (pass_cleanup_cfg_post_optimizing); - *p = NULL; - - p = &pass_loop.sub; - NEXT_PASS (pass_loop_init); - NEXT_PASS (pass_copy_prop); - NEXT_PASS (pass_lim); - NEXT_PASS (pass_unswitch); - NEXT_PASS (pass_scev_cprop); - NEXT_PASS (pass_record_bounds); - NEXT_PASS (pass_linear_transform); - NEXT_PASS (pass_iv_canon); - NEXT_PASS (pass_if_conversion); - NEXT_PASS (pass_vectorize); - /* NEXT_PASS (pass_may_alias) cannot be done again because the - vectorizer creates alias relations that are not supported by - pass_may_alias. */ - NEXT_PASS (pass_lower_vector_ssa); - NEXT_PASS (pass_complete_unroll); - NEXT_PASS (pass_iv_optimize); - NEXT_PASS (pass_loop_done); - *p = NULL; - -#undef NEXT_PASS - - register_dump_files (all_lowering_passes, false, PROP_gimple_any); - register_dump_files (all_passes, false, PROP_gimple_any - | PROP_gimple_lcf - | PROP_gimple_leh - | PROP_cfg); - register_dump_files (all_ipa_passes, true, PROP_gimple_any - | PROP_gimple_lcf - | PROP_gimple_leh - | PROP_cfg); -} - -static unsigned int last_verified; - -static void -execute_todo (struct tree_opt_pass *pass, unsigned int flags, bool use_required) -{ - int properties - = use_required ? pass->properties_required : pass->properties_provided; - -#if defined ENABLE_CHECKING - if (need_ssa_update_p ()) - gcc_assert (flags & TODO_update_ssa_any); -#endif - - if (flags & TODO_update_ssa_any) - { - unsigned update_flags = flags & TODO_update_ssa_any; - update_ssa (update_flags); - } - - if (flags & TODO_cleanup_cfg) - { - if (current_loops) - cleanup_tree_cfg_loop (); - else - cleanup_tree_cfg (); - } - - if ((flags & TODO_dump_func) - && dump_file && current_function_decl) - { - if (properties & PROP_trees) - dump_function_to_file (current_function_decl, - dump_file, dump_flags); - else if (properties & PROP_cfg) - print_rtl_with_bb (dump_file, get_insns ()); - else - print_rtl (dump_file, get_insns ()); - - /* Flush the file. If verification fails, we won't be able to - close the file before dieing. */ - fflush (dump_file); - } - if ((flags & TODO_dump_cgraph) - && dump_file && !current_function_decl) - { - dump_cgraph (dump_file); - /* Flush the file. If verification fails, we won't be able to - close the file before aborting. */ - fflush (dump_file); - } - - if (flags & TODO_ggc_collect) - { - ggc_collect (); - } - -#if defined ENABLE_CHECKING - if ((pass->properties_required & PROP_ssa) - && !(pass->properties_destroyed & PROP_ssa)) - verify_ssa (true); - if (flags & TODO_verify_flow) - verify_flow_info (); - if (flags & TODO_verify_stmts) - verify_stmts (); - if (flags & TODO_verify_loops) - verify_loop_closed_ssa (); -#endif -} - -static bool -execute_one_pass (struct tree_opt_pass *pass) -{ - unsigned int todo; - - /* See if we're supposed to run this pass. */ - if (pass->gate && !pass->gate ()) - return false; - - /* Note that the folders should only create gimple expressions. - This is a hack until the new folder is ready. */ - in_gimple_form = (pass->properties_provided & PROP_trees) != 0; - - /* Run pre-pass verification. */ - todo = pass->todo_flags_start & ~last_verified; - if (todo) - execute_todo (pass, todo, true); - - /* 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;; Function %s (%s)%s\n\n", dname, aname, - cfun->function_frequency == FUNCTION_FREQUENCY_HOT - ? " (hot)" - : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED - ? " (unlikely executed)" - : ""); - } - - if (initializing_dump - && graph_dump_format != no_graph - && (pass->properties_provided & (PROP_cfg | PROP_rtl)) - == (PROP_cfg | PROP_rtl)) - clean_graph_dump_file (dump_file_name); - } - - /* If a timevar is present, start it. */ - if (pass->tv_id) - timevar_push (pass->tv_id); - - /* Do it! */ - if (pass->execute) - pass->execute (); - - /* Stop timevar. */ - if (pass->tv_id) - timevar_pop (pass->tv_id); - - if (dump_file - && (pass->properties_provided & (PROP_cfg | PROP_rtl)) - == (PROP_cfg | PROP_rtl)) - print_rtl_with_bb (dump_file, get_insns ()); - - /* Run post-pass cleanup and verification. */ - todo = pass->todo_flags_finish; - last_verified = todo & TODO_verify_all; - if (todo) - execute_todo (pass, todo, false); - - /* Flush and close dump file. */ - if (dump_file_name) - { - free ((char *) dump_file_name); - dump_file_name = NULL; - } - if (dump_file) - { - dump_end (pass->static_pass_number, dump_file); - dump_file = NULL; - } - - return true; -} - -static void -execute_pass_list (struct tree_opt_pass *pass) -{ - do - { - if (execute_one_pass (pass) && pass->sub) - execute_pass_list (pass->sub); - pass = pass->next; - } - while (pass); -} - -/* Same as execute_pass_list but assume that subpasses of IPA passes - are local passes. */ -static void -execute_ipa_pass_list (struct tree_opt_pass *pass) -{ - do - { - if (execute_one_pass (pass) && pass->sub) - { - struct cgraph_node *node; - for (node = cgraph_nodes; node; node = node->next) - if (node->analyzed) - { - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); - current_function_decl = node->decl; - execute_pass_list (pass->sub); - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); - current_function_decl = NULL; - pop_cfun (); - ggc_collect (); - } - } - pass = pass->next; - } - while (pass); -} - + void tree_lowering_passes (tree fn) { @@ -800,18 +317,6 @@ tree_lowering_passes (tree fn) pop_cfun (); } -/* Execute all IPA passes. */ -void -ipa_passes (void) -{ - cfun = NULL; - tree_register_cfg_hooks (); - bitmap_obstack_initialize (NULL); - execute_ipa_pass_list (all_ipa_passes); - bitmap_obstack_release (NULL); -} - - /* Update recursively all inlined_to pointers of functions inlined into NODE to INLINED_TO. */ static void |