/* Top-level control of tree optimizations.
- Copyright 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@redhat.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
-#include "rtl.h"
#include "tm_p.h"
-#include "hard-reg-set.h"
#include "basic-block.h"
#include "output.h"
-#include "expr.h"
-#include "diagnostic.h"
-#include "basic-block.h"
#include "flags.h"
#include "tree-flow.h"
#include "tree-dump.h"
#include "timevar.h"
#include "function.h"
#include "langhooks.h"
+#include "diagnostic-core.h"
#include "toplev.h"
#include "flags.h"
#include "cgraph.h"
#include "graph.h"
#include "cfgloop.h"
#include "except.h"
-
+#include "plugin.h"
+#include "regset.h" /* FIXME: For reg_obstack. */
/* Gate: execute, or not, all of the non-trivial optimizations. */
gate_all_optimizations (void)
{
return (optimize >= 1
- /* Don't bother doing anything if the program has errors.
+ /* Don't bother doing anything if the program has errors.
We have to pass down the queue if we already went into SSA */
- && (!(errorcount || sorrycount) || gimple_in_ssa_p (cfun)));
+ && (!seen_error () || gimple_in_ssa_p (cfun)));
}
-struct tree_opt_pass pass_all_optimizations =
+struct gimple_opt_pass pass_all_optimizations =
{
- NULL, /* name */
+ {
+ GIMPLE_PASS,
+ "*all_optimizations", /* name */
gate_all_optimizations, /* gate */
NULL, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_OPTIMIZE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
- 0 /* letter */
+ 0 /* todo_flags_finish */
+ }
};
/* Gate: execute, or not, all of the non-trivial optimizations. */
gate_all_early_local_passes (void)
{
/* Don't bother doing anything if the program has errors. */
- return (!errorcount && !sorrycount);
+ return (!seen_error () && !in_lto_p);
+}
+
+static unsigned int
+execute_all_early_local_passes (void)
+{
+ /* Once this pass (and its sub-passes) are complete, all functions
+ will be in SSA form. Technically this state change is happening
+ a tad early, since the sub-passes have not yet run, but since
+ none of the sub-passes are IPA passes and do not create new
+ functions, this is ok. We're setting this value for the benefit
+ of IPA passes that follow. */
+ if (cgraph_state < CGRAPH_STATE_IPA_SSA)
+ cgraph_state = CGRAPH_STATE_IPA_SSA;
+ return 0;
}
-struct tree_opt_pass pass_early_local_passes =
+struct simple_ipa_opt_pass pass_early_local_passes =
{
+ {
+ SIMPLE_IPA_PASS,
"early_local_cleanups", /* name */
gate_all_early_local_passes, /* gate */
- NULL, /* execute */
+ execute_all_early_local_passes, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_EARLY_LOCAL, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_remove_functions, /* todo_flags_finish */
- 0 /* letter */
+ TODO_remove_functions /* todo_flags_finish */
+ }
};
-static unsigned int
-execute_early_local_optimizations (void)
-{
- if (flag_unit_at_a_time)
- cgraph_state = CGRAPH_STATE_IPA_SSA;
- return 0;
-}
-
/* Gate: execute, or not, all of the non-trivial optimizations. */
static bool
{
return (optimize >= 1
/* Don't bother doing anything if the program has errors. */
- && !(errorcount || sorrycount));
+ && !seen_error ());
}
-struct tree_opt_pass pass_all_early_optimizations =
+struct gimple_opt_pass pass_all_early_optimizations =
{
+ {
+ GIMPLE_PASS,
"early_optimizations", /* name */
gate_all_early_optimizations, /* gate */
- execute_early_local_optimizations, /* execute */
+ NULL, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_NONE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
- 0 /* letter */
-};
-
-/* Pass: cleanup the CFG just before expanding trees to RTL.
- This is just a round of label cleanups and case node grouping
- because after the tree optimizers have run such cleanups may
- be necessary. */
-
-static unsigned int
-execute_cleanup_cfg_pre_ipa (void)
-{
- cleanup_tree_cfg ();
- return 0;
-}
-
-struct tree_opt_pass pass_cleanup_cfg =
-{
- "cleanup_cfg", /* name */
- NULL, /* gate */
- execute_cleanup_cfg_pre_ipa, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- 0, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func, /* todo_flags_finish */
- 0 /* letter */
+ 0 /* todo_flags_finish */
+ }
};
static unsigned int
execute_cleanup_cfg_post_optimizing (void)
{
- fold_cond_expr_cond ();
cleanup_tree_cfg ();
cleanup_dead_labels ();
group_case_labels ();
+ if ((flag_compare_debug_opt || flag_compare_debug)
+ && flag_dump_final_insns)
+ {
+ FILE *final_output = fopen (flag_dump_final_insns, "a");
+
+ if (!final_output)
+ {
+ error ("could not open final insn dump file %qs: %m",
+ flag_dump_final_insns);
+ flag_dump_final_insns = NULL;
+ }
+ else
+ {
+ int save_unnumbered = flag_dump_unnumbered;
+ int save_noaddr = flag_dump_noaddr;
+
+ flag_dump_noaddr = flag_dump_unnumbered = 1;
+ fprintf (final_output, "\n");
+ dump_enumerated_decls (final_output, dump_flags | TDF_NOUID);
+ flag_dump_noaddr = save_noaddr;
+ flag_dump_unnumbered = save_unnumbered;
+ if (fclose (final_output))
+ {
+ error ("could not close final insn dump file %qs: %m",
+ flag_dump_final_insns);
+ flag_dump_final_insns = NULL;
+ }
+ }
+ }
return 0;
}
-struct tree_opt_pass pass_cleanup_cfg_post_optimizing =
+struct gimple_opt_pass pass_cleanup_cfg_post_optimizing =
{
- "final_cleanup", /* name */
+ {
+ GIMPLE_PASS,
+ "optimized", /* name */
NULL, /* gate */
execute_cleanup_cfg_post_optimizing, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_TREE_CLEANUP_CFG, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func, /* todo_flags_finish */
- 0 /* letter */
+ TODO_dump_func /* todo_flags_finish */
+ | TODO_remove_unused_locals
+ }
};
/* Pass: do the actions required to finish with tree-ssa optimization
passes. */
-static unsigned int
+unsigned int
execute_free_datastructures (void)
{
free_dominance_info (CDI_DOMINATORS);
free_dominance_info (CDI_POST_DOMINATORS);
- /* Remove the ssa structures. */
- if (cfun->gimple_df)
- delete_tree_ssa ();
- return 0;
-}
-
-struct tree_opt_pass pass_free_datastructures =
-{
- NULL, /* name */
- NULL, /* gate */
- execute_free_datastructures, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- 0, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
- 0 /* letter */
-};
-/* Pass: free cfg annotations. */
-
-static unsigned int
-execute_free_cfg_annotations (void)
-{
/* And get rid of annotations we no longer need. */
delete_tree_cfg_annotations ();
return 0;
}
-struct tree_opt_pass pass_free_cfg_annotations =
-{
- NULL, /* name */
- NULL, /* gate */
- execute_free_cfg_annotations, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- 0, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
- 0 /* letter */
-};
-
-/* Pass: fixup_cfg. IPA passes, compilation of earlier functions or inlining
- might have changed some properties, such as marked functions nothrow.
+/* IPA passes, compilation of earlier functions or inlining
+ might have changed some properties, such as marked functions nothrow,
+ pure, const or noreturn.
Remove redundant edges and basic blocks, and create new ones if necessary.
This pass can't be executed as stand alone pass from pass manager, because
execute_fixup_cfg (void)
{
basic_block bb;
- block_stmt_iterator bsi;
+ gimple_stmt_iterator gsi;
int todo = gimple_in_ssa_p (cfun) ? TODO_verify_ssa : 0;
+ gcov_type count_scale;
+ edge e;
+ edge_iterator ei;
+
+ if (ENTRY_BLOCK_PTR->count)
+ count_scale = (cgraph_node (current_function_decl)->count * REG_BR_PROB_BASE
+ + ENTRY_BLOCK_PTR->count / 2) / ENTRY_BLOCK_PTR->count;
+ else
+ count_scale = REG_BR_PROB_BASE;
+
+ ENTRY_BLOCK_PTR->count = cgraph_node (current_function_decl)->count;
+ EXIT_BLOCK_PTR->count = (EXIT_BLOCK_PTR->count * count_scale
+ + REG_BR_PROB_BASE / 2) / REG_BR_PROB_BASE;
+
+ FOR_EACH_BB (bb)
+ {
+ bb->count = (bb->count * count_scale
+ + REG_BR_PROB_BASE / 2) / REG_BR_PROB_BASE;
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple stmt = gsi_stmt (gsi);
+ tree decl = is_gimple_call (stmt)
+ ? gimple_call_fndecl (stmt)
+ : NULL;
+ if (decl)
+ {
+ int flags = gimple_call_flags (stmt);
+ if (flags & (ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE))
+ {
+ if (gimple_purge_dead_abnormal_call_edges (bb))
+ todo |= TODO_cleanup_cfg;
+
+ if (gimple_in_ssa_p (cfun))
+ {
+ todo |= TODO_update_ssa | TODO_cleanup_cfg;
+ update_stmt (stmt);
+ }
+ }
+
+ if (flags & ECF_NORETURN
+ && fixup_noreturn_call (stmt))
+ todo |= TODO_cleanup_cfg;
+ }
+
+ if (maybe_clean_eh_stmt (stmt)
+ && gimple_purge_dead_eh_edges (bb))
+ todo |= TODO_cleanup_cfg;
+ }
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ e->count = (e->count * count_scale
+ + REG_BR_PROB_BASE / 2) / REG_BR_PROB_BASE;
+ }
+ if (count_scale != REG_BR_PROB_BASE)
+ compute_function_frequency ();
- cfun->after_inlining = true;
-
- if (cfun->eh)
- FOR_EACH_BB (bb)
- {
- for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
- {
- tree stmt = bsi_stmt (bsi);
- tree call = get_call_expr_in (stmt);
- tree decl = call ? get_callee_fndecl (call) : NULL;
-
- if (decl && call_expr_flags (call) & (ECF_CONST | ECF_PURE)
- && TREE_SIDE_EFFECTS (call))
- {
- if (gimple_in_ssa_p (cfun))
- {
- todo |= TODO_update_ssa | TODO_cleanup_cfg;
- update_stmt (stmt);
- }
- TREE_SIDE_EFFECTS (call) = 0;
- }
- if (decl && TREE_NOTHROW (decl))
- TREE_NOTHROW (call) = 1;
- if (!tree_could_throw_p (stmt) && lookup_stmt_eh_region (stmt))
- remove_stmt_from_eh_region (stmt);
- }
- if (tree_purge_dead_eh_edges (bb))
- todo |= TODO_cleanup_cfg;
- }
+ /* We just processed all calls. */
+ if (cfun->gimple_df)
+ {
+ VEC_free (gimple, gc, MODIFIED_NORETURN_CALLS (cfun));
+ MODIFIED_NORETURN_CALLS (cfun) = NULL;
+ }
/* Dump a textual representation of the flowgraph. */
if (dump_file)
- dump_tree_cfg (dump_file, dump_flags);
+ gimple_dump_cfg (dump_file, dump_flags);
return todo;
}
+struct gimple_opt_pass pass_fixup_cfg =
+{
+ {
+ GIMPLE_PASS,
+ "*free_cfg_annotations", /* name */
+ NULL, /* gate */
+ execute_fixup_cfg, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_NONE, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0 /* todo_flags_finish */
+ }
+};
+
/* Do the actions required to initialize internal data structures used
in tree-ssa optimization passes. */
execute_init_datastructures (void)
{
/* Allocate hash tables, arrays and other structures. */
- init_tree_ssa ();
+ init_tree_ssa (cfun);
return 0;
}
-/* Gate: initialize or not the SSA datastructures. */
-
-static bool
-gate_init_datastructures (void)
-{
- return (optimize >= 1);
-}
-
-struct tree_opt_pass pass_init_datastructures =
+struct gimple_opt_pass pass_init_datastructures =
{
- NULL, /* name */
- gate_init_datastructures, /* gate */
+ {
+ GIMPLE_PASS,
+ "*init_datastructures", /* name */
+ NULL, /* gate */
execute_init_datastructures, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_NONE, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
- 0 /* letter */
+ 0 /* todo_flags_finish */
+ }
};
void
current_function_decl = fn;
push_cfun (DECL_STRUCT_FUNCTION (fn));
- tree_register_cfg_hooks ();
+ gimple_register_cfg_hooks ();
bitmap_obstack_initialize (NULL);
execute_pass_list (all_lowering_passes);
if (optimize && cgraph_global_info_ready)
- execute_pass_list (pass_early_local_passes.sub);
+ execute_pass_list (pass_early_local_passes.pass.sub);
free_dominance_info (CDI_POST_DOMINATORS);
free_dominance_info (CDI_DOMINATORS);
compact_blocks ();
tree_rest_of_compilation (tree fndecl)
{
location_t saved_loc;
- struct cgraph_node *node;
-
- timevar_push (TV_EXPAND);
- gcc_assert (!flag_unit_at_a_time || cgraph_global_info_ready);
+ timevar_push (TV_REST_OF_COMPILATION);
- node = cgraph_node (fndecl);
+ gcc_assert (cgraph_global_info_ready);
/* Initialize the default bitmap obstack. */
bitmap_obstack_initialize (NULL);
/* Initialize the RTL code for the function. */
current_function_decl = fndecl;
- cfun = DECL_STRUCT_FUNCTION (fndecl);
saved_loc = input_location;
input_location = DECL_SOURCE_LOCATION (fndecl);
init_function_start (fndecl);
call expand_expr to calculate the size of a variable-sized array.
We haven't necessarily assigned RTL to all variables yet, so it's
not safe to try to expand expressions involving them. */
- cfun->x_dont_save_pending_sizes_p = 1;
-
- tree_register_cfg_hooks ();
+ cfun->dont_save_pending_sizes_p = 1;
+
+ gimple_register_cfg_hooks ();
bitmap_obstack_initialize (®_obstack); /* FIXME, only at RTL generation*/
+
+ execute_all_ipa_transforms ();
+
/* Perform all tree transforms and optimizations. */
+
+ /* Signal the start of passes. */
+ invoke_plugin_callbacks (PLUGIN_ALL_PASSES_START, NULL);
+
execute_pass_list (all_passes);
-
+
+ /* Signal the end of passes. */
+ invoke_plugin_callbacks (PLUGIN_ALL_PASSES_END, NULL);
+
bitmap_obstack_release (®_obstack);
/* Release the default bitmap obstack. */
bitmap_obstack_release (NULL);
-
- DECL_SAVED_TREE (fndecl) = NULL;
- cfun = 0;
+
+ set_cfun (NULL);
/* If requested, warn about function definitions where the function will
return a value (usually of some struct or union type) which itself will
= TREE_INT_CST_LOW (TYPE_SIZE_UNIT (ret_type));
if (compare_tree_int (TYPE_SIZE_UNIT (ret_type), size_as_int) == 0)
- warning (0, "size of return value of %q+D is %u bytes",
+ warning (OPT_Wlarger_than_, "size of return value of %q+D is %u bytes",
fndecl, size_as_int);
else
- warning (0, "size of return value of %q+D is larger than %wd bytes",
+ warning (OPT_Wlarger_than_, "size of return value of %q+D is larger than %wd bytes",
fndecl, larger_than_size);
}
}
- if (!flag_inline_trees)
+ gimple_set_body (fndecl, NULL);
+ if (DECL_STRUCT_FUNCTION (fndecl) == 0
+ && !cgraph_node (fndecl)->origin)
{
- DECL_SAVED_TREE (fndecl) = NULL;
- if (DECL_STRUCT_FUNCTION (fndecl) == 0
- && !cgraph_node (fndecl)->origin)
- {
- /* Stop pointing to the local nodes about to be freed.
- But DECL_INITIAL must remain nonzero so we know this
- was an actual function definition.
- For a nested function, this is done in c_pop_function_context.
- If rest_of_compilation set this to 0, leave it 0. */
- if (DECL_INITIAL (fndecl) != 0)
- DECL_INITIAL (fndecl) = error_mark_node;
- }
+ /* Stop pointing to the local nodes about to be freed.
+ But DECL_INITIAL must remain nonzero so we know this
+ was an actual function definition.
+ For a nested function, this is done in c_pop_function_context.
+ If rest_of_compilation set this to 0, leave it 0. */
+ if (DECL_INITIAL (fndecl) != 0)
+ DECL_INITIAL (fndecl) = error_mark_node;
}
input_location = saved_loc;
ggc_collect ();
- timevar_pop (TV_EXPAND);
+ timevar_pop (TV_REST_OF_COMPILATION);
}