#include "config.h"
#undef FLOAT
#undef FFS
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include <signal.h>
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif
#ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
#include "line-map.h"
#include "input.h"
#include "tree.h"
#include "rtl.h"
#include "tm_p.h"
#include "flags.h"
#include "insn-attr.h"
#include "insn-config.h"
#include "insn-flags.h"
#include "hard-reg-set.h"
#include "recog.h"
#include "output.h"
#include "except.h"
#include "function.h"
#include "toplev.h"
#include "expr.h"
#include "basic-block.h"
#include "intl.h"
#include "ggc.h"
#include "graph.h"
#include "regs.h"
#include "timevar.h"
#include "diagnostic.h"
#include "params.h"
#include "reload.h"
#include "dwarf2asm.h"
#include "integrate.h"
#include "real.h"
#include "debug.h"
#include "target.h"
#include "langhooks.h"
#include "cfglayout.h"
#include "cfgloop.h"
#include "hosthooks.h"
#include "cgraph.h"
#include "opts.h"
#include "coverage.h"
#include "value-prof.h"
#include "alloc-pool.h"
#include "tree-pass.h"
#include "tree-dump.h"
#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
#include "dwarf2out.h"
#endif
#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
#include "dbxout.h"
#endif
#ifdef SDB_DEBUGGING_INFO
#include "sdbout.h"
#endif
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h"
#endif
#ifndef HAVE_conditional_execution
#define HAVE_conditional_execution 0
#endif
#ifndef DUMPFILE_FORMAT
#define DUMPFILE_FORMAT ".%02d."
#endif
static int initializing_dump = 0;
static int
open_dump_file (enum tree_dump_index index, tree decl)
{
if (! dump_enabled_p (index))
return 0;
timevar_push (TV_DUMP);
if (dump_file != NULL || dump_file_name != NULL)
abort ();
dump_file_name = get_dump_file_name (index);
initializing_dump = !dump_initialized_p (index);
dump_file = dump_begin (index, NULL);
if (dump_file == NULL)
fatal_error ("can't open %s: %m", dump_file_name);
if (decl)
fprintf (dump_file, "\n;; Function %s%s\n\n",
lang_hooks.decl_printable_name (decl, 2),
cfun->function_frequency == FUNCTION_FREQUENCY_HOT
? " (hot)"
: cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
? " (unlikely executed)"
: "");
timevar_pop (TV_DUMP);
return 1;
}
static void
close_dump_file (enum tree_dump_index index,
void (*func) (FILE *, rtx),
rtx insns)
{
if (! dump_file)
return;
timevar_push (TV_DUMP);
if (insns
&& graph_dump_format != no_graph)
{
if (initializing_dump)
clean_graph_dump_file (dump_file_name);
print_rtl_graph_with_bb (dump_file_name, insns);
}
if (func && insns)
func (dump_file, insns);
dump_end (index, dump_file);
free ((char *) dump_file_name);
dump_file = NULL;
dump_file_name = NULL;
timevar_pop (TV_DUMP);
}
void
rest_of_decl_compilation (tree decl,
int top_level,
int at_end)
{
{
tree alias;
alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl));
if (alias)
{
alias = TREE_VALUE (TREE_VALUE (alias));
alias = get_identifier (TREE_STRING_POINTER (alias));
assemble_alias (decl, alias);
}
}
if (DECL_REGISTER (decl) && DECL_ASSEMBLER_NAME_SET_P (decl))
make_decl_rtl (decl);
if (TREE_STATIC (decl) || DECL_EXTERNAL (decl)
|| TREE_CODE (decl) == FUNCTION_DECL)
{
timevar_push (TV_VARCONST);
if ((at_end
|| !DECL_DEFER_OUTPUT (decl)
|| (flag_unit_at_a_time && DECL_INITIAL (decl)))
&& !DECL_EXTERNAL (decl))
{
if (flag_unit_at_a_time && !cgraph_global_info_ready
&& TREE_CODE (decl) != FUNCTION_DECL && top_level)
cgraph_varpool_finalize_decl (decl);
else
assemble_variable (decl, top_level, at_end, 0);
}
#ifdef ASM_FINISH_DECLARE_OBJECT
if (decl == last_assemble_variable_decl)
{
ASM_FINISH_DECLARE_OBJECT (asm_out_file, decl,
top_level, at_end);
}
#endif
timevar_pop (TV_VARCONST);
}
else if (TREE_CODE (decl) == TYPE_DECL)
{
timevar_push (TV_SYMOUT);
debug_hooks->type_decl (decl, !top_level);
timevar_pop (TV_SYMOUT);
}
if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
cgraph_varpool_node (decl);
}
void
rest_of_type_compilation (tree type, int toplev)
{
if (errorcount != 0 || sorrycount != 0)
return;
timevar_push (TV_SYMOUT);
debug_hooks->type_decl (TYPE_STUB_DECL (type), !toplev);
timevar_pop (TV_SYMOUT);
}
static void
rest_of_handle_final (void)
{
timevar_push (TV_FINAL);
{
rtx x;
const char *fnname;
x = DECL_RTL (current_function_decl);
if (!MEM_P (x))
abort ();
x = XEXP (x, 0);
if (GET_CODE (x) != SYMBOL_REF)
abort ();
fnname = XSTR (x, 0);
assemble_start_function (current_function_decl, fnname);
final_start_function (get_insns (), asm_out_file, optimize);
final (get_insns (), asm_out_file, optimize, 0);
final_end_function ();
#ifdef TARGET_UNWIND_INFO
output_function_exception_table ();
#endif
assemble_end_function (current_function_decl, fnname);
#ifndef TARGET_UNWIND_INFO
output_function_exception_table ();
#endif
user_defined_section_attribute = false;
if (! quiet_flag)
fflush (asm_out_file);
free_basic_block_vars ();
}
timevar_push (TV_SYMOUT);
(*debug_hooks->function_decl) (current_function_decl);
timevar_pop (TV_SYMOUT);
ggc_collect ();
timevar_pop (TV_FINAL);
}
#ifdef DELAY_SLOTS
static void
rest_of_handle_delay_slots (void)
{
timevar_push (TV_DBR_SCHED);
open_dump_file (DFI_dbr, current_function_decl);
dbr_schedule (get_insns (), dump_file);
close_dump_file (DFI_dbr, print_rtl, get_insns ());
ggc_collect ();
timevar_pop (TV_DBR_SCHED);
}
#endif
#ifdef STACK_REGS
static void
rest_of_handle_stack_regs (void)
{
#if defined (HAVE_ATTR_length)
#ifdef INSN_SCHEDULING
if (optimize && !flag_schedule_insns_after_reload)
#else
if (optimize)
#endif
{
timevar_push (TV_SHORTEN_BRANCH);
split_all_insns (1);
timevar_pop (TV_SHORTEN_BRANCH);
}
#endif
timevar_push (TV_REG_STACK);
open_dump_file (DFI_stack, current_function_decl);
if (reg_to_stack (dump_file) && optimize)
{
if (cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_POST_REGSTACK
| (flag_crossjumping ? CLEANUP_CROSSJUMP : 0))
&& (flag_reorder_blocks || flag_reorder_blocks_and_partition))
{
reorder_basic_blocks (0);
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_POST_REGSTACK);
}
}
close_dump_file (DFI_stack, print_rtl_with_bb, get_insns ());
ggc_collect ();
timevar_pop (TV_REG_STACK);
}
#endif
static void
rest_of_handle_variable_tracking (void)
{
timevar_push (TV_VAR_TRACKING);
open_dump_file (DFI_vartrack, current_function_decl);
variable_tracking_main ();
close_dump_file (DFI_vartrack, print_rtl_with_bb, get_insns ());
timevar_pop (TV_VAR_TRACKING);
}
static void
rest_of_handle_machine_reorg (void)
{
timevar_push (TV_MACH_DEP);
open_dump_file (DFI_mach, current_function_decl);
targetm.machine_dependent_reorg ();
close_dump_file (DFI_mach, print_rtl, get_insns ());
ggc_collect ();
timevar_pop (TV_MACH_DEP);
}
static bool
rest_of_handle_old_regalloc (void)
{
int failure;
int rebuild_notes;
timevar_push (TV_LOCAL_ALLOC);
open_dump_file (DFI_lreg, current_function_decl);
allocate_reg_info (max_regno, FALSE, TRUE);
VARRAY_GROW (reg_equiv_memory_loc_varray, max_regno);
reg_equiv_memory_loc = &VARRAY_RTX (reg_equiv_memory_loc_varray, 0);
allocate_initial_values (reg_equiv_memory_loc);
regclass (get_insns (), max_reg_num (), dump_file);
rebuild_notes = local_alloc ();
timevar_pop (TV_LOCAL_ALLOC);
if (rebuild_notes)
{
timevar_push (TV_JUMP);
rebuild_jump_labels (get_insns ());
purge_all_dead_edges (0);
delete_unreachable_blocks ();
timevar_pop (TV_JUMP);
}
if (dump_enabled_p (DFI_lreg))
{
timevar_push (TV_DUMP);
dump_flow_info (dump_file);
dump_local_alloc (dump_file);
timevar_pop (TV_DUMP);
}
close_dump_file (DFI_lreg, print_rtl_with_bb, get_insns ());
ggc_collect ();
timevar_push (TV_GLOBAL_ALLOC);
open_dump_file (DFI_greg, current_function_decl);
if (optimize)
failure = global_alloc (dump_file);
else
{
build_insn_chain (get_insns ());
failure = reload (get_insns (), 0);
}
if (dump_enabled_p (DFI_greg))
{
timevar_push (TV_DUMP);
dump_global_regs (dump_file);
timevar_pop (TV_DUMP);
close_dump_file (DFI_greg, print_rtl_with_bb, get_insns ());
}
ggc_collect ();
timevar_pop (TV_GLOBAL_ALLOC);
return failure;
}
static void
rest_of_handle_regrename (void)
{
timevar_push (TV_RENAME_REGISTERS);
open_dump_file (DFI_rnreg, current_function_decl);
if (flag_rename_registers)
regrename_optimize ();
if (flag_cprop_registers)
copyprop_hardreg_forward ();
close_dump_file (DFI_rnreg, print_rtl_with_bb, get_insns ());
timevar_pop (TV_RENAME_REGISTERS);
}
static void
rest_of_handle_reorder_blocks (void)
{
bool changed;
unsigned int liveness_flags;
open_dump_file (DFI_bbro, current_function_decl);
liveness_flags = (!HAVE_conditional_execution ? CLEANUP_UPDATE_LIFE : 0);
changed = cleanup_cfg (CLEANUP_EXPENSIVE | liveness_flags);
if (flag_sched2_use_traces && flag_schedule_insns_after_reload)
tracer (liveness_flags);
if (flag_reorder_blocks || flag_reorder_blocks_and_partition)
reorder_basic_blocks (liveness_flags);
if (flag_reorder_blocks || flag_reorder_blocks_and_partition
|| (flag_sched2_use_traces && flag_schedule_insns_after_reload))
changed |= cleanup_cfg (CLEANUP_EXPENSIVE | liveness_flags);
if (changed && HAVE_conditional_execution)
update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES,
PROP_DEATH_NOTES);
close_dump_file (DFI_bbro, print_rtl_with_bb, get_insns ());
}
static void
rest_of_handle_partition_blocks (void)
{
no_new_pseudos = 0;
partition_hot_cold_basic_blocks ();
allocate_reg_life_data ();
update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES,
PROP_LOG_LINKS | PROP_REG_INFO | PROP_DEATH_NOTES);
no_new_pseudos = 1;
}
#ifdef INSN_SCHEDULING
static void
rest_of_handle_sms (void)
{
sbitmap blocks;
timevar_push (TV_SMS);
open_dump_file (DFI_sms, current_function_decl);
no_new_pseudos = 0;
sms_schedule (dump_file);
close_dump_file (DFI_sms, print_rtl, get_insns ());
max_regno = max_reg_num ();
allocate_reg_info (max_regno, FALSE, FALSE);
blocks = sbitmap_alloc (last_basic_block);
sbitmap_ones (blocks);
update_life_info (blocks, UPDATE_LIFE_GLOBAL_RM_NOTES,
(PROP_DEATH_NOTES
| PROP_REG_INFO
| PROP_KILL_DEAD_CODE
| PROP_SCAN_DEAD_CODE));
no_new_pseudos = 1;
ggc_collect ();
timevar_pop (TV_SMS);
}
static void
rest_of_handle_sched (void)
{
timevar_push (TV_SCHED);
open_dump_file (DFI_sched, current_function_decl);
schedule_insns (dump_file);
close_dump_file (DFI_sched, print_rtl_with_bb, get_insns ());
ggc_collect ();
timevar_pop (TV_SCHED);
}
static void
rest_of_handle_sched2 (void)
{
timevar_push (TV_SCHED2);
open_dump_file (DFI_sched2, current_function_decl);
split_all_insns (1);
if (flag_sched2_use_superblocks || flag_sched2_use_traces)
{
schedule_ebbs (dump_file);
count_or_remove_death_notes (NULL, 1);
cleanup_cfg (CLEANUP_EXPENSIVE);
}
else
schedule_insns (dump_file);
close_dump_file (DFI_sched2, print_rtl_with_bb, get_insns ());
ggc_collect ();
timevar_pop (TV_SCHED2);
}
#endif
static void
rest_of_handle_gcse2 (void)
{
timevar_push (TV_GCSE_AFTER_RELOAD);
open_dump_file (DFI_gcse2, current_function_decl);
gcse_after_reload_main (get_insns ());
rebuild_jump_labels (get_insns ());
delete_trivially_dead_insns (get_insns (), max_reg_num ());
close_dump_file (DFI_gcse2, print_rtl_with_bb, get_insns ());
ggc_collect ();
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
timevar_pop (TV_GCSE_AFTER_RELOAD);
}
static void
rest_of_handle_regmove (void)
{
timevar_push (TV_REGMOVE);
open_dump_file (DFI_regmove, current_function_decl);
regmove_optimize (get_insns (), max_reg_num (), dump_file);
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
close_dump_file (DFI_regmove, print_rtl_with_bb, get_insns ());
ggc_collect ();
timevar_pop (TV_REGMOVE);
}
static void
rest_of_handle_tracer (void)
{
open_dump_file (DFI_tracer, current_function_decl);
if (dump_file)
dump_flow_info (dump_file);
tracer (0);
cleanup_cfg (CLEANUP_EXPENSIVE);
reg_scan (get_insns (), max_reg_num ());
close_dump_file (DFI_tracer, print_rtl_with_bb, get_insns ());
}
static void
rest_of_handle_if_conversion (void)
{
timevar_push (TV_IFCVT);
open_dump_file (DFI_ce1, current_function_decl);
if (flag_if_conversion)
{
if (dump_file)
dump_flow_info (dump_file);
cleanup_cfg (CLEANUP_EXPENSIVE);
reg_scan (get_insns (), max_reg_num ());
if_convert (0);
}
timevar_push (TV_JUMP);
cleanup_cfg (CLEANUP_EXPENSIVE);
reg_scan (get_insns (), max_reg_num ());
timevar_pop (TV_JUMP);
close_dump_file (DFI_ce1, print_rtl_with_bb, get_insns ());
timevar_pop (TV_IFCVT);
}
static void
rest_of_handle_if_after_combine (void)
{
timevar_push (TV_IFCVT);
open_dump_file (DFI_ce2, current_function_decl);
no_new_pseudos = 0;
if_convert (1);
no_new_pseudos = 1;
close_dump_file (DFI_ce2, print_rtl_with_bb, get_insns ());
timevar_pop (TV_IFCVT);
}
static void
rest_of_handle_if_after_reload (void)
{
timevar_push (TV_IFCVT2);
open_dump_file (DFI_ce3, current_function_decl);
cleanup_cfg (CLEANUP_EXPENSIVE
| CLEANUP_UPDATE_LIFE
| (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
if (flag_if_conversion2)
if_convert (1);
close_dump_file (DFI_ce3, print_rtl_with_bb, get_insns ());
timevar_pop (TV_IFCVT2);
}
static void
rest_of_handle_web (void)
{
open_dump_file (DFI_web, current_function_decl);
timevar_push (TV_WEB);
web_main ();
delete_trivially_dead_insns (get_insns (), max_reg_num ());
cleanup_cfg (CLEANUP_EXPENSIVE);
timevar_pop (TV_WEB);
close_dump_file (DFI_web, print_rtl_with_bb, get_insns ());
reg_scan (get_insns (), max_reg_num ());
}
static void
rest_of_handle_branch_prob (void)
{
struct loops loops;
timevar_push (TV_BRANCH_PROB);
open_dump_file (DFI_bp, current_function_decl);
if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
branch_prob ();
flow_loops_find (&loops, LOOP_TREE);
if (dump_file)
flow_loops_dump (&loops, dump_file, NULL, 0);
if (flag_guess_branch_prob)
estimate_probability (&loops);
flow_loops_free (&loops);
free_dominance_info (CDI_DOMINATORS);
close_dump_file (DFI_bp, print_rtl_with_bb, get_insns ());
timevar_pop (TV_BRANCH_PROB);
}
static void
rest_of_handle_value_profile_transformations (void)
{
open_dump_file (DFI_vpt, current_function_decl);
timevar_push (TV_VPT);
if (value_profile_transformations ())
cleanup_cfg (CLEANUP_EXPENSIVE);
timevar_pop (TV_VPT);
close_dump_file (DFI_vpt, print_rtl_with_bb, get_insns ());
}
static void
rest_of_handle_cfg (void)
{
open_dump_file (DFI_cfg, current_function_decl);
if (dump_file)
dump_flow_info (dump_file);
if (optimize)
cleanup_cfg (CLEANUP_EXPENSIVE
| (flag_thread_jumps ? CLEANUP_THREADING : 0));
if (optimize
&& (!flag_tree_based_profiling
|| (!profile_arc_flag && !flag_branch_probabilities)))
{
reg_scan (get_insns (), max_reg_num ());
mark_constant_function ();
}
close_dump_file (DFI_cfg, print_rtl_with_bb, get_insns ());
}
static void
rest_of_handle_jump_bypass (void)
{
timevar_push (TV_BYPASS);
open_dump_file (DFI_bypass, current_function_decl);
cleanup_cfg (CLEANUP_EXPENSIVE);
reg_scan (get_insns (), max_reg_num ());
if (bypass_jumps (dump_file))
{
rebuild_jump_labels (get_insns ());
cleanup_cfg (CLEANUP_EXPENSIVE);
delete_trivially_dead_insns (get_insns (), max_reg_num ());
}
close_dump_file (DFI_bypass, print_rtl_with_bb, get_insns ());
timevar_pop (TV_BYPASS);
ggc_collect ();
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
}
static void
rest_of_handle_combine (void)
{
int rebuild_jump_labels_after_combine = 0;
timevar_push (TV_COMBINE);
open_dump_file (DFI_combine, current_function_decl);
rebuild_jump_labels_after_combine
= combine_instructions (get_insns (), max_reg_num ());
if (rebuild_jump_labels_after_combine)
{
timevar_push (TV_JUMP);
rebuild_jump_labels (get_insns ());
timevar_pop (TV_JUMP);
delete_dead_jumptables ();
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
}
close_dump_file (DFI_combine, print_rtl_with_bb, get_insns ());
timevar_pop (TV_COMBINE);
ggc_collect ();
}
static void
rest_of_handle_life (void)
{
open_dump_file (DFI_life, current_function_decl);
regclass_init ();
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
life_analysis (dump_file, PROP_FINAL);
if (optimize)
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE | CLEANUP_LOG_LINKS
| (flag_thread_jumps ? CLEANUP_THREADING : 0));
if (extra_warnings)
{
setjmp_vars_warning (DECL_INITIAL (current_function_decl));
setjmp_args_warning ();
}
if (optimize)
{
if (initialize_uninitialized_subregs ())
{
allocate_reg_life_data ();
update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES,
PROP_LOG_LINKS | PROP_REG_INFO | PROP_DEATH_NOTES);
}
}
no_new_pseudos = 1;
close_dump_file (DFI_life, print_rtl_with_bb, get_insns ());
ggc_collect ();
}
static void
rest_of_handle_cse (void)
{
int tem;
open_dump_file (DFI_cse, current_function_decl);
if (dump_file)
dump_flow_info (dump_file);
timevar_push (TV_CSE);
reg_scan (get_insns (), max_reg_num ());
tem = cse_main (get_insns (), max_reg_num (), dump_file);
if (tem)
rebuild_jump_labels (get_insns ());
if (purge_all_dead_edges (0))
delete_unreachable_blocks ();
delete_trivially_dead_insns (get_insns (), max_reg_num ());
cse_not_expected = !flag_rerun_cse_after_loop && !flag_gcse;
if (tem)
delete_dead_jumptables ();
if (tem || optimize > 1)
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
timevar_pop (TV_CSE);
close_dump_file (DFI_cse, print_rtl_with_bb, get_insns ());
ggc_collect ();
}
static void
rest_of_handle_cse2 (void)
{
int tem;
timevar_push (TV_CSE2);
open_dump_file (DFI_cse2, current_function_decl);
if (dump_file)
dump_flow_info (dump_file);
tem = cse_main (get_insns (), max_reg_num (), dump_file);
cse_condition_code_reg ();
purge_all_dead_edges (0);
delete_trivially_dead_insns (get_insns (), max_reg_num ());
if (tem)
{
timevar_push (TV_JUMP);
rebuild_jump_labels (get_insns ());
delete_dead_jumptables ();
cleanup_cfg (CLEANUP_EXPENSIVE);
timevar_pop (TV_JUMP);
}
reg_scan (get_insns (), max_reg_num ());
close_dump_file (DFI_cse2, print_rtl_with_bb, get_insns ());
timevar_pop (TV_CSE2);
ggc_collect ();
}
static void
rest_of_handle_gcse (void)
{
int save_csb, save_cfj;
int tem2 = 0, tem;
timevar_push (TV_GCSE);
open_dump_file (DFI_gcse, current_function_decl);
tem = gcse_main (get_insns (), dump_file);
rebuild_jump_labels (get_insns ());
delete_trivially_dead_insns (get_insns (), max_reg_num ());
save_csb = flag_cse_skip_blocks;
save_cfj = flag_cse_follow_jumps;
flag_cse_skip_blocks = flag_cse_follow_jumps = 0;
if (flag_expensive_optimizations)
{
timevar_push (TV_CSE);
reg_scan (get_insns (), max_reg_num ());
tem2 = cse_main (get_insns (), max_reg_num (), dump_file);
purge_all_dead_edges (0);
delete_trivially_dead_insns (get_insns (), max_reg_num ());
timevar_pop (TV_CSE);
cse_not_expected = !flag_rerun_cse_after_loop;
}
if (tem || tem2)
{
timevar_push (TV_JUMP);
rebuild_jump_labels (get_insns ());
delete_dead_jumptables ();
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
timevar_pop (TV_JUMP);
}
close_dump_file (DFI_gcse, print_rtl_with_bb, get_insns ());
timevar_pop (TV_GCSE);
ggc_collect ();
flag_cse_skip_blocks = save_csb;
flag_cse_follow_jumps = save_cfj;
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
}
static void
rest_of_handle_loop_optimize (void)
{
int do_prefetch;
timevar_push (TV_LOOP);
open_dump_file (DFI_loop, current_function_decl);
free_bb_for_insn ();
profile_status = PROFILE_ABSENT;
do_prefetch = flag_prefetch_loop_arrays ? LOOP_PREFETCH : 0;
if (flag_rerun_loop_opt)
{
cleanup_barriers ();
loop_optimize (get_insns (), dump_file, 0);
delete_trivially_dead_insns (get_insns (), max_reg_num ());
reg_scan (get_insns (), max_reg_num ());
}
cleanup_barriers ();
loop_optimize (get_insns (), dump_file, do_prefetch);
delete_trivially_dead_insns (get_insns (), max_reg_num ());
find_basic_blocks (get_insns ());
close_dump_file (DFI_loop, print_rtl, get_insns ());
timevar_pop (TV_LOOP);
ggc_collect ();
}
static void
rest_of_handle_loop2 (void)
{
struct loops *loops;
basic_block bb;
if (!flag_move_loop_invariants
&& !flag_unswitch_loops
&& !flag_peel_loops
&& !flag_unroll_loops
&& !flag_branch_on_count_reg)
return;
timevar_push (TV_LOOP);
open_dump_file (DFI_loop2, current_function_decl);
if (dump_file)
dump_flow_info (dump_file);
cfg_layout_initialize (0);
loops = loop_optimizer_init (dump_file);
if (loops)
{
if (flag_move_loop_invariants)
move_loop_invariants (loops);
if (flag_unswitch_loops)
unswitch_loops (loops);
if (flag_peel_loops || flag_unroll_loops)
unroll_and_peel_loops (loops,
(flag_peel_loops ? UAP_PEEL : 0) |
(flag_unroll_loops ? UAP_UNROLL : 0) |
(flag_unroll_all_loops ? UAP_UNROLL_ALL : 0));
#ifdef HAVE_doloop_end
if (flag_branch_on_count_reg && HAVE_doloop_end)
doloop_optimize_loops (loops);
#endif
loop_optimizer_finalize (loops, dump_file);
}
free_dominance_info (CDI_DOMINATORS);
FOR_EACH_BB (bb)
if (bb->next_bb != EXIT_BLOCK_PTR)
bb->rbi->next = bb->next_bb;
cfg_layout_finalize ();
cleanup_cfg (CLEANUP_EXPENSIVE);
delete_trivially_dead_insns (get_insns (), max_reg_num ());
reg_scan (get_insns (), max_reg_num ());
if (dump_file)
dump_flow_info (dump_file);
close_dump_file (DFI_loop2, print_rtl_with_bb, get_insns ());
timevar_pop (TV_LOOP);
ggc_collect ();
}
static void
rest_of_handle_branch_target_load_optimize (void)
{
static int warned = 0;
if (flag_branch_target_load_optimize
&& flag_branch_target_load_optimize2
&& !warned)
{
warning ("branch target register load optimization is not intended "
"to be run twice");
warned = 1;
}
open_dump_file (DFI_branch_target_load, current_function_decl);
branch_target_load_optimize (epilogue_completed);
close_dump_file (DFI_branch_target_load, print_rtl_with_bb, get_insns ());
ggc_collect ();
}
#ifdef OPTIMIZE_MODE_SWITCHING
static void
rest_of_handle_mode_switching (void)
{
timevar_push (TV_MODE_SWITCH);
no_new_pseudos = 0;
optimize_mode_switching (NULL);
no_new_pseudos = 1;
timevar_pop (TV_MODE_SWITCH);
}
#endif
static void
rest_of_handle_jump (void)
{
ggc_collect ();
timevar_push (TV_JUMP);
open_dump_file (DFI_sibling, current_function_decl);
delete_unreachable_blocks ();
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
if (cfun->tail_call_emit)
fixup_tail_calls ();
close_dump_file (DFI_sibling, print_rtl, get_insns ());
timevar_pop (TV_JUMP);
}
static void
rest_of_handle_eh (void)
{
insn_locators_initialize ();
if (doing_eh (0))
{
timevar_push (TV_JUMP);
open_dump_file (DFI_eh, current_function_decl);
cleanup_cfg (CLEANUP_PRE_LOOP | CLEANUP_NO_INSN_DEL);
finish_eh_generation ();
cleanup_cfg (CLEANUP_PRE_LOOP | CLEANUP_NO_INSN_DEL);
close_dump_file (DFI_eh, print_rtl, get_insns ());
timevar_pop (TV_JUMP);
}
}
static void
rest_of_handle_stack_adjustments (void)
{
life_analysis (dump_file, PROP_POSTRELOAD);
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE
| (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
#ifndef PUSH_ROUNDING
if (!ACCUMULATE_OUTGOING_ARGS)
#endif
combine_stack_adjustments ();
}
static void
rest_of_handle_flow2 (void)
{
timevar_push (TV_FLOW2);
open_dump_file (DFI_flow2, current_function_decl);
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
#ifndef STACK_REGS
if (optimize > 0)
#endif
split_all_insns (0);
if (flag_branch_target_load_optimize)
{
close_dump_file (DFI_flow2, print_rtl_with_bb, get_insns ());
rest_of_handle_branch_target_load_optimize ();
open_dump_file (DFI_flow2, current_function_decl);
}
if (optimize)
cleanup_cfg (CLEANUP_EXPENSIVE);
thread_prologue_and_epilogue_insns (get_insns ());
epilogue_completed = 1;
if (optimize)
rest_of_handle_stack_adjustments ();
flow2_completed = 1;
close_dump_file (DFI_flow2, print_rtl_with_bb, get_insns ());
timevar_pop (TV_FLOW2);
ggc_collect ();
}
static void
rest_of_handle_jump2 (void)
{
open_dump_file (DFI_jump, current_function_decl);
timevar_push (TV_JUMP);
if (flag_guess_branch_prob)
expected_value_to_br_prob ();
delete_trivially_dead_insns (get_insns (), max_reg_num ());
reg_scan (get_insns (), max_reg_num ());
if (dump_file)
dump_flow_info (dump_file);
cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_PRE_LOOP
| (flag_thread_jumps ? CLEANUP_THREADING : 0));
create_loop_notes ();
purge_line_number_notes (get_insns ());
if (optimize)
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
renumber_insns (dump_file);
close_dump_file (DFI_jump, print_rtl_with_bb, get_insns ());
timevar_pop (TV_JUMP);
ggc_collect ();
}
#ifdef HAVE_peephole2
static void
rest_of_handle_peephole2 (void)
{
timevar_push (TV_PEEPHOLE2);
open_dump_file (DFI_peephole2, current_function_decl);
peephole2_optimize (dump_file);
close_dump_file (DFI_peephole2, print_rtl_with_bb, get_insns ());
timevar_pop (TV_PEEPHOLE2);
}
#endif
static void
rest_of_handle_postreload (void)
{
timevar_push (TV_RELOAD_CSE_REGS);
open_dump_file (DFI_postreload, current_function_decl);
reload_cse_regs (get_insns ());
if (flag_non_call_exceptions)
purge_all_dead_edges (0);
close_dump_file (DFI_postreload, print_rtl_with_bb, get_insns ());
timevar_pop (TV_RELOAD_CSE_REGS);
}
static void
rest_of_handle_shorten_branches (void)
{
timevar_push (TV_SHORTEN_BRANCH);
shorten_branches (get_insns ());
timevar_pop (TV_SHORTEN_BRANCH);
}
static void
rest_of_clean_state (void)
{
rtx insn, next;
coverage_end_function ();
for (insn = get_insns (); insn; insn = next)
{
next = NEXT_INSN (insn);
NEXT_INSN (insn) = NULL;
PREV_INSN (insn) = NULL;
}
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG)
sdbout_types (NULL_TREE);
#endif
reload_completed = 0;
epilogue_completed = 0;
flow2_completed = 0;
no_new_pseudos = 0;
timevar_push (TV_FINAL);
init_insn_lengths ();
init_temp_slots ();
free_basic_block_vars ();
free_bb_for_insn ();
timevar_pop (TV_FINAL);
if (targetm.binds_local_p (current_function_decl))
{
int pref = cfun->preferred_stack_boundary;
if (cfun->stack_alignment_needed > cfun->preferred_stack_boundary)
pref = cfun->stack_alignment_needed;
cgraph_rtl_info (current_function_decl)->preferred_incoming_stack_boundary
= pref;
}
init_recog_no_volatile ();
free_after_parsing (cfun);
free_after_compilation (cfun);
}
static void
rest_of_compilation (void)
{
#ifdef TARGET_386
unsigned int save_PREFERRED_STACK_BOUNDARY = 0;
#endif
{
tree parent;
for (parent = DECL_CONTEXT (current_function_decl);
parent != NULL_TREE;
parent = get_containing_scope (parent))
if (TREE_CODE (parent) == FUNCTION_DECL)
TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (parent)) = 1;
}
if (cgraph_function_possibly_inlined_p (current_function_decl))
(*debug_hooks->outlining_inline_function) (current_function_decl);
remove_unnecessary_notes ();
init_function_for_compilation ();
TREE_ASM_WRITTEN (current_function_decl) = 1;
if (rtl_dump_and_exit || flag_syntax_only || errorcount || sorrycount)
goto exit_rest_of_compilation;
rest_of_handle_jump ();
rest_of_handle_eh ();
emit_initial_value_sets ();
#ifdef FINALIZE_PIC
if (flag_pic)
FINALIZE_PIC;
#endif
unshare_all_rtl ();
#ifdef SETJMP_VIA_SAVE_AREA
if (current_function_calls_alloca)
optimize_save_area_alloca ();
#endif
instantiate_virtual_regs ();
rest_of_handle_jump2 ();
if (optimize > 0)
rest_of_handle_cse ();
if (optimize > 0)
{
if (flag_gcse)
rest_of_handle_gcse ();
if (flag_loop_optimize)
rest_of_handle_loop_optimize ();
if (flag_gcse)
rest_of_handle_jump_bypass ();
}
timevar_push (TV_FLOW);
rest_of_handle_cfg ();
if (!flag_tree_based_profiling
&& (optimize > 0 || profile_arc_flag
|| flag_test_coverage || flag_branch_probabilities))
{
rtl_register_profile_hooks ();
rtl_register_value_prof_hooks ();
rest_of_handle_branch_prob ();
if (flag_branch_probabilities
&& flag_profile_values
&& (flag_value_profile_transformations
|| flag_speculative_prefetching))
rest_of_handle_value_profile_transformations ();
if (flag_profile_values)
count_or_remove_death_notes (NULL, 1);
}
if (optimize > 0)
rest_of_handle_if_conversion ();
if (optimize > 0 && flag_tracer)
rest_of_handle_tracer ();
if (optimize > 0
&& flag_loop_optimize2)
rest_of_handle_loop2 ();
if (optimize > 0 && flag_web)
rest_of_handle_web ();
if (optimize > 0 && flag_rerun_cse_after_loop)
rest_of_handle_cse2 ();
cse_not_expected = 1;
rest_of_handle_life ();
timevar_pop (TV_FLOW);
if (optimize > 0)
rest_of_handle_combine ();
if (optimize > 0 && flag_if_conversion)
rest_of_handle_if_after_combine ();
if (flag_reorder_blocks_and_partition
&& !DECL_ONE_ONLY (current_function_decl)
&& !user_defined_section_attribute)
rest_of_handle_partition_blocks ();
if (optimize > 0 && flag_regmove)
rest_of_handle_regmove ();
split_all_insns (1);
#ifdef OPTIMIZE_MODE_SWITCHING
rest_of_handle_mode_switching ();
#endif
recompute_reg_usage ();
#ifdef INSN_SCHEDULING
if (optimize > 0 && flag_modulo_sched)
rest_of_handle_sms ();
if (flag_schedule_insns)
rest_of_handle_sched ();
#endif
current_function_is_leaf = leaf_function_p ();
#ifdef TARGET_386
if ((optimize > 0 || optimize_size)
&& current_function_is_leaf
&& PREFERRED_STACK_BOUNDARY >= 128
&& !DECL_STRUCT_FUNCTION (current_function_decl)->uses_vector)
{
save_PREFERRED_STACK_BOUNDARY = PREFERRED_STACK_BOUNDARY;
PREFERRED_STACK_BOUNDARY = 32;
cfun->stack_alignment_needed = STACK_BOUNDARY;
cfun->preferred_stack_boundary = STACK_BOUNDARY;
}
#endif
if (rest_of_handle_old_regalloc ())
goto exit_rest_of_compilation;
if (optimize > 0)
rest_of_handle_postreload ();
if (optimize > 0 && flag_gcse_after_reload)
rest_of_handle_gcse2 ();
rest_of_handle_flow2 ();
#ifdef HAVE_peephole2
if (optimize > 0 && flag_peephole2)
rest_of_handle_peephole2 ();
#endif
if (optimize > 0)
rest_of_handle_if_after_reload ();
if (optimize > 0)
{
if (flag_rename_registers || flag_cprop_registers)
rest_of_handle_regrename ();
rest_of_handle_reorder_blocks ();
}
if (flag_branch_target_load_optimize2)
rest_of_handle_branch_target_load_optimize ();
#ifdef LEAF_REGISTERS
current_function_uses_only_leaf_regs
= optimize > 0 && only_leaf_regs_used () && leaf_function_p ();
#endif
#ifdef INSN_SCHEDULING
if (optimize > 0 && flag_schedule_insns_after_reload)
rest_of_handle_sched2 ();
#endif
#ifdef STACK_REGS
rest_of_handle_stack_regs ();
#endif
compute_alignments ();
if (flag_expensive_optimizations && !optimize_size)
duplicate_computed_gotos ();
if (flag_var_tracking)
rest_of_handle_variable_tracking ();
free_bb_for_insn ();
if (targetm.machine_dependent_reorg != 0)
rest_of_handle_machine_reorg ();
purge_line_number_notes (get_insns ());
cleanup_barriers ();
#ifdef DELAY_SLOTS
if (flag_delayed_branch)
rest_of_handle_delay_slots ();
#endif
#if defined (HAVE_ATTR_length) && !defined (STACK_REGS)
timevar_push (TV_SHORTEN_BRANCH);
split_all_insns_noflow ();
timevar_pop (TV_SHORTEN_BRANCH);
#endif
convert_to_eh_region_ranges ();
rest_of_handle_shorten_branches ();
set_nothrow_function_flags ();
rest_of_handle_final ();
exit_rest_of_compilation:
#ifdef TARGET_386
if (save_PREFERRED_STACK_BOUNDARY > 0)
{
PREFERRED_STACK_BOUNDARY = save_PREFERRED_STACK_BOUNDARY;
cfun->stack_alignment_needed = STACK_BOUNDARY;
cfun->preferred_stack_boundary = STACK_BOUNDARY;
}
#endif
rest_of_clean_state ();
}
void
finish_optimization_passes (void)
{
enum tree_dump_index i;
struct dump_file_info *dfi;
char *name;
timevar_push (TV_DUMP);
if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
{
open_dump_file (DFI_bp, NULL);
end_branch_prob ();
close_dump_file (DFI_bp, NULL, NULL_RTX);
}
if (optimize > 0 && open_dump_file (DFI_combine, NULL))
{
dump_combine_total_stats (dump_file);
close_dump_file (DFI_combine, NULL, NULL_RTX);
}
if (graph_dump_format != no_graph)
for (i = DFI_MIN; (dfi = get_dump_file_info (i)) != NULL; ++i)
if (dump_initialized_p (i)
&& (dfi->flags & TDF_RTL) != 0
&& (name = get_dump_file_name (i)) != NULL)
{
finish_graph_dump_file (name);
free (name);
}
timevar_pop (TV_DUMP);
}
struct tree_opt_pass pass_rest_of_compilation =
{
NULL,
NULL,
rest_of_compilation,
NULL,
NULL,
0,
TV_REST_OF_COMPILATION,
PROP_rtl,
0,
PROP_rtl,
0,
TODO_ggc_collect,
0
};