/* Top-level control of tree optimizations.
- Copyright 2001, 2002, 2003, 2004, 2005, 2007 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.
#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_NONE, /* 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);
}
-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 */
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 */
- 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)
+ /* First time we start with early optimization we need to advance
+ cgraph state so newly inserted functions are also early optimized.
+ However we execute early local optimizations for lately inserted
+ functions, in that case don't reset cgraph state back to IPA_SSA. */
+ if (cgraph_state < CGRAPH_STATE_IPA_SSA)
cgraph_state = CGRAPH_STATE_IPA_SSA;
return 0;
}
{
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, /* 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 */
+ 0 /* todo_flags_finish */
+ }
};
/* Pass: cleanup the CFG just before expanding trees to RTL.
return 0;
}
-struct tree_opt_pass pass_cleanup_cfg =
+struct gimple_opt_pass pass_cleanup_cfg =
{
+ {
+ GIMPLE_PASS,
"cleanup_cfg", /* name */
NULL, /* gate */
execute_cleanup_cfg_pre_ipa, /* 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 */
- TODO_dump_func, /* todo_flags_finish */
- 0 /* letter */
+ TODO_dump_func /* todo_flags_finish */
+ }
};
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_NONE, /* 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.
+ 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;
- 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;
- }
+ 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_in_ssa_p (cfun))
+ {
+ todo |= TODO_update_ssa | TODO_cleanup_cfg;
+ mark_symbols_for_renaming (stmt);
+ update_stmt (stmt);
+ }
+ }
+
+ if (flags & ECF_NORETURN
+ && fixup_noreturn_call (stmt))
+ todo |= TODO_cleanup_cfg;
+ }
+
+ maybe_clean_eh_stmt (stmt);
+ }
+
+ if (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 ();
+
+ /* 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);
-
- node = cgraph_node (fndecl);
+ gcc_assert (cgraph_global_info_ready);
/* Initialize the default bitmap obstack. */
bitmap_obstack_initialize (NULL);
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;
+
set_cfun (NULL);
/* If requested, warn about function definitions where the function will
= TREE_INT_CST_LOW (TYPE_SIZE_UNIT (ret_type));
if (compare_tree_int (TYPE_SIZE_UNIT (ret_type), size_as_int) == 0)
- warning (OPT_Wlarger_than_, "size of return value of %q+D is %u bytes",
+ warning (OPT_Wlarger_than_eq, "size of return value of %q+D is %u bytes",
fndecl, size_as_int);
else
- warning (OPT_Wlarger_than_, "size of return value of %q+D is larger than %wd bytes",
+ warning (OPT_Wlarger_than_eq, "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;