/* Top level of GCC compilers (cc1, cc1plus, etc.)
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
#include "intl.h"
#include "ggc.h"
#include "graph.h"
-#include "loop.h"
#include "regs.h"
#include "timevar.h"
#include "diagnostic.h"
timevar_push (TV_DUMP);
- gcc_assert (!dump_file);
- gcc_assert (!dump_file_name);
+ if (dump_file != NULL || dump_file_name != NULL)
+ abort ();
dump_file_name = get_dump_file_name (index);
initializing_dump = !dump_initialized_p (index);
&& !DECL_EXTERNAL (decl))
{
if (flag_unit_at_a_time && !cgraph_global_info_ready
- && TREE_CODE (decl) != FUNCTION_DECL && top_level
- /* If we defer processing of decls that have had their
- DECL_RTL set above (say, in make_decl_rtl),
- check_global_declarations() will clear it before
- assemble_variable has a chance to act on it. This
- would remove all traces of the register name in a
- global register variable, for example. */
- && !DECL_RTL_SET_P (decl))
+ && TREE_CODE (decl) != FUNCTION_DECL && top_level)
cgraph_varpool_finalize_decl (decl);
else
assemble_variable (decl, top_level, at_end, 0);
debug_hooks->type_decl (decl, !top_level);
timevar_pop (TV_SYMOUT);
}
+
+ /* Let cgraph know about the existance of variables. */
+ if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
+ cgraph_varpool_node (decl);
}
/* Called after finishing a record, union or enumeral type. */
different from the DECL_NAME name used in the source file. */
x = DECL_RTL (current_function_decl);
- gcc_assert (MEM_P (x));
+ if (!MEM_P (x))
+ abort ();
x = XEXP (x, 0);
- gcc_assert (GET_CODE (x) == SYMBOL_REF);
+ if (GET_CODE (x) != SYMBOL_REF)
+ abort ();
fnname = XSTR (x, 0);
assemble_start_function (current_function_decl, fnname);
/* Release all memory allocated by flow. */
free_basic_block_vars ();
-
- /* Release all memory held by regsets now. */
- regset_release_memory ();
}
/* Write DBX symbols if requested. */
}
#endif
-/* Track the variables, ie. compute where the variable is stored at each position in function. */
+/* Track the variables, i.e. compute where the variable is stored at each position in function. */
static void
rest_of_handle_variable_tracking (void)
{
}
-/* Run new register allocator. Return TRUE if we must exit
- rest_of_compilation upon return. */
-static bool
-rest_of_handle_new_regalloc (void)
-{
- int failure;
-
- timevar_push (TV_LOCAL_ALLOC);
- open_dump_file (DFI_lreg, current_function_decl);
-
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
- reg_alloc ();
-
- timevar_pop (TV_LOCAL_ALLOC);
- close_dump_file (DFI_lreg, NULL, NULL);
-
- /* XXX clean up the whole mess to bring live info in shape again. */
- timevar_push (TV_GLOBAL_ALLOC);
- open_dump_file (DFI_greg, current_function_decl);
-
- build_insn_chain (get_insns ());
- failure = reload (get_insns (), 0);
-
- timevar_pop (TV_GLOBAL_ALLOC);
-
- ggc_collect ();
-
- 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 ());
- }
-
- if (failure)
- return true;
-
- reload_completed = 1;
-
- return false;
-}
-
/* Run old register allocator. Return TRUE if we must exit
rest_of_compilation upon return. */
static bool
rebuild_jump_labels (get_insns ());
purge_all_dead_edges (0);
+ delete_unreachable_blocks ();
timevar_pop (TV_JUMP);
}
static void
rest_of_handle_sms (void)
{
+ sbitmap blocks;
+
timevar_push (TV_SMS);
open_dump_file (DFI_sms, current_function_decl);
/* Update the life information, because we add pseudos. */
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));
+ 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 ();
dump_flow_info (dump_file);
tracer (0);
cleanup_cfg (CLEANUP_EXPENSIVE);
- reg_scan (get_insns (), max_reg_num (), 0);
+ reg_scan (get_insns (), max_reg_num ());
close_dump_file (DFI_tracer, print_rtl_with_bb, get_insns ());
}
if (dump_file)
dump_flow_info (dump_file);
cleanup_cfg (CLEANUP_EXPENSIVE);
- reg_scan (get_insns (), max_reg_num (), 0);
+ 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 (), 0);
+ 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_WEB);
close_dump_file (DFI_web, print_rtl_with_bb, get_insns ());
- reg_scan (get_insns (), max_reg_num (), 0);
+ reg_scan (get_insns (), max_reg_num ());
}
/* Do branch profiling and static profile estimation passes. */
/* Discover and record the loop depth at the head of each basic
block. The loop infrastructure does the real job for us. */
- flow_loops_find (&loops, LOOP_TREE);
+ flow_loops_find (&loops);
if (dump_file)
flow_loops_dump (&loops, dump_file, NULL, 0);
it as constant, otherwise -fbranch-probabilities will not read data back.
life_analysis rarely eliminates modification of external memory.
- */
- if (optimize)
+
+ FIXME: now with tree based profiling we are in the trap described above
+ again. It seems to be easiest to disable the optimization for time
+ being before the problem is either solved by moving the transformation
+ to the IPA level (we need the CFG for this) or the very early optimization
+ passes are made to ignore the const/pure flags so code does not change. */
+ if (optimize
+ && (!flag_tree_based_profiling
+ || (!profile_arc_flag && !flag_branch_probabilities)))
{
/* Alias analysis depends on this information and mark_constant_function
depends on alias analysis. */
- reg_scan (get_insns (), max_reg_num (), 1);
+ reg_scan (get_insns (), max_reg_num ());
mark_constant_function ();
}
open_dump_file (DFI_bypass, current_function_decl);
cleanup_cfg (CLEANUP_EXPENSIVE);
- reg_scan (get_insns (), max_reg_num (), 1);
+ reg_scan (get_insns (), max_reg_num ());
if (bypass_jumps (dump_file))
{
rebuild_jump_labels (get_insns ());
timevar_pop (TV_JUMP);
+ delete_dead_jumptables ();
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
}
#endif
life_analysis (dump_file, PROP_FINAL);
if (optimize)
- cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_UPDATE_LIFE
- | CLEANUP_LOG_LINKS
+ cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE | CLEANUP_LOG_LINKS
| (flag_thread_jumps ? CLEANUP_THREADING : 0));
if (extra_warnings)
if (optimize)
{
- if (!flag_new_regalloc && initialize_uninitialized_subregs ())
+ if (initialize_uninitialized_subregs ())
{
/* Insns were inserted, and possibly pseudos created, so
things might look a bit different. */
dump_flow_info (dump_file);
timevar_push (TV_CSE);
- reg_scan (get_insns (), max_reg_num (), 1);
+ reg_scan (get_insns (), max_reg_num ());
tem = cse_main (get_insns (), max_reg_num (), dump_file);
if (tem)
expecting CSE to be run. But always rerun it in a cheap mode. */
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_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 (), 0);
+ reg_scan (get_insns (), max_reg_num ());
close_dump_file (DFI_cse2, print_rtl_with_bb, get_insns ());
timevar_pop (TV_CSE2);
if (flag_expensive_optimizations)
{
timevar_push (TV_CSE);
- reg_scan (get_insns (), max_reg_num (), 1);
+ 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 ());
}
/* If gcse or cse altered any jumps, rerun jump optimizations to clean
- things up. Then possibly re-run CSE again. */
- while (tem || tem2)
+ things up. */
+ if (tem || tem2)
{
- tem = tem2 = 0;
timevar_push (TV_JUMP);
rebuild_jump_labels (get_insns ());
+ delete_dead_jumptables ();
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
timevar_pop (TV_JUMP);
-
- if (flag_expensive_optimizations)
- {
- timevar_push (TV_CSE);
- reg_scan (get_insns (), max_reg_num (), 1);
- 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);
- }
}
close_dump_file (DFI_gcse, print_rtl_with_bb, get_insns ());
static void
rest_of_handle_loop_optimize (void)
{
- int do_unroll, do_prefetch;
+ int do_prefetch;
timevar_push (TV_LOOP);
- delete_dead_jumptables ();
- cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
open_dump_file (DFI_loop, current_function_decl);
/* CFG is no longer maintained up-to-date. */
free_bb_for_insn ();
+ profile_status = PROFILE_ABSENT;
- if (flag_unroll_loops)
- do_unroll = LOOP_AUTO_UNROLL; /* Having two unrollers is useless. */
- else
- do_unroll = flag_old_unroll_loops ? LOOP_UNROLL : LOOP_AUTO_UNROLL;
do_prefetch = flag_prefetch_loop_arrays ? LOOP_PREFETCH : 0;
if (flag_rerun_loop_opt)
cleanup_barriers ();
/* We only want to perform unrolling once. */
- loop_optimize (get_insns (), dump_file, do_unroll);
- do_unroll = 0;
+ loop_optimize (get_insns (), dump_file, 0);
/* The first call to loop_optimize makes some instructions
trivially dead. We delete those instructions now in the
/* The regscan pass is currently necessary as the alias
analysis code depends on this information. */
- reg_scan (get_insns (), max_reg_num (), 1);
+ reg_scan (get_insns (), max_reg_num ());
}
cleanup_barriers ();
- loop_optimize (get_insns (), dump_file, do_unroll | do_prefetch);
+ loop_optimize (get_insns (), dump_file, do_prefetch);
/* Loop can create trivially dead instructions. */
delete_trivially_dead_insns (get_insns (), max_reg_num ());
- find_basic_blocks (get_insns (), max_reg_num (), dump_file);
+ find_basic_blocks (get_insns ());
close_dump_file (DFI_loop, print_rtl, get_insns ());
timevar_pop (TV_LOOP);
cleanup_cfg (CLEANUP_EXPENSIVE);
delete_trivially_dead_insns (get_insns (), max_reg_num ());
- reg_scan (get_insns (), max_reg_num (), 0);
+ 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_push (TV_JUMP);
open_dump_file (DFI_sibling, current_function_decl);
- /* ??? We may get called either via tree_rest_of_compilation when the CFG
- is already built or directly (for instance from coverage code).
- The direct callers shall be updated. */
- if (!basic_block_info)
- {
- init_flow ();
- rebuild_jump_labels (get_insns ());
- find_exception_handler_labels ();
- find_basic_blocks (get_insns (), max_reg_num (), dump_file);
- }
-
- /* ??? We may get called either via tree_rest_of_compilation when the CFG
- is already built or directly (for instance from coverage code).
- The direct callers shall be updated. */
- if (!basic_block_info)
- {
- init_flow ();
- rebuild_jump_labels (get_insns ());
- find_exception_handler_labels ();
- find_basic_blocks (get_insns (), max_reg_num (), dump_file);
- }
delete_unreachable_blocks ();
#ifdef ENABLE_CHECKING
verify_flow_info ();
}
}
-
-static void
-rest_of_handle_prologue_epilogue (void)
-{
- if (optimize && !flow2_completed)
- cleanup_cfg (CLEANUP_EXPENSIVE);
-
- /* On some machines, the prologue and epilogue code, or parts thereof,
- can be represented as RTL. Doing so lets us schedule insns between
- it and the rest of the code and also allows delayed branch
- scheduling to operate in the epilogue. */
- thread_prologue_and_epilogue_insns (get_insns ());
- epilogue_completed = 1;
-
- if (optimize && flow2_completed)
- life_analysis (dump_file, PROP_POSTRELOAD);
-}
-
static void
rest_of_handle_stack_adjustments (void)
{
split_all_insns (0);
if (flag_branch_target_load_optimize)
- rest_of_handle_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);
- if (!targetm.late_rtl_prologue_epilogue)
- rest_of_handle_prologue_epilogue ();
+ /* On some machines, the prologue and epilogue code, or parts thereof,
+ can be represented as RTL. Doing so lets us schedule insns between
+ it and the rest of the code and also allows delayed branch
+ scheduling to operate in the epilogue. */
+ thread_prologue_and_epilogue_insns (get_insns ());
+ epilogue_completed = 1;
if (optimize)
rest_of_handle_stack_adjustments ();
expected_value_to_br_prob ();
delete_trivially_dead_insns (get_insns (), max_reg_num ());
- reg_scan (get_insns (), max_reg_num (), 0);
+ reg_scan (get_insns (), max_reg_num ());
if (dump_file)
dump_flow_info (dump_file);
cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_PRE_LOOP
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)
+ 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;
after all tree passes have finished for a single function, and we
have expanded the function body from trees to RTL.
Once we are here, we have decided that we're supposed to output
- that function, ie. that we should write assembler code for it.
+ that function, i.e. that we should write assembler code for it.
We run a series of low-level passes here on the function's RTL
representation. Each pass is called via a rest_of_* function. */
-void
+static void
rest_of_compilation (void)
{
- /* Convert from NOTE_INSN_EH_REGION style notes, and do other
- sorts of eh initialization. */
- convert_from_eh_region_ranges ();
-
/* If we're emitting a nested function, make sure its parent gets
emitted as well. Doing otherwise confuses debug info. */
{
&& !user_defined_section_attribute)
rest_of_handle_partition_blocks ();
- if (optimize > 0 && (flag_regmove || flag_expensive_optimizations))
+ if (optimize > 0 && flag_regmove)
rest_of_handle_regmove ();
/* Do unconditional splitting before register allocation to allow machine
/* Any of the several passes since flow1 will have munged register
lifetime data a bit. We need it to be up to date for scheduling
(see handling of reg_known_equiv in init_alias_analysis). */
- recompute_reg_usage (get_insns (), !optimize_size);
+ recompute_reg_usage ();
#ifdef INSN_SCHEDULING
if (optimize > 0 && flag_modulo_sched)
epilogue thus changing register elimination offsets. */
current_function_is_leaf = leaf_function_p ();
- if (flag_new_regalloc)
- {
- if (rest_of_handle_new_regalloc ())
- goto exit_rest_of_compilation;
- }
- else
- {
- if (rest_of_handle_old_regalloc ())
- goto exit_rest_of_compilation;
- }
+ if (rest_of_handle_old_regalloc ())
+ goto exit_rest_of_compilation;
if (optimize > 0)
rest_of_handle_postreload ();
= optimize > 0 && only_leaf_regs_used () && leaf_function_p ();
#endif
- if (targetm.late_rtl_prologue_epilogue)
- rest_of_handle_prologue_epilogue ();
-
#ifdef INSN_SCHEDULING
if (optimize > 0 && flag_schedule_insns_after_reload)
rest_of_handle_sched2 ();
compute_alignments ();
+ /* Aggressively duplicate basic blocks ending in computed gotos to the
+ tails of their predecessors, unless we are optimizing for size. */
+ if (flag_expensive_optimizations && !optimize_size)
+ duplicate_computed_gotos ();
+
if (flag_var_tracking)
rest_of_handle_variable_tracking ();