#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 "loop.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"
#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
struct dump_file_info
{
const char *const extension;
char const debug_switch;
char const graph_dump_p;
char enabled;
char initialized;
};
enum dump_file_index
{
DFI_cgraph,
DFI_rtl,
DFI_sibling,
DFI_eh,
DFI_jump,
DFI_null,
DFI_cse,
DFI_addressof,
DFI_gcse,
DFI_loop,
DFI_bypass,
DFI_cfg,
DFI_bp,
DFI_vpt,
DFI_ce1,
DFI_tracer,
DFI_loop2,
DFI_web,
DFI_cse2,
DFI_life,
DFI_combine,
DFI_ce2,
DFI_regmove,
DFI_sms,
DFI_sched,
DFI_lreg,
DFI_greg,
DFI_postreload,
DFI_gcse2,
DFI_flow2,
DFI_peephole2,
DFI_ce3,
DFI_rnreg,
DFI_bbro,
DFI_branch_target_load,
DFI_sched2,
DFI_stack,
DFI_vartrack,
DFI_mach,
DFI_dbr,
DFI_MAX
};
static struct dump_file_info dump_file_tbl[DFI_MAX] =
{
{ "cgraph", 'U', 0, 0, 0 },
{ "rtl", 'r', 0, 0, 0 },
{ "sibling", 'i', 0, 0, 0 },
{ "eh", 'h', 0, 0, 0 },
{ "jump", 'j', 0, 0, 0 },
{ "null", 'u', 0, 0, 0 },
{ "cse", 's', 0, 0, 0 },
{ "addressof", 'F', 0, 0, 0 },
{ "gcse", 'G', 1, 0, 0 },
{ "loop", 'L', 1, 0, 0 },
{ "bypass", 'G', 1, 0, 0 },
{ "cfg", 'f', 1, 0, 0 },
{ "bp", 'b', 1, 0, 0 },
{ "vpt", 'V', 1, 0, 0 },
{ "ce1", 'C', 1, 0, 0 },
{ "tracer", 'T', 1, 0, 0 },
{ "loop2", 'L', 1, 0, 0 },
{ "web", 'Z', 0, 0, 0 },
{ "cse2", 't', 1, 0, 0 },
{ "life", 'f', 1, 0, 0 },
{ "combine", 'c', 1, 0, 0 },
{ "ce2", 'C', 1, 0, 0 },
{ "regmove", 'N', 1, 0, 0 },
{ "sms", 'm', 0, 0, 0 },
{ "sched", 'S', 1, 0, 0 },
{ "lreg", 'l', 1, 0, 0 },
{ "greg", 'g', 1, 0, 0 },
{ "postreload", 'o', 1, 0, 0 },
{ "gcse2", 'J', 0, 0, 0 },
{ "flow2", 'w', 1, 0, 0 },
{ "peephole2", 'z', 1, 0, 0 },
{ "ce3", 'E', 1, 0, 0 },
{ "rnreg", 'n', 1, 0, 0 },
{ "bbro", 'B', 1, 0, 0 },
{ "btl", 'd', 1, 0, 0 },
{ "sched2", 'R', 1, 0, 0 },
{ "stack", 'k', 1, 0, 0 },
{ "vartrack", 'V', 1, 0, 0 },
{ "mach", 'M', 1, 0, 0 },
{ "dbr", 'd', 0, 0, 0 },
};
static int
open_dump_file (enum dump_file_index index, tree decl)
{
char *dump_name;
const char *open_arg;
char seq[16];
if (! dump_file_tbl[index].enabled)
return 0;
timevar_push (TV_DUMP);
if (dump_file != NULL)
fclose (dump_file);
sprintf (seq, DUMPFILE_FORMAT, index);
if (! dump_file_tbl[index].initialized)
{
if (graph_dump_format != no_graph
&& dump_file_tbl[index].graph_dump_p)
{
dump_name = concat (seq, dump_file_tbl[index].extension, NULL);
clean_graph_dump_file (dump_base_name, dump_name);
free (dump_name);
}
dump_file_tbl[index].initialized = 1;
open_arg = "w";
}
else
open_arg = "a";
dump_name = concat (dump_base_name, seq,
dump_file_tbl[index].extension, NULL);
dump_file = fopen (dump_name, open_arg);
if (dump_file == NULL)
fatal_error ("can't open %s: %m", dump_name);
free (dump_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 dump_file_index index,
void (*func) (FILE *, rtx),
rtx insns)
{
if (! dump_file)
return;
timevar_push (TV_DUMP);
if (insns
&& graph_dump_format != no_graph
&& dump_file_tbl[index].graph_dump_p)
{
char seq[16];
char *suffix;
sprintf (seq, DUMPFILE_FORMAT, index);
suffix = concat (seq, dump_file_tbl[index].extension, NULL);
print_rtl_graph_with_bb (dump_base_name, suffix, insns);
free (suffix);
}
if (func && insns)
func (dump_file, insns);
fflush (dump_file);
fclose (dump_file);
dump_file = NULL;
timevar_pop (TV_DUMP);
}
void
rest_of_decl_compilation (tree decl,
const char *asmspec,
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 (TREE_STATIC (decl) || DECL_EXTERNAL (decl)
|| TREE_CODE (decl) == FUNCTION_DECL)
{
timevar_push (TV_VARCONST);
if (asmspec)
make_decl_rtl (decl, asmspec);
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 (DECL_REGISTER (decl) && asmspec != 0)
{
if (decode_reg_name (asmspec) >= 0)
{
SET_DECL_RTL (decl, NULL_RTX);
make_decl_rtl (decl, asmspec);
}
else
{
error ("%Hinvalid register name `%s' for register variable",
&DECL_SOURCE_LOCATION (decl), asmspec);
DECL_REGISTER (decl) = 0;
if (!top_level)
expand_decl (decl);
}
}
else if (TREE_CODE (decl) == TYPE_DECL)
{
timevar_push (TV_SYMOUT);
debug_hooks->type_decl (decl, !top_level);
timevar_pop (TV_SYMOUT);
}
}
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 (tree decl, rtx insns)
{
timevar_push (TV_FINAL);
{
rtx x;
const char *fnname;
x = DECL_RTL (decl);
if (GET_CODE (x) != MEM)
abort ();
x = XEXP (x, 0);
if (GET_CODE (x) != SYMBOL_REF)
abort ();
fnname = XSTR (x, 0);
assemble_start_function (decl, fnname);
final_start_function (insns, asm_out_file, optimize);
final (insns, asm_out_file, optimize, 0);
final_end_function ();
#ifdef IA64_UNWIND_INFO
output_function_exception_table ();
#endif
assemble_end_function (decl, fnname);
#ifndef IA64_UNWIND_INFO
output_function_exception_table ();
#endif
if (! quiet_flag)
fflush (asm_out_file);
free_basic_block_vars ();
regset_release_memory ();
}
timevar_pop (TV_FINAL);
ggc_collect ();
}
#ifdef DELAY_SLOTS
static void
rest_of_handle_delay_slots (tree decl, rtx insns)
{
timevar_push (TV_DBR_SCHED);
open_dump_file (DFI_dbr, decl);
dbr_schedule (insns, dump_file);
close_dump_file (DFI_dbr, print_rtl, insns);
timevar_pop (TV_DBR_SCHED);
ggc_collect ();
}
#endif
#ifdef STACK_REGS
static void
rest_of_handle_stack_regs (tree decl, rtx insns)
{
#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, 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 ();
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_POST_REGSTACK);
}
}
close_dump_file (DFI_stack, print_rtl_with_bb, insns);
timevar_pop (TV_REG_STACK);
ggc_collect ();
}
#endif
static void
rest_of_handle_variable_tracking (tree decl, rtx insns)
{
timevar_push (TV_VAR_TRACKING);
open_dump_file (DFI_vartrack, decl);
variable_tracking_main ();
close_dump_file (DFI_vartrack, print_rtl_with_bb, insns);
timevar_pop (TV_VAR_TRACKING);
}
static void
rest_of_handle_machine_reorg (tree decl, rtx insns)
{
timevar_push (TV_MACH_DEP);
open_dump_file (DFI_mach, decl);
targetm.machine_dependent_reorg ();
close_dump_file (DFI_mach, print_rtl, insns);
timevar_pop (TV_MACH_DEP);
ggc_collect ();
}
static bool
rest_of_handle_new_regalloc (tree decl, rtx insns)
{
int failure;
delete_trivially_dead_insns (insns, max_reg_num ());
reg_alloc ();
timevar_pop (TV_LOCAL_ALLOC);
if (dump_file_tbl[DFI_lreg].enabled)
{
timevar_push (TV_DUMP);
close_dump_file (DFI_lreg, NULL, NULL);
timevar_pop (TV_DUMP);
}
timevar_push (TV_GLOBAL_ALLOC);
open_dump_file (DFI_greg, decl);
build_insn_chain (insns);
failure = reload (insns, 0);
timevar_pop (TV_GLOBAL_ALLOC);
if (dump_file_tbl[DFI_greg].enabled)
{
timevar_push (TV_DUMP);
dump_global_regs (dump_file);
close_dump_file (DFI_greg, print_rtl_with_bb, insns);
timevar_pop (TV_DUMP);
}
if (failure)
return true;
reload_completed = 1;
return false;
}
static bool
rest_of_handle_old_regalloc (tree decl, rtx insns)
{
int failure;
int rebuild_notes;
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 (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 (insns);
purge_all_dead_edges (0);
timevar_pop (TV_JUMP);
}
if (dump_file_tbl[DFI_lreg].enabled)
{
timevar_push (TV_DUMP);
dump_flow_info (dump_file);
dump_local_alloc (dump_file);
close_dump_file (DFI_lreg, print_rtl_with_bb, insns);
timevar_pop (TV_DUMP);
}
ggc_collect ();
timevar_push (TV_GLOBAL_ALLOC);
open_dump_file (DFI_greg, decl);
if (optimize)
failure = global_alloc (dump_file);
else
{
build_insn_chain (insns);
failure = reload (insns, 0);
}
timevar_pop (TV_GLOBAL_ALLOC);
if (dump_file_tbl[DFI_greg].enabled)
{
timevar_push (TV_DUMP);
dump_global_regs (dump_file);
close_dump_file (DFI_greg, print_rtl_with_bb, insns);
timevar_pop (TV_DUMP);
}
return failure;
}
static void
rest_of_handle_regrename (tree decl, rtx insns)
{
timevar_push (TV_RENAME_REGISTERS);
open_dump_file (DFI_rnreg, decl);
if (flag_rename_registers)
regrename_optimize ();
if (flag_cprop_registers)
copyprop_hardreg_forward ();
close_dump_file (DFI_rnreg, print_rtl_with_bb, insns);
timevar_pop (TV_RENAME_REGISTERS);
}
static void
rest_of_handle_reorder_blocks (tree decl, rtx insns)
{
bool changed;
open_dump_file (DFI_bbro, decl);
changed = cleanup_cfg (CLEANUP_EXPENSIVE
| (!HAVE_conditional_execution
? CLEANUP_UPDATE_LIFE : 0));
if (flag_sched2_use_traces && flag_schedule_insns_after_reload)
tracer ();
if (flag_reorder_blocks || flag_reorder_blocks_and_partition)
reorder_basic_blocks ();
if (flag_reorder_blocks || flag_reorder_blocks_and_partition
|| (flag_sched2_use_traces && flag_schedule_insns_after_reload))
changed |= cleanup_cfg (CLEANUP_EXPENSIVE
| (!HAVE_conditional_execution
? CLEANUP_UPDATE_LIFE : 0));
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, insns);
}
#ifdef INSN_SCHEDULING
static void
rest_of_handle_sched (tree decl, rtx insns)
{
timevar_push (TV_SMS);
if (optimize > 0 && flag_modulo_sched)
{
open_dump_file (DFI_sms, 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);
update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
(PROP_DEATH_NOTES
| PROP_KILL_DEAD_CODE
| PROP_SCAN_DEAD_CODE));
no_new_pseudos = 1;
}
timevar_pop (TV_SMS);
timevar_push (TV_SCHED);
if (optimize > 0 && flag_schedule_insns)
{
open_dump_file (DFI_sched, decl);
schedule_insns (dump_file);
close_dump_file (DFI_sched, print_rtl_with_bb, insns);
}
timevar_pop (TV_SCHED);
ggc_collect ();
}
static void
rest_of_handle_sched2 (tree decl, rtx insns)
{
timevar_push (TV_SCHED2);
open_dump_file (DFI_sched2, 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, insns);
timevar_pop (TV_SCHED2);
ggc_collect ();
}
#endif
static void
rest_of_handle_gcse2 (tree decl, rtx insns)
{
open_dump_file (DFI_gcse2, decl);
gcse_after_reload_main (insns, dump_file);
rebuild_jump_labels (insns);
delete_trivially_dead_insns (insns, max_reg_num ());
close_dump_file (DFI_gcse2, print_rtl_with_bb, insns);
ggc_collect ();
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
}
static void
rest_of_handle_regmove (tree decl, rtx insns)
{
timevar_push (TV_REGMOVE);
open_dump_file (DFI_regmove, decl);
regmove_optimize (insns, max_reg_num (), dump_file);
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
close_dump_file (DFI_regmove, print_rtl_with_bb, insns);
timevar_pop (TV_REGMOVE);
ggc_collect ();
}
static void
rest_of_handle_tracer (tree decl, rtx insns)
{
open_dump_file (DFI_tracer, decl);
if (dump_file)
dump_flow_info (dump_file);
tracer ();
cleanup_cfg (CLEANUP_EXPENSIVE);
reg_scan (insns, max_reg_num (), 0);
close_dump_file (DFI_tracer, print_rtl_with_bb, get_insns ());
}
static void
rest_of_handle_if_conversion (tree decl, rtx insns)
{
open_dump_file (DFI_ce1, decl);
if (flag_if_conversion)
{
timevar_push (TV_IFCVT);
if (dump_file)
dump_flow_info (dump_file);
cleanup_cfg (CLEANUP_EXPENSIVE);
reg_scan (insns, max_reg_num (), 0);
if_convert (0);
timevar_pop (TV_IFCVT);
}
timevar_push (TV_JUMP);
cleanup_cfg (CLEANUP_EXPENSIVE);
reg_scan (insns, max_reg_num (), 0);
timevar_pop (TV_JUMP);
close_dump_file (DFI_ce1, print_rtl_with_bb, get_insns ());
}
static void
rest_of_handle_if_after_combine (tree decl, rtx insns)
{
timevar_push (TV_IFCVT);
open_dump_file (DFI_ce2, decl);
no_new_pseudos = 0;
if_convert (1);
no_new_pseudos = 1;
close_dump_file (DFI_ce2, print_rtl_with_bb, insns);
timevar_pop (TV_IFCVT);
}
static void
rest_of_handle_web (tree decl, rtx insns)
{
open_dump_file (DFI_web, decl);
timevar_push (TV_WEB);
web_main ();
delete_trivially_dead_insns (insns, max_reg_num ());
cleanup_cfg (CLEANUP_EXPENSIVE);
timevar_pop (TV_WEB);
close_dump_file (DFI_web, print_rtl_with_bb, insns);
reg_scan (get_insns (), max_reg_num (), 0);
}
static void
rest_of_handle_branch_prob (tree decl, rtx insns)
{
struct loops loops;
timevar_push (TV_BRANCH_PROB);
open_dump_file (DFI_bp, 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, insns);
timevar_pop (TV_BRANCH_PROB);
}
static void
rest_of_handle_value_profile_transformations (tree decl, rtx insns)
{
open_dump_file (DFI_vpt, 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, insns);
}
static void
rest_of_handle_cfg (tree decl, rtx insns)
{
open_dump_file (DFI_cfg, decl);
if (dump_file)
dump_flow_info (dump_file);
if (optimize)
cleanup_cfg (CLEANUP_EXPENSIVE
| (flag_thread_jumps ? CLEANUP_THREADING : 0));
if (optimize)
{
reg_scan (insns, max_reg_num (), 1);
mark_constant_function ();
}
close_dump_file (DFI_cfg, print_rtl_with_bb, insns);
}
static void
rest_of_handle_addressof (tree decl, rtx insns)
{
open_dump_file (DFI_addressof, decl);
purge_addressof (insns);
if (optimize && purge_all_dead_edges (0))
delete_unreachable_blocks ();
reg_scan (insns, max_reg_num (), 1);
close_dump_file (DFI_addressof, print_rtl, insns);
}
static void
rest_of_handle_jump_bypass (tree decl, rtx insns)
{
timevar_push (TV_BYPASS);
open_dump_file (DFI_bypass, decl);
cleanup_cfg (CLEANUP_EXPENSIVE);
reg_scan (insns, max_reg_num (), 1);
if (bypass_jumps (dump_file))
{
rebuild_jump_labels (insns);
cleanup_cfg (CLEANUP_EXPENSIVE);
delete_trivially_dead_insns (insns, max_reg_num ());
}
close_dump_file (DFI_bypass, print_rtl_with_bb, insns);
timevar_pop (TV_BYPASS);
ggc_collect ();
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
}
static void
rest_of_handle_combine (tree decl, rtx insns)
{
int rebuild_jump_labels_after_combine = 0;
timevar_push (TV_COMBINE);
open_dump_file (DFI_combine, decl);
rebuild_jump_labels_after_combine
= combine_instructions (insns, max_reg_num ());
if (rebuild_jump_labels_after_combine)
{
timevar_push (TV_JUMP);
rebuild_jump_labels (insns);
timevar_pop (TV_JUMP);
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
}
close_dump_file (DFI_combine, print_rtl_with_bb, insns);
timevar_pop (TV_COMBINE);
ggc_collect ();
}
static void
rest_of_handle_life (tree decl, rtx insns)
{
open_dump_file (DFI_life, decl);
regclass_init ();
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
life_analysis (dump_file, PROP_FINAL);
if (optimize)
cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_UPDATE_LIFE
| CLEANUP_LOG_LINKS
| (flag_thread_jumps ? CLEANUP_THREADING : 0));
timevar_pop (TV_FLOW);
if (extra_warnings)
{
setjmp_vars_warning (DECL_INITIAL (decl));
setjmp_args_warning ();
}
if (optimize)
{
if (!flag_new_regalloc && initialize_uninitialized_subregs ())
{
insns = get_insns ();
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, insns);
ggc_collect ();
}
static void
rest_of_handle_cse (tree decl, rtx insns)
{
int tem;
open_dump_file (DFI_cse, decl);
if (dump_file)
dump_flow_info (dump_file);
timevar_push (TV_CSE);
reg_scan (insns, max_reg_num (), 1);
tem = cse_main (insns, max_reg_num (), 0, dump_file);
if (tem)
rebuild_jump_labels (insns);
if (purge_all_dead_edges (0))
delete_unreachable_blocks ();
delete_trivially_dead_insns (insns, max_reg_num ());
cse_not_expected = !flag_rerun_cse_after_loop && !flag_gcse;
if (tem || optimize > 1)
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
timevar_pop (TV_CSE);
close_dump_file (DFI_cse, print_rtl_with_bb, insns);
}
static void
rest_of_handle_cse2 (tree decl, rtx insns)
{
int tem;
timevar_push (TV_CSE2);
open_dump_file (DFI_cse2, decl);
if (dump_file)
dump_flow_info (dump_file);
tem = cse_main (insns, max_reg_num (), 1, dump_file);
cse_condition_code_reg ();
purge_all_dead_edges (0);
delete_trivially_dead_insns (insns, max_reg_num ());
if (tem)
{
timevar_push (TV_JUMP);
rebuild_jump_labels (insns);
cleanup_cfg (CLEANUP_EXPENSIVE);
timevar_pop (TV_JUMP);
}
reg_scan (insns, max_reg_num (), 0);
close_dump_file (DFI_cse2, print_rtl_with_bb, insns);
ggc_collect ();
timevar_pop (TV_CSE2);
}
static void
rest_of_handle_gcse (tree decl, rtx insns)
{
int save_csb, save_cfj;
int tem2 = 0, tem;
timevar_push (TV_GCSE);
open_dump_file (DFI_gcse, decl);
tem = gcse_main (insns, dump_file);
rebuild_jump_labels (insns);
delete_trivially_dead_insns (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 (insns, max_reg_num (), 1);
tem2 = cse_main (insns, max_reg_num (), 0, dump_file);
purge_all_dead_edges (0);
delete_trivially_dead_insns (insns, max_reg_num ());
timevar_pop (TV_CSE);
cse_not_expected = !flag_rerun_cse_after_loop;
}
while (tem || tem2)
{
tem = tem2 = 0;
timevar_push (TV_JUMP);
rebuild_jump_labels (insns);
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
timevar_pop (TV_JUMP);
if (flag_expensive_optimizations)
{
timevar_push (TV_CSE);
reg_scan (insns, max_reg_num (), 1);
tem2 = cse_main (insns, max_reg_num (), 0, dump_file);
purge_all_dead_edges (0);
delete_trivially_dead_insns (insns, max_reg_num ());
timevar_pop (TV_CSE);
}
}
close_dump_file (DFI_gcse, print_rtl_with_bb, 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 (tree decl, rtx insns)
{
int do_unroll, do_prefetch;
timevar_push (TV_LOOP);
delete_dead_jumptables ();
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
open_dump_file (DFI_loop, decl);
free_bb_for_insn ();
do_unroll = flag_unroll_loops ? LOOP_UNROLL : LOOP_AUTO_UNROLL;
do_prefetch = flag_prefetch_loop_arrays ? LOOP_PREFETCH : 0;
if (flag_rerun_loop_opt)
{
cleanup_barriers ();
loop_optimize (insns, dump_file, do_unroll);
do_unroll = 0;
delete_trivially_dead_insns (insns, max_reg_num ());
reg_scan (insns, max_reg_num (), 1);
}
cleanup_barriers ();
loop_optimize (insns, dump_file, do_unroll | do_prefetch);
delete_trivially_dead_insns (insns, max_reg_num ());
close_dump_file (DFI_loop, print_rtl, insns);
timevar_pop (TV_LOOP);
find_basic_blocks (insns, max_reg_num (), dump_file);
ggc_collect ();
}
static void
rest_of_handle_loop2 (tree decl, rtx insns)
{
struct loops *loops;
basic_block bb;
if (!flag_unswitch_loops
&& !flag_peel_loops
&& !flag_unroll_loops
&& !flag_branch_on_count_reg)
return;
timevar_push (TV_LOOP);
open_dump_file (DFI_loop2, decl);
if (dump_file)
dump_flow_info (dump_file);
cfg_layout_initialize ();
loops = loop_optimizer_init (dump_file);
if (loops)
{
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);
}
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 (insns, max_reg_num ());
reg_scan (insns, max_reg_num (), 0);
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 ();
}
void
rest_of_compilation (tree decl)
{
rtx insns;
timevar_push (TV_REST_OF_COMPILATION);
rtl_register_cfg_hooks ();
generating_concat_p = 0;
cse_not_expected = ! optimize;
if (!cfun->dont_emit_block_notes)
{
if (!cfun->x_whole_function_mode_p)
identify_blocks ();
if (cfun->x_whole_function_mode_p)
reorder_blocks ();
}
else
finalize_block_changes ();
init_flow ();
if (open_dump_file (DFI_rtl, decl))
close_dump_file (DFI_rtl, print_rtl, get_insns ());
convert_from_eh_region_ranges ();
{
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 (decl))
(*debug_hooks->outlining_inline_function) (decl);
remove_unnecessary_notes ();
if (!cfun->dont_emit_block_notes)
reorder_blocks ();
ggc_collect ();
init_function_for_compilation ();
if (! DECL_DEFER_OUTPUT (decl))
TREE_ASM_WRITTEN (decl) = 1;
rtx_equal_function_value_matters = 0;
purge_hard_subreg_sets (get_insns ());
if (((rtl_dump_and_exit || flag_syntax_only) && !warn_return_type)
|| errorcount || sorrycount)
goto exit_rest_of_compilation;
timevar_push (TV_JUMP);
open_dump_file (DFI_sibling, decl);
insns = get_insns ();
rebuild_jump_labels (insns);
find_exception_handler_labels ();
find_basic_blocks (insns, max_reg_num (), dump_file);
delete_unreachable_blocks ();
if (flag_guess_branch_prob)
{
timevar_push (TV_BRANCH_PROB);
note_prediction_to_br_prob ();
timevar_pop (TV_BRANCH_PROB);
}
timevar_pop (TV_JUMP);
if (cfun->tail_call_emit)
fixup_tail_calls ();
insn_locators_initialize ();
if (doing_eh (0))
{
timevar_push (TV_JUMP);
open_dump_file (DFI_eh, decl);
finish_eh_generation ();
close_dump_file (DFI_eh, print_rtl, get_insns ());
timevar_pop (TV_JUMP);
}
emit_initial_value_sets ();
#ifdef FINALIZE_PIC
if (flag_pic)
FINALIZE_PIC;
#endif
insns = get_insns ();
unshare_all_rtl (current_function_decl, insns);
#ifdef SETJMP_VIA_SAVE_AREA
if (current_function_calls_alloca)
optimize_save_area_alloca (insns);
#endif
instantiate_virtual_regs (current_function_decl, insns);
open_dump_file (DFI_jump, decl);
timevar_push (TV_JUMP);
if (flag_guess_branch_prob)
expected_value_to_br_prob ();
reg_scan (insns, max_reg_num (), 0);
rebuild_jump_labels (insns);
find_basic_blocks (insns, max_reg_num (), dump_file);
delete_trivially_dead_insns (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 (insns);
timevar_pop (TV_JUMP);
close_dump_file (DFI_jump, print_rtl, insns);
if (rtl_dump_and_exit || flag_syntax_only || DECL_DEFER_OUTPUT (decl))
goto exit_rest_of_compilation;
timevar_push (TV_JUMP);
if (optimize)
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
renumber_insns (dump_file);
timevar_pop (TV_JUMP);
close_dump_file (DFI_jump, print_rtl_with_bb, insns);
ggc_collect ();
if (optimize > 0)
rest_of_handle_cse (decl, insns);
rest_of_handle_addressof (decl, insns);
ggc_collect ();
if (optimize > 0)
{
if (flag_gcse)
rest_of_handle_gcse (decl, insns);
if (flag_loop_optimize)
rest_of_handle_loop_optimize (decl, insns);
if (flag_gcse)
rest_of_handle_jump_bypass (decl, insns);
}
timevar_push (TV_FLOW);
rest_of_handle_cfg (decl, insns);
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 (decl, insns);
if (flag_branch_probabilities
&& flag_profile_values
&& flag_value_profile_transformations)
rest_of_handle_value_profile_transformations (decl, insns);
if (flag_profile_values)
count_or_remove_death_notes (NULL, 1);
}
if (optimize > 0)
rest_of_handle_if_conversion (decl, insns);
if (flag_tracer)
rest_of_handle_tracer (decl, insns);
if (optimize > 0
&& flag_loop_optimize2)
rest_of_handle_loop2 (decl, insns);
if (flag_web)
rest_of_handle_web (decl, insns);
if (flag_rerun_cse_after_loop)
rest_of_handle_cse2 (decl, insns);
cse_not_expected = 1;
rest_of_handle_life (decl, insns);
if (optimize > 0)
rest_of_handle_combine (decl, insns);
if (flag_if_conversion)
rest_of_handle_if_after_combine (decl, insns);
if (flag_reorder_blocks_and_partition)
{
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;
}
if (optimize > 0 && (flag_regmove || flag_expensive_optimizations))
rest_of_handle_regmove (decl, insns);
split_all_insns (1);
#ifdef OPTIMIZE_MODE_SWITCHING
timevar_push (TV_MODE_SWITCH);
no_new_pseudos = 0;
optimize_mode_switching (NULL);
no_new_pseudos = 1;
timevar_pop (TV_MODE_SWITCH);
#endif
recompute_reg_usage (insns, !optimize_size);
#ifdef INSN_SCHEDULING
rest_of_handle_sched (decl, insns);
#endif
current_function_is_leaf = leaf_function_p ();
timevar_push (TV_LOCAL_ALLOC);
open_dump_file (DFI_lreg, decl);
if (flag_new_regalloc)
{
if (rest_of_handle_new_regalloc (decl, insns))
goto exit_rest_of_compilation;
}
else
{
if (rest_of_handle_old_regalloc (decl, insns))
goto exit_rest_of_compilation;
}
ggc_collect ();
open_dump_file (DFI_postreload, decl);
if (optimize > 0)
{
timevar_push (TV_RELOAD_CSE_REGS);
reload_cse_regs (insns);
if (flag_non_call_exceptions)
purge_all_dead_edges (0);
timevar_pop (TV_RELOAD_CSE_REGS);
}
close_dump_file (DFI_postreload, print_rtl_with_bb, insns);
if (optimize > 0 && flag_gcse_after_reload)
rest_of_handle_gcse2 (decl, insns);
timevar_push (TV_FLOW2);
open_dump_file (DFI_flow2, 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)
{
open_dump_file (DFI_branch_target_load, decl);
branch_target_load_optimize (false);
close_dump_file (DFI_branch_target_load, print_rtl_with_bb, insns);
ggc_collect ();
}
if (optimize)
cleanup_cfg (CLEANUP_EXPENSIVE);
thread_prologue_and_epilogue_insns (insns);
epilogue_completed = 1;
if (optimize)
{
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 ();
ggc_collect ();
}
flow2_completed = 1;
close_dump_file (DFI_flow2, print_rtl_with_bb, insns);
timevar_pop (TV_FLOW2);
#ifdef HAVE_peephole2
if (optimize > 0 && flag_peephole2)
{
timevar_push (TV_PEEPHOLE2);
open_dump_file (DFI_peephole2, decl);
peephole2_optimize (dump_file);
close_dump_file (DFI_peephole2, print_rtl_with_bb, insns);
timevar_pop (TV_PEEPHOLE2);
}
#endif
open_dump_file (DFI_ce3, decl);
if (optimize)
cleanup_cfg (CLEANUP_EXPENSIVE
| CLEANUP_UPDATE_LIFE
| (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
if (flag_if_conversion2)
{
timevar_push (TV_IFCVT2);
if_convert (1);
timevar_pop (TV_IFCVT2);
}
close_dump_file (DFI_ce3, print_rtl_with_bb, insns);
if (optimize > 0)
{
if (flag_rename_registers || flag_cprop_registers)
rest_of_handle_regrename (decl, insns);
rest_of_handle_reorder_blocks (decl, insns);
}
if (flag_branch_target_load_optimize2)
{
if (flag_branch_target_load_optimize)
warning ("branch target register load optimization is not intended "
"to be run twice");
open_dump_file (DFI_branch_target_load, decl);
branch_target_load_optimize (true);
close_dump_file (DFI_branch_target_load, print_rtl_with_bb, insns);
ggc_collect ();
}
#ifdef INSN_SCHEDULING
if (optimize > 0 && flag_schedule_insns_after_reload)
rest_of_handle_sched2 (decl, insns);
#endif
#ifdef LEAF_REGISTERS
current_function_uses_only_leaf_regs
= optimize > 0 && only_leaf_regs_used () && leaf_function_p ();
#endif
#ifdef STACK_REGS
rest_of_handle_stack_regs (decl, insns);
#endif
compute_alignments ();
if (flag_var_tracking)
rest_of_handle_variable_tracking (decl, insns);
free_bb_for_insn ();
if (targetm.machine_dependent_reorg != 0)
rest_of_handle_machine_reorg (decl, insns);
purge_line_number_notes (insns);
cleanup_barriers ();
#ifdef DELAY_SLOTS
if (optimize > 0 && flag_delayed_branch)
rest_of_handle_delay_slots (decl, insns);
#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 ();
timevar_push (TV_SHORTEN_BRANCH);
shorten_branches (get_insns ());
timevar_pop (TV_SHORTEN_BRANCH);
set_nothrow_function_flags ();
if (current_function_nothrow)
TREE_NOTHROW (current_function_decl) = 1;
rest_of_handle_final (decl, insns);
timevar_push (TV_SYMOUT);
(*debug_hooks->function_decl) (decl);
timevar_pop (TV_SYMOUT);
exit_rest_of_compilation:
coverage_end_function ();
#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->recursive_call_emit
&& 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);
ggc_collect ();
timevar_pop (TV_REST_OF_COMPILATION);
}
void
init_optimization_passes (void)
{
open_dump_file (DFI_cgraph, NULL);
cgraph_dump_file = dump_file;
dump_file = NULL;
}
void
finish_optimization_passes (void)
{
if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
{
timevar_push (TV_DUMP);
open_dump_file (DFI_bp, NULL);
end_branch_prob ();
close_dump_file (DFI_bp, NULL, NULL_RTX);
timevar_pop (TV_DUMP);
}
if (optimize > 0 && open_dump_file (DFI_combine, NULL))
{
timevar_push (TV_DUMP);
dump_combine_total_stats (dump_file);
close_dump_file (DFI_combine, NULL, NULL_RTX);
timevar_pop (TV_DUMP);
}
dump_file = cgraph_dump_file;
cgraph_dump_file = NULL;
close_dump_file (DFI_cgraph, NULL, NULL_RTX);
if (graph_dump_format != no_graph)
{
int i;
for (i = 0; i < (int) DFI_MAX; ++i)
if (dump_file_tbl[i].initialized && dump_file_tbl[i].graph_dump_p)
{
char seq[16];
char *suffix;
sprintf (seq, DUMPFILE_FORMAT, i);
suffix = concat (seq, dump_file_tbl[i].extension, NULL);
finish_graph_dump_file (dump_base_name, suffix);
free (suffix);
}
}
}
bool
enable_rtl_dump_file (int letter)
{
bool matched = false;
int i;
if (letter == 'a')
{
for (i = 0; i < (int) DFI_MAX; ++i)
dump_file_tbl[i].enabled = 1;
matched = true;
}
else
{
for (i = 0; i < (int) DFI_MAX; ++i)
if (letter == dump_file_tbl[i].debug_switch)
{
dump_file_tbl[i].enabled = 1;
matched = true;
}
}
return matched;
}