From: aldyh Date: Sat, 31 May 2003 23:46:41 +0000 (+0000) Subject: 2003-05-31 Aldy Hernandez X-Git-Tag: upstream/4.9.2~79292 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=03414cfbaab5ca7aa73ec39ab1f943046d2bd090;p=platform%2Fupstream%2Flinaro-gcc.git 2003-05-31 Aldy Hernandez * toplev.c (botch): Remove. (do_abort): Remove. (set_Wunused): Comment. (set_Wextra): Comment. Remove ^L's. (rest_of_compilation): Factor out common code into functions. (rest_of_handle_inlining): New. (rest_of_handle_ssa): New. (rest_of_handle_cse): New. (rest_of_handle_gcse): New. (rest_of_handle_loop_optimize): New. (rest_of_handle_jump_bypass): New. (rest_of_handle_sibling_calls): New. (rest_of_handle_null_pointer): New. (rest_of_handle_addresof): New. (rest_of_handle_flow): New. (rest_of_handle_branch_prob): New. (rest_of_handle_if_conversion): New. (rest_of_handle_tracer): New. (rest_of_handle_loop2): New. (rest_of_handle_cse2): New. (rest_of_handle_life): New. (rest_of_handle_combine): New. (rest_of_handle_if_after_combine): New. (rest_of_handle_regmove): New. (rest_of_handle_sched): New. (rest_of_handle_old_regalloc): New. (rest_of_handle_new_regalloc): New. (rest_of_handle_regrename): New. (rest_of_handle_reorder_blocks): New. (rest_of_handle_sched2): New. (rest_of_handle_new_regalloc): New. (rest_of_handle_old_regalloc): New. (rest_of_handle_regrename): New. (rest_of_handle_reorder_blocks): New. (rest_of_handle_stack_regs): New. (rest_of_handle_machine_reorg): New. (rest_of_handle_delay_slots): New. (rest_of_handle_final): New. * toplev.h (botch): Remove prototype. (do_abort): Same. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@67281 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2c2ce7b..ec269cc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,48 @@ +2003-05-31 Aldy Hernandez + + * toplev.c (botch): Remove. + (do_abort): Remove. + (set_Wunused): Comment. + (set_Wextra): Comment. + Remove ^L's. + (rest_of_compilation): Factor out common code into functions. + (rest_of_handle_inlining): New. + (rest_of_handle_ssa): New. + (rest_of_handle_cse): New. + (rest_of_handle_gcse): New. + (rest_of_handle_loop_optimize): New. + (rest_of_handle_jump_bypass): New. + (rest_of_handle_sibling_calls): New. + (rest_of_handle_null_pointer): New. + (rest_of_handle_addresof): New. + (rest_of_handle_flow): New. + (rest_of_handle_branch_prob): New. + (rest_of_handle_if_conversion): New. + (rest_of_handle_tracer): New. + (rest_of_handle_loop2): New. + (rest_of_handle_cse2): New. + (rest_of_handle_life): New. + (rest_of_handle_combine): New. + (rest_of_handle_if_after_combine): New. + (rest_of_handle_regmove): New. + (rest_of_handle_sched): New. + (rest_of_handle_old_regalloc): New. + (rest_of_handle_new_regalloc): New. + (rest_of_handle_regrename): New. + (rest_of_handle_reorder_blocks): New. + (rest_of_handle_sched2): New. + (rest_of_handle_new_regalloc): New. + (rest_of_handle_old_regalloc): New. + (rest_of_handle_regrename): New. + (rest_of_handle_reorder_blocks): New. + (rest_of_handle_stack_regs): New. + (rest_of_handle_machine_reorg): New. + (rest_of_handle_delay_slots): New. + (rest_of_handle_final): New. + + * toplev.h (botch): Remove prototype. + (do_abort): Same. + 2003-05-31 Neil Booth * Makefile.in (c-opts.o, c-options.h): Update dependencies. diff --git a/gcc/toplev.c b/gcc/toplev.c index f2c352f..77a3bb9 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -93,7 +93,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "xcoffout.h" /* Needed for external data declarations for e.g. AIX 4.x. */ #endif - + /* Carry information from ASM_DECLARE_OBJECT_NAME to ASM_FINISH_DECLARE_OBJECT. */ @@ -133,6 +133,43 @@ static int print_single_switch PARAMS ((FILE *, int, int, const char *, static void print_switch_values PARAMS ((FILE *, int, int, const char *, const char *, const char *)); +/* Rest of compilation helper functions. */ +static bool rest_of_handle_inlining (tree); +static rtx rest_of_handle_ssa (tree, rtx); +static void rest_of_handle_cse (tree, rtx); +static void rest_of_handle_cse2 (tree, rtx); +static void rest_of_handle_gcse (tree, rtx); +static void rest_of_handle_life (tree, rtx); +static void rest_of_handle_loop_optimize (tree, rtx); +static void rest_of_handle_loop2 (tree, rtx); +static void rest_of_handle_jump_bypass (tree, rtx); +static void rest_of_handle_sibling_calls (rtx); +static void rest_of_handle_null_pointer (tree, rtx); +static void rest_of_handle_addresof (tree, rtx); +static void rest_of_handle_cfg (tree, rtx); +static void rest_of_handle_branch_prob (tree, rtx); +static void rest_of_handle_if_conversion (tree, rtx); +static void rest_of_handle_if_after_combine (tree, rtx); +static void rest_of_handle_tracer (tree, rtx); +static void rest_of_handle_combine (tree, rtx); +static void rest_of_handle_regmove (tree, rtx); +static void rest_of_handle_sched (tree, rtx); +#ifdef INSN_SCHEDULING +static void rest_of_handle_sched2 (tree, rtx); +#endif +static bool rest_of_handle_new_regalloc (tree, rtx, int *); +static bool rest_of_handle_old_regalloc (tree, rtx, int *); +static void rest_of_handle_regrename (tree, rtx); +static void rest_of_handle_reorder_blocks (tree, rtx); +#ifdef STACK_REGS +static void rest_of_handle_stack_regs (tree, rtx); +#endif +static void rest_of_handle_machine_reorg (tree, rtx); +#ifdef DELAY_SLOTS +static void rest_of_handle_delay_slots (tree, rtx); +#endif +static void rest_of_handle_final (tree, rtx); + /* Nonzero to dump debug info whilst parsing (-dy option). */ static int set_yydebug; @@ -149,7 +186,7 @@ const char *progname; /* Copy of arguments to toplev_main. */ int save_argc; char **save_argv; - + /* Name of top-level original source file (what was input to cpp). This comes from the #-command at the beginning of the actual input. If there isn't any there, then this is the cc1 input file name. */ @@ -438,7 +475,6 @@ int mem_report = 0; and to print them when we are done. */ int flag_detailed_statistics = 0; - /* -f flags. */ /* Nonzero means `char' should be signed. */ @@ -1437,7 +1473,7 @@ static const struct } target_options[] = TARGET_OPTIONS; #endif - + /* Options controlling warnings. */ /* Don't print warning messages. -w. */ @@ -1596,6 +1632,7 @@ static const lang_independent_options W_options[] = N_ ("Warn about code which might break the strict aliasing rules") } }; +/* Initialize unused warning flags. */ void set_Wunused (setting) int setting; @@ -1613,6 +1650,7 @@ set_Wunused (setting) warn_unused_value = setting; } +/* Initialize more unused warning flags. */ static void set_Wextra (setting) int setting; @@ -1655,7 +1693,6 @@ fast_math_flags_set_p () && !flag_errno_math); } - /* Output files for assembler code (real compiler output) and debugging dumps. */ @@ -1693,26 +1730,7 @@ read_integral_parameter (p, pname, defval) return atoi (p); } - -/* This calls abort and is used to avoid problems when abort is a macro. - It is used when we need to pass the address of abort. */ - -void -do_abort () -{ - abort (); -} -/* When `malloc.c' is compiled with `rcheck' defined, - it calls this function to report clobberage. */ - -void -botch (s) - const char *s ATTRIBUTE_UNUSED; -{ - abort (); -} - /* Return the logarithm of X, base 2, considering X unsigned, if X is a power of 2. Otherwise, returns -1. @@ -1877,7 +1895,7 @@ output_file_directive (asm_file, input_name) #endif #endif } - + /* Routine to open a dump file. Return true if the dump file is enabled. */ static int @@ -2283,7 +2301,7 @@ compile_file () timevar_pop (TV_DUMP); } } - + /* This is called from various places for FUNCTION_DECL, VAR_DECL, and TYPE_DECL nodes. @@ -2424,499 +2442,451 @@ rest_of_type_compilation (type, toplev) timevar_pop (TV_SYMOUT); } -/* This is called from finish_function (within langhooks.parse_file) - after each top-level definition is parsed. - It is supposed to compile that function or variable - and output the assembler code for it. - After we return, the tree storage is freed. */ - -void -rest_of_compilation (decl) - tree decl; +/* Turn the RTL into assembly. */ +static void +rest_of_handle_final (tree decl, rtx insns) { - rtx insns; - int tem; - int failure = 0; - int rebuild_label_notes_after_reload; + timevar_push (TV_FINAL); + { + rtx x; + const char *fnname; - timevar_push (TV_REST_OF_COMPILATION); + /* Get the function's name, as described by its RTL. This may be + different from the DECL_NAME name used in the source file. */ - /* Now that we're out of the frontend, we shouldn't have any more - CONCATs anywhere. */ - generating_concat_p = 0; + 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); - /* When processing delayed functions, prepare_function_start() won't - have been run to re-initialize it. */ - cse_not_expected = ! optimize; + assemble_start_function (decl, fnname); + final_start_function (insns, asm_out_file, optimize); + final (insns, asm_out_file, optimize, 0); + final_end_function (); - /* First, make sure that NOTE_BLOCK is set correctly for each - NOTE_INSN_BLOCK_BEG/NOTE_INSN_BLOCK_END note. */ - if (!cfun->x_whole_function_mode_p) - identify_blocks (); +#ifdef IA64_UNWIND_INFO + /* ??? The IA-64 ".handlerdata" directive must be issued before + the ".endp" directive that closes the procedure descriptor. */ + output_function_exception_table (); +#endif - /* In function-at-a-time mode, we do not attempt to keep the BLOCK - tree in sensible shape. So, we just recalculate it here. */ - if (cfun->x_whole_function_mode_p) - reorder_blocks (); + assemble_end_function (decl, fnname); - init_flow (); +#ifndef IA64_UNWIND_INFO + /* Otherwise, it feels unclean to switch sections in the middle. */ + output_function_exception_table (); +#endif - /* If we are reconsidering an inline function - at the end of compilation, skip the stuff for making it inline. */ + if (! quiet_flag) + fflush (asm_out_file); - if (DECL_SAVED_INSNS (decl) == 0) - { - int inlinable = 0; - tree parent; - const char *lose; - - /* If this is nested inside an inlined external function, pretend - it was only declared. Since we cannot inline such functions, - generating code for this one is not only not necessary but will - confuse some debugging output writers. */ - for (parent = DECL_CONTEXT (current_function_decl); - parent != NULL_TREE; - parent = get_containing_scope (parent)) - if (TREE_CODE (parent) == FUNCTION_DECL - && DECL_INLINE (parent) && DECL_EXTERNAL (parent)) - { - DECL_INITIAL (decl) = 0; - goto exit_rest_of_compilation; - } - else if (TYPE_P (parent)) - /* A function in a local class should be treated normally. */ - break; + /* Release all memory allocated by flow. */ + free_basic_block_vars (0); - /* If requested, consider whether to make this function inline. */ - if ((DECL_INLINE (decl) && !flag_no_inline) - || flag_inline_functions) - { - timevar_push (TV_INTEGRATION); - lose = function_cannot_inline_p (decl); - timevar_pop (TV_INTEGRATION); - if (lose || ! optimize) - { - if (warn_inline && DECL_INLINE (decl)) - warning_with_decl (decl, lose); - DECL_ABSTRACT_ORIGIN (decl) = 0; - /* Don't really compile an extern inline function. - If we can't make it inline, pretend - it was only declared. */ - if (DECL_EXTERNAL (decl)) - { - DECL_INITIAL (decl) = 0; - goto exit_rest_of_compilation; - } - } - else { - /* ??? Note that we used to just make it look like if - the "inline" keyword was specified when we decide - to inline it (because of -finline-functions). - garloff@suse.de, 2002-04-24: Add another flag to - actually record this piece of information. */ - if (!DECL_INLINE (decl)) - DID_INLINE_FUNC (decl) = 1; - inlinable = DECL_INLINE (decl) = 1; - } - } + /* Release all memory held by regsets now. */ + regset_release_memory (); + } + timevar_pop (TV_FINAL); - insns = get_insns (); + ggc_collect (); +} - /* Dump the rtl code if we are dumping rtl. */ +#ifdef DELAY_SLOTS +/* Run delay slot optimization. */ +static void +rest_of_handle_delay_slots (tree decl, rtx insns) +{ + timevar_push (TV_DBR_SCHED); + open_dump_file (DFI_dbr, decl); - if (open_dump_file (DFI_rtl, decl)) - { - if (DECL_SAVED_INSNS (decl)) - fprintf (rtl_dump_file, ";; (integrable)\n\n"); - close_dump_file (DFI_rtl, print_rtl, insns); - } + dbr_schedule (insns, rtl_dump_file); - /* Convert from NOTE_INSN_EH_REGION style notes, and do other - sorts of eh initialization. Delay this until after the - initial rtl dump so that we can see the original nesting. */ - convert_from_eh_region_ranges (); - - /* If function is inline, and we don't yet know whether to - compile it by itself, defer decision till end of compilation. - wrapup_global_declarations will (indirectly) call - rest_of_compilation again for those functions that need to - be output. Also defer those functions that we are supposed - to defer. */ - - if (inlinable - || (DECL_INLINE (decl) - && flag_inline_functions - && ((! TREE_PUBLIC (decl) && ! TREE_ADDRESSABLE (decl) - && ! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) - && ! flag_keep_inline_functions) - || DECL_EXTERNAL (decl)))) - DECL_DEFER_OUTPUT (decl) = 1; - - if (DECL_INLINE (decl)) - /* DWARF wants separate debugging info for abstract and - concrete instances of all inline functions, including those - declared inline but not inlined, and those inlined even - though they weren't declared inline. Conveniently, that's - what DECL_INLINE means at this point. */ - (*debug_hooks->deferred_inline_function) (decl); - - if (DECL_DEFER_OUTPUT (decl)) - { - /* If -Wreturn-type, we have to do a bit of compilation. We just - want to call cleanup the cfg to figure out whether or not we can - fall off the end of the function; we do the minimum amount of - work necessary to make that safe. */ - if (warn_return_type) - { - int saved_optimize = optimize; + close_dump_file (DFI_dbr, print_rtl, insns); + timevar_pop (TV_DBR_SCHED); - optimize = 0; - rebuild_jump_labels (insns); - find_exception_handler_labels (); - find_basic_blocks (insns, max_reg_num (), rtl_dump_file); - cleanup_cfg (CLEANUP_PRE_SIBCALL | CLEANUP_PRE_LOOP); - optimize = saved_optimize; + ggc_collect (); +} +#endif - /* CFG is no longer maintained up-to-date. */ - free_bb_for_insn (); - } +#ifdef STACK_REGS +/* Convert register usage from flat register file usage to a stack + register file. */ +static void +rest_of_handle_stack_regs (tree decl, rtx insns) +{ + timevar_push (TV_REG_STACK); + open_dump_file (DFI_stack, decl); - set_nothrow_function_flags (); - if (current_function_nothrow) - /* Now we know that this can't throw; set the flag for the benefit - of other functions later in this translation unit. */ - TREE_NOTHROW (current_function_decl) = 1; - - timevar_push (TV_INTEGRATION); - save_for_inline (decl); - timevar_pop (TV_INTEGRATION); - DECL_SAVED_INSNS (decl)->inlinable = inlinable; - goto exit_rest_of_compilation; + if (reg_to_stack (insns, rtl_dump_file) && optimize) + { + if (cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_POST_REGSTACK + | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0)) + && flag_reorder_blocks) + { + reorder_basic_blocks (); + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_POST_REGSTACK); } - - /* If specified extern inline but we aren't inlining it, we are - done. This goes for anything that gets here with DECL_EXTERNAL - set, not just things with DECL_INLINE. */ - if (DECL_EXTERNAL (decl)) - goto exit_rest_of_compilation; } - /* If we're emitting a nested function, make sure its parent gets - emitted as well. Doing otherwise confuses debug info. */ - { - 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; - } - - /* We are now committed to emitting code for this function. Do any - preparation, such as emitting abstract debug info for the inline - before it gets mangled by optimization. */ - if (DECL_INLINE (decl)) - (*debug_hooks->outlining_inline_function) (decl); - - /* Remove any notes we don't need. That will make iterating - over the instruction sequence faster, and allow the garbage - collector to reclaim the memory used by the notes. */ - remove_unnecessary_notes (); - reorder_blocks (); + close_dump_file (DFI_stack, print_rtl_with_bb, insns); + timevar_pop (TV_REG_STACK); ggc_collect (); +} +#endif - /* Initialize some variables used by the optimizers. */ - init_function_for_compilation (); - if (! DECL_DEFER_OUTPUT (decl)) - TREE_ASM_WRITTEN (decl) = 1; +/* Machine independent reorg pass. */ +static void +rest_of_handle_machine_reorg (tree decl, rtx insns) +{ + timevar_push (TV_MACH_DEP); + open_dump_file (DFI_mach, decl); - /* Now that integrate will no longer see our rtl, we need not - distinguish between the return value of this function and the - return value of called functions. Also, we can remove all SETs - of subregs of hard registers; they are only here because of - integrate. Also, we can now initialize pseudos intended to - carry magic hard reg data throughout the function. */ - rtx_equal_function_value_matters = 0; - purge_hard_subreg_sets (get_insns ()); + (*targetm.machine_dependent_reorg) (); - /* Early return if there were errors. We can run afoul of our - consistency checks, and there's not really much point in fixing them. - Don't return yet if -Wreturn-type; we need to do cleanup_cfg. */ - if (((rtl_dump_and_exit || flag_syntax_only) && !warn_return_type) - || errorcount || sorrycount) - goto exit_rest_of_compilation; + close_dump_file (DFI_mach, print_rtl, insns); + timevar_pop (TV_MACH_DEP); - 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 (), rtl_dump_file); + ggc_collect (); +} - delete_unreachable_blocks (); - /* We have to issue these warnings now already, because CFG cleanups - further down may destroy the required information. */ - check_function_return_warnings (); +/* Run new register allocator. Return TRUE if we must exit + rest_of_compilation upon return. */ +static bool +rest_of_handle_new_regalloc (tree decl, rtx insns, int *rebuild_notes) +{ + int failure; - /* Turn NOTE_INSN_PREDICTIONs into branch predictions. */ - if (flag_guess_branch_prob) - { - timevar_push (TV_BRANCH_PROB); - note_prediction_to_br_prob (); - timevar_pop (TV_BRANCH_PROB); - } + delete_trivially_dead_insns (insns, max_reg_num ()); + reg_alloc (); - /* We may have potential sibling or tail recursion sites. Select one - (of possibly multiple) methods of performing the call. */ - if (flag_optimize_sibling_calls) + timevar_pop (TV_LOCAL_ALLOC); + if (dump_file[DFI_lreg].enabled) { - rtx insn; - optimize_sibling_and_tail_recursive_calls (); + timevar_push (TV_DUMP); - /* Recompute the CFG as sibling optimization clobbers it randomly. */ - free_bb_for_insn (); - find_exception_handler_labels (); - rebuild_jump_labels (insns); - find_basic_blocks (insns, max_reg_num (), rtl_dump_file); + close_dump_file (DFI_lreg, NULL, NULL); + timevar_pop (TV_DUMP); + } - /* There is pass ordering problem - we must lower NOTE_INSN_PREDICTION - notes before simplifying cfg and we must do lowering after sibcall - that unhides parts of RTL chain and cleans up the CFG. + /* XXX clean up the whole mess to bring live info in shape again. */ + timevar_push (TV_GLOBAL_ALLOC); + open_dump_file (DFI_greg, decl); - Until sibcall is replaced by tree-level optimizer, lets just - sweep away the NOTE_INSN_PREDICTION notes that leaked out. */ - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_PREDICTION) - delete_insn (insn); - } - close_dump_file (DFI_sibling, print_rtl, get_insns ()); - timevar_pop (TV_JUMP); + build_insn_chain (insns); + failure = reload (insns, 0); - scope_to_insns_initialize (); - /* Complete generation of exception handling code. */ - if (doing_eh (0)) + timevar_pop (TV_GLOBAL_ALLOC); + + if (dump_file[DFI_greg].enabled) { - timevar_push (TV_JUMP); - open_dump_file (DFI_eh, decl); + timevar_push (TV_DUMP); - finish_eh_generation (); + dump_global_regs (rtl_dump_file); - close_dump_file (DFI_eh, print_rtl, get_insns ()); - timevar_pop (TV_JUMP); + close_dump_file (DFI_greg, print_rtl_with_bb, insns); + timevar_pop (TV_DUMP); } - /* Delay emitting hard_reg_initial_value sets until after EH landing pad - generation, which might create new sets. */ - emit_initial_value_sets (); - -#ifdef FINALIZE_PIC - /* If we are doing position-independent code generation, now - is the time to output special prologues and epilogues. - We do not want to do this earlier, because it just clutters - up inline functions with meaningless insns. */ - if (flag_pic) - FINALIZE_PIC; -#endif + if (failure) + return true; - insns = get_insns (); + reload_completed = 1; + *rebuild_notes = 0; - /* Copy any shared structure that should not be shared. */ - unshare_all_rtl (current_function_decl, insns); + return false; +} -#ifdef SETJMP_VIA_SAVE_AREA - /* This must be performed before virtual register instantiation. - Please be aware the everything in the compiler that can look - at the RTL up to this point must understand that REG_SAVE_AREA - is just like a use of the REG contained inside. */ - if (current_function_calls_alloca) - optimize_save_area_alloca (insns); -#endif +/* Run old register allocator. Return TRUE if we must exit + rest_of_compilation upon return. */ +static bool +rest_of_handle_old_regalloc (tree decl, rtx insns, int *rebuild_notes) +{ + int failure; - /* Instantiate all virtual registers. */ - instantiate_virtual_regs (current_function_decl, insns); + /* Allocate the reg_renumber array. */ + allocate_reg_info (max_regno, FALSE, TRUE); - open_dump_file (DFI_jump, decl); + /* And the reg_equiv_memory_loc array. */ + reg_equiv_memory_loc = (rtx *) xcalloc (max_regno, sizeof (rtx)); - /* Always do one jump optimization pass to ensure that JUMP_LABEL fields - are initialized and to compute whether control can drop off the end - of the function. */ + allocate_initial_values (reg_equiv_memory_loc); - timevar_push (TV_JUMP); - /* Turn NOTE_INSN_EXPECTED_VALUE into REG_BR_PROB. Do this - before jump optimization switches branch directions. */ - if (flag_guess_branch_prob) - expected_value_to_br_prob (); + regclass (insns, max_reg_num (), rtl_dump_file); + *rebuild_notes = local_alloc (); - reg_scan (insns, max_reg_num (), 0); - rebuild_jump_labels (insns); - find_basic_blocks (insns, max_reg_num (), rtl_dump_file); - delete_trivially_dead_insns (insns, max_reg_num ()); - if (rtl_dump_file) - dump_flow_info (rtl_dump_file); - cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_PRE_LOOP - | (flag_thread_jumps ? CLEANUP_THREADING : 0)); + timevar_pop (TV_LOCAL_ALLOC); - if (optimize) + if (dump_file[DFI_lreg].enabled) { - free_bb_for_insn (); - copy_loop_headers (insns); - find_basic_blocks (insns, max_reg_num (), rtl_dump_file); + timevar_push (TV_DUMP); + + dump_flow_info (rtl_dump_file); + dump_local_alloc (rtl_dump_file); + + close_dump_file (DFI_lreg, print_rtl_with_bb, insns); + timevar_pop (TV_DUMP); } - purge_line_number_notes (insns); - timevar_pop (TV_JUMP); - close_dump_file (DFI_jump, print_rtl, insns); + ggc_collect (); - /* Now is when we stop if -fsyntax-only and -Wreturn-type. */ - if (rtl_dump_and_exit || flag_syntax_only || DECL_DEFER_OUTPUT (decl)) + timevar_push (TV_GLOBAL_ALLOC); + open_dump_file (DFI_greg, decl); + + /* If optimizing, allocate remaining pseudo-regs. Do the reload + pass fixing up any insns that are invalid. */ + + if (optimize) + failure = global_alloc (rtl_dump_file); + else { - goto exit_rest_of_compilation; + build_insn_chain (insns); + failure = reload (insns, 0); } - /* Long term, this should probably move before the jump optimizer too, - but I didn't want to disturb the rtl_dump_and_exit and related - stuff at this time. */ - if (optimize > 0 && flag_ssa) - { - /* Convert to SSA form. */ + timevar_pop (TV_GLOBAL_ALLOC); - timevar_push (TV_TO_SSA); - open_dump_file (DFI_ssa, decl); + if (dump_file[DFI_greg].enabled) + { + timevar_push (TV_DUMP); - cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); - convert_to_ssa (); + dump_global_regs (rtl_dump_file); - close_dump_file (DFI_ssa, print_rtl_with_bb, insns); - timevar_pop (TV_TO_SSA); + close_dump_file (DFI_greg, print_rtl_with_bb, insns); + timevar_pop (TV_DUMP); + } - /* Perform sparse conditional constant propagation, if requested. */ - if (flag_ssa_ccp) - { - timevar_push (TV_SSA_CCP); - open_dump_file (DFI_ssa_ccp, decl); + return failure; +} - ssa_const_prop (); +/* Run the regrename and cprop passes. */ +static void +rest_of_handle_regrename (tree decl, rtx insns) +{ + timevar_push (TV_RENAME_REGISTERS); + open_dump_file (DFI_rnreg, decl); - close_dump_file (DFI_ssa_ccp, print_rtl_with_bb, get_insns ()); - timevar_pop (TV_SSA_CCP); - } + if (flag_rename_registers) + regrename_optimize (); + if (flag_cprop_registers) + copyprop_hardreg_forward (); - /* It would be useful to cleanup the CFG at this point, but block - merging and possibly other transformations might leave a PHI - node in the middle of a basic block, which is a strict no-no. */ + close_dump_file (DFI_rnreg, print_rtl_with_bb, insns); + timevar_pop (TV_RENAME_REGISTERS); +} - /* The SSA implementation uses basic block numbers in its phi - nodes. Thus, changing the control-flow graph or the basic - blocks, e.g., calling find_basic_blocks () or cleanup_cfg (), - may cause problems. */ +/* Reorder basic blocks. */ +static void +rest_of_handle_reorder_blocks (tree decl, rtx insns) +{ + timevar_push (TV_REORDER_BLOCKS); + open_dump_file (DFI_bbro, decl); + + /* Last attempt to optimize CFG, as scheduling, peepholing and insn + splitting possibly introduced more crossjumping opportunities. */ + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE + | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0)); + + if (flag_sched2_use_traces && flag_schedule_insns_after_reload) + tracer (); + if (flag_reorder_blocks) + reorder_basic_blocks (); + if (flag_reorder_blocks + || (flag_sched2_use_traces && flag_schedule_insns_after_reload)) + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE); + + close_dump_file (DFI_bbro, print_rtl_with_bb, insns); + timevar_pop (TV_REORDER_BLOCKS); +} + +/* Run instruction scheduler. */ +static void +rest_of_handle_sched (tree decl, rtx insns) +{ + timevar_push (TV_SCHED); +#ifdef INSN_SCHEDULING - if (flag_ssa_dce) - { - /* Remove dead code. */ + /* Print function header into sched dump now + because doing the sched analysis makes some of the dump. */ + if (optimize > 0 && flag_schedule_insns) + { + open_dump_file (DFI_sched, decl); - timevar_push (TV_SSA_DCE); - open_dump_file (DFI_ssa_dce, decl); + /* Do control and data sched analysis, + and write some of the results to dump file. */ - insns = get_insns (); - ssa_eliminate_dead_code (); + schedule_insns (rtl_dump_file); - close_dump_file (DFI_ssa_dce, print_rtl_with_bb, insns); - timevar_pop (TV_SSA_DCE); - } + close_dump_file (DFI_sched, print_rtl_with_bb, insns); + } +#endif + timevar_pop (TV_SCHED); - /* Convert from SSA form. */ + ggc_collect (); +} - timevar_push (TV_FROM_SSA); - open_dump_file (DFI_ussa, decl); +#ifdef INSN_SCHEDULING +/* Run second scheduling pass after reload. */ +static void +rest_of_handle_sched2 (tree decl, rtx insns) +{ + timevar_push (TV_SCHED2); + open_dump_file (DFI_sched2, decl); - convert_from_ssa (); - /* New registers have been created. Rescan their usage. */ - reg_scan (insns, max_reg_num (), 1); + /* Do control and data sched analysis again, + and write some more of the results to dump file. */ - close_dump_file (DFI_ussa, print_rtl_with_bb, insns); - timevar_pop (TV_FROM_SSA); + split_all_insns (1); - ggc_collect (); + if (flag_sched2_use_superblocks || flag_sched2_use_traces) + { + schedule_ebbs (rtl_dump_file); + /* No liveness updating code yet, but it should be easy to do. + reg-stack recompute the liveness when needed for now. */ + count_or_remove_death_notes (NULL, 1); + cleanup_cfg (CLEANUP_EXPENSIVE); } + else + schedule_insns (rtl_dump_file); - timevar_push (TV_JUMP); - if (optimize) - cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); - - /* Try to identify useless null pointer tests and delete them. */ - if (flag_delete_null_pointer_checks) - { - open_dump_file (DFI_null, decl); - if (rtl_dump_file) - dump_flow_info (rtl_dump_file); + close_dump_file (DFI_sched2, print_rtl_with_bb, insns); + timevar_pop (TV_SCHED2); - if (delete_null_pointer_checks (insns)) - cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); + ggc_collect (); +} +#endif - close_dump_file (DFI_null, print_rtl_with_bb, insns); - } +/* Register allocation pre-pass, to reduce number of moves necessary + for two-address machines. */ +static void +rest_of_handle_regmove (tree decl, rtx insns) +{ + timevar_push (TV_REGMOVE); + open_dump_file (DFI_regmove, decl); - /* Jump optimization, and the removal of NULL pointer checks, may - have reduced the number of instructions substantially. CSE, and - future passes, allocate arrays whose dimensions involve the - maximum instruction UID, so if we can reduce the maximum UID - we'll save big on memory. */ - renumber_insns (rtl_dump_file); - timevar_pop (TV_JUMP); + regmove_optimize (insns, max_reg_num (), rtl_dump_file); - close_dump_file (DFI_jump, print_rtl_with_bb, insns); + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE); + close_dump_file (DFI_regmove, print_rtl_with_bb, insns); + timevar_pop (TV_REGMOVE); ggc_collect (); +} - /* Perform common subexpression elimination. - Nonzero value from `cse_main' means that jumps were simplified - and some code may now be unreachable, so do - jump optimization again. */ +/* Run tracer. */ +static void +rest_of_handle_tracer (tree decl, rtx insns) +{ + timevar_push (TV_TRACER); + open_dump_file (DFI_tracer, decl); + if (rtl_dump_file) + dump_flow_info (rtl_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 ()); + timevar_pop (TV_TRACER); +} - if (optimize > 0) +/* If-conversion and CFG cleanup. */ +static void +rest_of_handle_if_conversion (tree decl, rtx insns) +{ + open_dump_file (DFI_ce1, decl); + if (flag_if_conversion) { - open_dump_file (DFI_cse, decl); + timevar_push (TV_IFCVT); if (rtl_dump_file) dump_flow_info (rtl_dump_file); - timevar_push (TV_CSE); + 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 ()); +} - reg_scan (insns, max_reg_num (), 1); +/* Rerun if-conversion, as combine may have simplified things enough + to now meet sequence length restrictions. */ +static void +rest_of_handle_if_after_combine (tree decl, rtx insns) +{ + timevar_push (TV_IFCVT); + open_dump_file (DFI_ce2, decl); - tem = cse_main (insns, max_reg_num (), 0, rtl_dump_file); - if (tem) - rebuild_jump_labels (insns); - purge_all_dead_edges (0); + no_new_pseudos = 0; + if_convert (1); + no_new_pseudos = 1; - delete_trivially_dead_insns (insns, max_reg_num ()); + close_dump_file (DFI_ce2, print_rtl_with_bb, insns); + timevar_pop (TV_IFCVT); +} - /* If we are not running more CSE passes, then we are no longer - expecting CSE to be run. But always rerun it in a cheap mode. */ - cse_not_expected = !flag_rerun_cse_after_loop && !flag_gcse; +/* Do branch profiling and static profile estimation passes. */ +static void +rest_of_handle_branch_prob (tree decl, rtx insns) +{ + struct loops loops; - if (tem || optimize > 1) - cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); - /* Try to identify useless null pointer tests and delete them. */ - if (flag_delete_null_pointer_checks) - { - timevar_push (TV_JUMP); + timevar_push (TV_BRANCH_PROB); + open_dump_file (DFI_bp, decl); + if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities) + branch_prob (); - if (delete_null_pointer_checks (insns)) - cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); - timevar_pop (TV_JUMP); - } + /* 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); + + if (rtl_dump_file) + flow_loops_dump (&loops, rtl_dump_file, NULL, 0); - /* The second pass of jump optimization is likely to have - removed a bunch more instructions. */ - renumber_insns (rtl_dump_file); + /* Estimate using heuristics if no profiling info is available. */ + if (flag_guess_branch_prob) + estimate_probability (&loops); - timevar_pop (TV_CSE); - close_dump_file (DFI_cse, print_rtl_with_bb, insns); - } + flow_loops_free (&loops); + close_dump_file (DFI_bp, print_rtl_with_bb, insns); + timevar_pop (TV_BRANCH_PROB); +} + +/* Do control and data flow analysis; write some of the results to the + dump file. */ +static void +rest_of_handle_cfg (tree decl, rtx insns) +{ + open_dump_file (DFI_cfg, decl); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + if (optimize) + cleanup_cfg (CLEANUP_EXPENSIVE + | (flag_thread_jumps ? CLEANUP_THREADING : 0)); + + /* It may make more sense to mark constant functions after dead code is + eliminated by life_analysis, but we need to do it early, as -fprofile-arcs + may insert code making function non-constant, but we still must consider + it as constant, otherwise -fbranch-probabilities will not read data back. + + life_analysis rarely eliminates modification of external memory. + */ + if (optimize) + mark_constant_function (); + close_dump_file (DFI_cfg, print_rtl_with_bb, insns); +} + +/* Purge addressofs. */ +static void +rest_of_handle_addresof (tree decl, rtx insns) +{ open_dump_file (DFI_addressof, decl); purge_addressof (insns); @@ -2925,395 +2895,859 @@ rest_of_compilation (decl) reg_scan (insns, max_reg_num (), 1); close_dump_file (DFI_addressof, print_rtl, insns); +} - ggc_collect (); +/* We may have potential sibling or tail recursion sites. Select one + (of possibly multiple) methods of performing the call. */ +static void +rest_of_handle_sibling_calls (rtx insns) +{ + rtx insn; + optimize_sibling_and_tail_recursive_calls (); + + /* Recompute the CFG as sibling optimization clobbers it randomly. */ + free_bb_for_insn (); + find_exception_handler_labels (); + rebuild_jump_labels (insns); + find_basic_blocks (insns, max_reg_num (), rtl_dump_file); - /* Perform global cse. */ + /* There is pass ordering problem - we must lower NOTE_INSN_PREDICTION + notes before simplifying cfg and we must do lowering after sibcall + that unhides parts of RTL chain and cleans up the CFG. - if (optimize > 0 && flag_gcse) - { - int save_csb, save_cfj; - int tem2 = 0; + Until sibcall is replaced by tree-level optimizer, lets just + sweep away the NOTE_INSN_PREDICTION notes that leaked out. */ + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == NOTE + && NOTE_LINE_NUMBER (insn) == NOTE_INSN_PREDICTION) + delete_insn (insn); + + close_dump_file (DFI_sibling, print_rtl, get_insns ()); +} + +/* Perform jump bypassing and control flow optimizations. */ +static void +rest_of_handle_jump_bypass (tree decl, rtx insns) +{ + timevar_push (TV_BYPASS); + open_dump_file (DFI_bypass, decl); - timevar_push (TV_GCSE); - open_dump_file (DFI_gcse, decl); + cleanup_cfg (CLEANUP_EXPENSIVE); - tem = gcse_main (insns, rtl_dump_file); + if (bypass_jumps (rtl_dump_file)) + { rebuild_jump_labels (insns); + cleanup_cfg (CLEANUP_EXPENSIVE); 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; + close_dump_file (DFI_bypass, print_rtl_with_bb, insns); + timevar_pop (TV_BYPASS); - /* Instantiate any remaining CONSTANT_P_RTX nodes. */ - if (current_function_calls_constant_p) - purge_builtin_constant_p (); + ggc_collect (); - /* If -fexpensive-optimizations, re-run CSE to clean up things done - by gcse. */ - if (flag_expensive_optimizations) - { - timevar_push (TV_CSE); - reg_scan (insns, max_reg_num (), 1); - tem2 = cse_main (insns, max_reg_num (), 0, rtl_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; - } +#ifdef ENABLE_CHECKING + verify_flow_info (); +#endif +} - /* If gcse or cse altered any jumps, rerun jump optimizations to clean - things up. Then possibly re-run CSE again. */ - 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); +/* Handle inlining of functions in rest_of_compilation. Return TRUE + if we must exit rest_of_compilation upon return. */ +static bool +rest_of_handle_inlining (tree decl) +{ + rtx insns; + int inlinable = 0; + tree parent; + const char *lose; + + /* If we are reconsidering an inline function at the end of + compilation, skip the stuff for making it inline. */ + if (DECL_SAVED_INSNS (decl) != 0) + return 0; + + /* If this is nested inside an inlined external function, pretend + it was only declared. Since we cannot inline such functions, + generating code for this one is not only not necessary but will + confuse some debugging output writers. */ + for (parent = DECL_CONTEXT (current_function_decl); + parent != NULL_TREE; + parent = get_containing_scope (parent)) + if (TREE_CODE (parent) == FUNCTION_DECL + && DECL_INLINE (parent) && DECL_EXTERNAL (parent)) + { + DECL_INITIAL (decl) = 0; + return true; + } + else if (TYPE_P (parent)) + /* A function in a local class should be treated normally. */ + break; - if (flag_expensive_optimizations) + /* If requested, consider whether to make this function inline. */ + if ((DECL_INLINE (decl) && !flag_no_inline) + || flag_inline_functions) + { + timevar_push (TV_INTEGRATION); + lose = function_cannot_inline_p (decl); + timevar_pop (TV_INTEGRATION); + if (lose || ! optimize) + { + if (warn_inline && DECL_INLINE (decl)) + warning_with_decl (decl, lose); + DECL_ABSTRACT_ORIGIN (decl) = 0; + /* Don't really compile an extern inline function. + If we can't make it inline, pretend + it was only declared. */ + if (DECL_EXTERNAL (decl)) { - timevar_push (TV_CSE); - reg_scan (insns, max_reg_num (), 1); - tem2 = cse_main (insns, max_reg_num (), 0, rtl_dump_file); - purge_all_dead_edges (0); - delete_trivially_dead_insns (insns, max_reg_num ()); - timevar_pop (TV_CSE); + DECL_INITIAL (decl) = 0; + return true; } } - - 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 + else { + /* ??? Note that we used to just make it look like if + the "inline" keyword was specified when we decide + to inline it (because of -finline-functions). + garloff@suse.de, 2002-04-24: Add another flag to + actually record this piece of information. */ + if (!DECL_INLINE (decl)) + DID_INLINE_FUNC (decl) = 1; + inlinable = DECL_INLINE (decl) = 1; + } } - /* Move constant computations out of loops. */ + insns = get_insns (); + + /* Dump the rtl code if we are dumping rtl. */ - if (optimize > 0 && flag_loop_optimize) + if (open_dump_file (DFI_rtl, decl)) { - int do_unroll, do_prefetch; + if (DECL_SAVED_INSNS (decl)) + fprintf (rtl_dump_file, ";; (integrable)\n\n"); + close_dump_file (DFI_rtl, print_rtl, insns); + } - timevar_push (TV_LOOP); - delete_dead_jumptables (); - cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); - open_dump_file (DFI_loop, decl); - /* CFG is no longer maintained up-to-date. */ - free_bb_for_insn (); + /* Convert from NOTE_INSN_EH_REGION style notes, and do other + sorts of eh initialization. Delay this until after the + initial rtl dump so that we can see the original nesting. */ + convert_from_eh_region_ranges (); + + /* If function is inline, and we don't yet know whether to + compile it by itself, defer decision till end of compilation. + wrapup_global_declarations will (indirectly) call + rest_of_compilation again for those functions that need to + be output. Also defer those functions that we are supposed + to defer. */ + + if (inlinable + || (DECL_INLINE (decl) + && flag_inline_functions + && ((! TREE_PUBLIC (decl) && ! TREE_ADDRESSABLE (decl) + && ! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) + && ! flag_keep_inline_functions) + || DECL_EXTERNAL (decl)))) + DECL_DEFER_OUTPUT (decl) = 1; - if (flag_unroll_loops) - do_unroll = 0; /* 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) + if (DECL_INLINE (decl)) + /* DWARF wants separate debugging info for abstract and + concrete instances of all inline functions, including those + declared inline but not inlined, and those inlined even + though they weren't declared inline. Conveniently, that's + what DECL_INLINE means at this point. */ + (*debug_hooks->deferred_inline_function) (decl); + + if (DECL_DEFER_OUTPUT (decl)) + { + /* If -Wreturn-type, we have to do a bit of compilation. We just + want to call cleanup the cfg to figure out whether or not we can + fall off the end of the function; we do the minimum amount of + work necessary to make that safe. */ + if (warn_return_type) { - cleanup_barriers (); + int saved_optimize = optimize; - /* We only want to perform unrolling once. */ - loop_optimize (insns, rtl_dump_file, do_unroll); - do_unroll = 0; - - /* The first call to loop_optimize makes some instructions - trivially dead. We delete those instructions now in the - hope that doing so will make the heuristics in loop work - better and possibly speed up compilation. */ - delete_trivially_dead_insns (insns, max_reg_num ()); + optimize = 0; + rebuild_jump_labels (insns); + find_exception_handler_labels (); + find_basic_blocks (insns, max_reg_num (), rtl_dump_file); + cleanup_cfg (CLEANUP_PRE_SIBCALL | CLEANUP_PRE_LOOP); + optimize = saved_optimize; - /* The regscan pass is currently necessary as the alias - analysis code depends on this information. */ - reg_scan (insns, max_reg_num (), 1); + /* CFG is no longer maintained up-to-date. */ + free_bb_for_insn (); } - cleanup_barriers (); - loop_optimize (insns, rtl_dump_file, do_unroll | LOOP_BCT | do_prefetch); - - /* Loop can create trivially dead instructions. */ - 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 (), rtl_dump_file); - ggc_collect (); + set_nothrow_function_flags (); + if (current_function_nothrow) + /* Now we know that this can't throw; set the flag for the benefit + of other functions later in this translation unit. */ + TREE_NOTHROW (current_function_decl) = 1; + + timevar_push (TV_INTEGRATION); + save_for_inline (decl); + timevar_pop (TV_INTEGRATION); + DECL_SAVED_INSNS (decl)->inlinable = inlinable; + return true; } - /* Perform jump bypassing and control flow optimizations. */ - if (optimize > 0 && flag_gcse) - { - timevar_push (TV_BYPASS); - open_dump_file (DFI_bypass, decl); + /* If specified extern inline but we aren't inlining it, we are + done. This goes for anything that gets here with DECL_EXTERNAL + set, not just things with DECL_INLINE. */ + return (bool) DECL_EXTERNAL (decl); +} - cleanup_cfg (CLEANUP_EXPENSIVE); - tem = bypass_jumps (rtl_dump_file); +/* Rest of compilation helper to convert the rtl to SSA form. */ +static rtx +rest_of_handle_ssa (tree decl, rtx insns) +{ + timevar_push (TV_TO_SSA); + open_dump_file (DFI_ssa, decl); - if (tem) - { - rebuild_jump_labels (insns); - cleanup_cfg (CLEANUP_EXPENSIVE); - delete_trivially_dead_insns (insns, max_reg_num ()); - } + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); + convert_to_ssa (); - close_dump_file (DFI_bypass, print_rtl_with_bb, insns); - timevar_pop (TV_BYPASS); + close_dump_file (DFI_ssa, print_rtl_with_bb, insns); + timevar_pop (TV_TO_SSA); - ggc_collect (); + /* Perform sparse conditional constant propagation, if requested. */ + if (flag_ssa_ccp) + { + timevar_push (TV_SSA_CCP); + open_dump_file (DFI_ssa_ccp, decl); -#ifdef ENABLE_CHECKING - verify_flow_info (); -#endif + ssa_const_prop (); + + close_dump_file (DFI_ssa_ccp, print_rtl_with_bb, get_insns ()); + timevar_pop (TV_SSA_CCP); } - /* Do control and data flow analysis; wrote some of the results to - the dump file. */ + /* It would be useful to cleanup the CFG at this point, but block + merging and possibly other transformations might leave a PHI + node in the middle of a basic block, which is a strict no-no. */ - timevar_push (TV_FLOW); - open_dump_file (DFI_cfg, decl); - if (rtl_dump_file) - dump_flow_info (rtl_dump_file); - if (optimize) - cleanup_cfg (CLEANUP_EXPENSIVE - | (flag_thread_jumps ? CLEANUP_THREADING : 0)); + /* The SSA implementation uses basic block numbers in its phi + nodes. Thus, changing the control-flow graph or the basic + blocks, e.g., calling find_basic_blocks () or cleanup_cfg (), + may cause problems. */ - /* It may make more sense to mark constant functions after dead code is - eliminated by life_analysis, but we need to do it early, as -fprofile-arcs - may insert code making function non-constant, but we still must consider - it as constant, otherwise -fbranch-probabilities will not read data back. + if (flag_ssa_dce) + { + /* Remove dead code. */ - life_analysis rarely eliminates modification of external memory. - */ - if (optimize) - mark_constant_function (); + timevar_push (TV_SSA_DCE); + open_dump_file (DFI_ssa_dce, decl); - close_dump_file (DFI_cfg, print_rtl_with_bb, insns); + insns = get_insns (); + ssa_eliminate_dead_code (); - /* Do branch profiling and static profile estimation passes. */ - if (optimize > 0 - || profile_arc_flag || flag_test_coverage || flag_branch_probabilities) - { - struct loops loops; + close_dump_file (DFI_ssa_dce, print_rtl_with_bb, insns); + timevar_pop (TV_SSA_DCE); + } - timevar_push (TV_BRANCH_PROB); - open_dump_file (DFI_bp, decl); - if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities) - branch_prob (); + /* Convert from SSA form. */ - /* 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); + timevar_push (TV_FROM_SSA); + open_dump_file (DFI_ussa, decl); - if (rtl_dump_file) - flow_loops_dump (&loops, rtl_dump_file, NULL, 0); + convert_from_ssa (); + /* New registers have been created. Rescan their usage. */ + reg_scan (insns, max_reg_num (), 1); - /* Estimate using heuristics if no profiling info is available. */ - if (flag_guess_branch_prob) - estimate_probability (&loops); + close_dump_file (DFI_ussa, print_rtl_with_bb, insns); + timevar_pop (TV_FROM_SSA); - flow_loops_free (&loops); - close_dump_file (DFI_bp, print_rtl_with_bb, insns); - timevar_pop (TV_BRANCH_PROB); + ggc_collect (); + + return insns; +} + +/* Try to identify useless null pointer tests and delete them. */ +static void +rest_of_handle_null_pointer (tree decl, rtx insns) +{ + open_dump_file (DFI_null, decl); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + + if (delete_null_pointer_checks (insns)) + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); + + close_dump_file (DFI_null, print_rtl_with_bb, insns); +} + +/* Try combining insns through substitution. */ +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 ()); + + /* Combining insns may have turned an indirect jump into a + direct jump. Rebuild the JUMP_LABEL fields of jumping + instructions. */ + 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); } - if (optimize > 0) + + close_dump_file (DFI_combine, print_rtl_with_bb, insns); + timevar_pop (TV_COMBINE); + + ggc_collect (); +} + +/* Perform life analysis. */ +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 (insns, rtl_dump_file, PROP_FINAL); + if (optimize) + cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_UPDATE_LIFE + | (flag_thread_jumps ? CLEANUP_THREADING : 0)); + timevar_pop (TV_FLOW); + + if (warn_uninitialized) { - open_dump_file (DFI_ce1, decl); - if (flag_if_conversion) + uninitialized_vars_warning (DECL_INITIAL (decl)); + if (extra_warnings) + setjmp_args_warning (); + } + + if (optimize) + { + if (!flag_new_regalloc && initialize_uninitialized_subregs ()) { - timevar_push (TV_IFCVT); - if (rtl_dump_file) - dump_flow_info (rtl_dump_file); - cleanup_cfg (CLEANUP_EXPENSIVE); - reg_scan (insns, max_reg_num (), 0); - if_convert (0); - timevar_pop (TV_IFCVT); + /* Insns were inserted, and possibly pseudos created, so + things might look a bit different. */ + 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 (); +} + +/* Perform common subexpression elimination. Nonzero value from + `cse_main' means that jumps were simplified and some code may now + be unreachable, so do jump optimization again. */ +static void +rest_of_handle_cse (tree decl, rtx insns) +{ + int tem; + + open_dump_file (DFI_cse, decl); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + timevar_push (TV_CSE); + + reg_scan (insns, max_reg_num (), 1); + + tem = cse_main (insns, max_reg_num (), 0, rtl_dump_file); + if (tem) + rebuild_jump_labels (insns); + purge_all_dead_edges (0); + + delete_trivially_dead_insns (insns, max_reg_num ()); + + /* If we are not running more CSE passes, then we are no longer + 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 || optimize > 1) + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); + /* Try to identify useless null pointer tests and delete them. */ + if (flag_delete_null_pointer_checks) + { timevar_push (TV_JUMP); - cleanup_cfg (CLEANUP_EXPENSIVE); - reg_scan (insns, max_reg_num (), 0); + + if (delete_null_pointer_checks (insns)) + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); timevar_pop (TV_JUMP); - close_dump_file (DFI_ce1, print_rtl_with_bb, get_insns ()); } - if (flag_tracer) + + /* The second pass of jump optimization is likely to have + removed a bunch more instructions. */ + renumber_insns (rtl_dump_file); + + timevar_pop (TV_CSE); + close_dump_file (DFI_cse, print_rtl_with_bb, insns); +} + +/* Run second CSE pass after loop optimizations. */ +static void +rest_of_handle_cse2 (tree decl, rtx insns) +{ + int tem; + + timevar_push (TV_CSE2); + open_dump_file (DFI_cse2, decl); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + /* CFG is no longer maintained up-to-date. */ + tem = cse_main (insns, max_reg_num (), 1, rtl_dump_file); + purge_all_dead_edges (0); + delete_trivially_dead_insns (insns, max_reg_num ()); + + if (tem) { - timevar_push (TV_TRACER); - open_dump_file (DFI_tracer, decl); - if (rtl_dump_file) - dump_flow_info (rtl_dump_file); - tracer (); + timevar_push (TV_JUMP); + rebuild_jump_labels (insns); cleanup_cfg (CLEANUP_EXPENSIVE); - reg_scan (insns, max_reg_num (), 0); - close_dump_file (DFI_tracer, print_rtl_with_bb, get_insns ()); - timevar_pop (TV_TRACER); + 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); +} - /* Perform loop optimalizations. It might be better to do them a bit - sooner, but we want the profile feedback to work more efficiently. */ - if (optimize > 0 - && (flag_unswitch_loops - || flag_peel_loops - || flag_unroll_loops)) - { - struct loops *loops; - timevar_push (TV_LOOP); - open_dump_file (DFI_loop2, decl); - if (rtl_dump_file) - dump_flow_info (rtl_dump_file); +/* Perform global cse. */ +static void +rest_of_handle_gcse (tree decl, rtx insns) +{ + int save_csb, save_cfj; + int tem2 = 0, tem; - loops = loop_optimizer_init (rtl_dump_file); + timevar_push (TV_GCSE); + open_dump_file (DFI_gcse, decl); - if (loops) - { - /* The optimalizations: */ - if (flag_unswitch_loops) - unswitch_loops (loops); + tem = gcse_main (insns, rtl_dump_file); + rebuild_jump_labels (insns); + delete_trivially_dead_insns (insns, max_reg_num ()); - 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)); + save_csb = flag_cse_skip_blocks; + save_cfj = flag_cse_follow_jumps; + flag_cse_skip_blocks = flag_cse_follow_jumps = 0; - loop_optimizer_finalize (loops, rtl_dump_file); - } + /* Instantiate any remaining CONSTANT_P_RTX nodes. */ + if (current_function_calls_constant_p) + purge_builtin_constant_p (); - cleanup_cfg (CLEANUP_EXPENSIVE); + /* If -fexpensive-optimizations, re-run CSE to clean up things done + by gcse. */ + if (flag_expensive_optimizations) + { + timevar_push (TV_CSE); + reg_scan (insns, max_reg_num (), 1); + tem2 = cse_main (insns, max_reg_num (), 0, rtl_dump_file); + purge_all_dead_edges (0); delete_trivially_dead_insns (insns, max_reg_num ()); - reg_scan (insns, max_reg_num (), 0); - if (rtl_dump_file) - dump_flow_info (rtl_dump_file); - close_dump_file (DFI_loop2, print_rtl_with_bb, get_insns ()); - timevar_pop (TV_LOOP); - ggc_collect (); + timevar_pop (TV_CSE); + cse_not_expected = !flag_rerun_cse_after_loop; } - if (flag_rerun_cse_after_loop) + /* If gcse or cse altered any jumps, rerun jump optimizations to clean + things up. Then possibly re-run CSE again. */ + while (tem || tem2) { - timevar_push (TV_CSE2); - open_dump_file (DFI_cse2, decl); - if (rtl_dump_file) - dump_flow_info (rtl_dump_file); - /* CFG is no longer maintained up-to-date. */ - tem = cse_main (insns, max_reg_num (), 1, rtl_dump_file); - purge_all_dead_edges (0); - delete_trivially_dead_insns (insns, max_reg_num ()); + tem = tem2 = 0; + timevar_push (TV_JUMP); + rebuild_jump_labels (insns); + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); + timevar_pop (TV_JUMP); - if (tem) + if (flag_expensive_optimizations) { - timevar_push (TV_JUMP); - rebuild_jump_labels (insns); - cleanup_cfg (CLEANUP_EXPENSIVE); - timevar_pop (TV_JUMP); + timevar_push (TV_CSE); + reg_scan (insns, max_reg_num (), 1); + tem2 = cse_main (insns, max_reg_num (), 0, rtl_dump_file); + purge_all_dead_edges (0); + delete_trivially_dead_insns (insns, max_reg_num ()); + timevar_pop (TV_CSE); } - reg_scan (insns, max_reg_num (), 0); - close_dump_file (DFI_cse2, print_rtl_with_bb, insns); - ggc_collect (); - timevar_pop (TV_CSE2); } - cse_not_expected = 1; - - open_dump_file (DFI_life, decl); - regclass_init (); + 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 - life_analysis (insns, rtl_dump_file, PROP_FINAL); - if (optimize) - cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_UPDATE_LIFE - | (flag_thread_jumps ? CLEANUP_THREADING : 0)); - timevar_pop (TV_FLOW); +} + +/* Move constant computations out of loops. */ +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); + + /* CFG is no longer maintained up-to-date. */ + free_bb_for_insn (); + + if (flag_unroll_loops) + do_unroll = 0; /* 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 (insns, rtl_dump_file, do_unroll); + do_unroll = 0; + + /* The first call to loop_optimize makes some instructions + trivially dead. We delete those instructions now in the + hope that doing so will make the heuristics in loop work + better and possibly speed up compilation. */ + delete_trivially_dead_insns (insns, max_reg_num ()); + + /* The regscan pass is currently necessary as the alias + analysis code depends on this information. */ + reg_scan (insns, max_reg_num (), 1); + } + cleanup_barriers (); + loop_optimize (insns, rtl_dump_file, do_unroll | LOOP_BCT | do_prefetch); + + /* Loop can create trivially dead instructions. */ + 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 (), rtl_dump_file); + + ggc_collect (); +} + +/* Perform loop optimalizations. It might be better to do them a bit + sooner, but we want the profile feedback to work more + efficiently. */ +static void +rest_of_handle_loop2 (tree decl, rtx insns) +{ + struct loops *loops; + timevar_push (TV_LOOP); + open_dump_file (DFI_loop2, decl); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + + loops = loop_optimizer_init (rtl_dump_file); + + if (loops) + { + /* The optimalizations: */ + 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)); + + loop_optimizer_finalize (loops, rtl_dump_file); + } + + cleanup_cfg (CLEANUP_EXPENSIVE); + delete_trivially_dead_insns (insns, max_reg_num ()); + reg_scan (insns, max_reg_num (), 0); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + close_dump_file (DFI_loop2, print_rtl_with_bb, get_insns ()); + timevar_pop (TV_LOOP); + ggc_collect (); +} + +/* This is called from finish_function (within langhooks.parse_file) + after each top-level definition is parsed. + It is supposed to compile that function or variable + and output the assembler code for it. + After we return, the tree storage is freed. */ + +void +rest_of_compilation (decl) + tree decl; +{ + rtx insns; + int rebuild_label_notes_after_reload; + + timevar_push (TV_REST_OF_COMPILATION); + + /* Now that we're out of the frontend, we shouldn't have any more + CONCATs anywhere. */ + generating_concat_p = 0; + + /* When processing delayed functions, prepare_function_start() won't + have been run to re-initialize it. */ + cse_not_expected = ! optimize; + + /* First, make sure that NOTE_BLOCK is set correctly for each + NOTE_INSN_BLOCK_BEG/NOTE_INSN_BLOCK_END note. */ + if (!cfun->x_whole_function_mode_p) + identify_blocks (); + + /* In function-at-a-time mode, we do not attempt to keep the BLOCK + tree in sensible shape. So, we just recalculate it here. */ + if (cfun->x_whole_function_mode_p) + reorder_blocks (); + + init_flow (); + + if (rest_of_handle_inlining (decl)) + goto exit_rest_of_compilation; + + /* If we're emitting a nested function, make sure its parent gets + emitted as well. Doing otherwise confuses debug info. */ + { + 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; + } + + /* We are now committed to emitting code for this function. Do any + preparation, such as emitting abstract debug info for the inline + before it gets mangled by optimization. */ + if (DECL_INLINE (decl)) + (*debug_hooks->outlining_inline_function) (decl); + + /* Remove any notes we don't need. That will make iterating + over the instruction sequence faster, and allow the garbage + collector to reclaim the memory used by the notes. */ + remove_unnecessary_notes (); + reorder_blocks (); + + ggc_collect (); + + /* Initialize some variables used by the optimizers. */ + init_function_for_compilation (); + + if (! DECL_DEFER_OUTPUT (decl)) + TREE_ASM_WRITTEN (decl) = 1; + + /* Now that integrate will no longer see our rtl, we need not + distinguish between the return value of this function and the + return value of called functions. Also, we can remove all SETs + of subregs of hard registers; they are only here because of + integrate. Also, we can now initialize pseudos intended to + carry magic hard reg data throughout the function. */ + rtx_equal_function_value_matters = 0; + purge_hard_subreg_sets (get_insns ()); + + /* Early return if there were errors. We can run afoul of our + consistency checks, and there's not really much point in fixing them. + Don't return yet if -Wreturn-type; we need to do cleanup_cfg. */ + 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 (), rtl_dump_file); + + delete_unreachable_blocks (); + + /* We have to issue these warnings now already, because CFG cleanups + further down may destroy the required information. */ + check_function_return_warnings (); + + /* Turn NOTE_INSN_PREDICTIONs into branch predictions. */ + if (flag_guess_branch_prob) + { + timevar_push (TV_BRANCH_PROB); + note_prediction_to_br_prob (); + timevar_pop (TV_BRANCH_PROB); + } + + if (flag_optimize_sibling_calls) + rest_of_handle_sibling_calls (insns); + + timevar_pop (TV_JUMP); + + scope_to_insns_initialize (); + /* Complete generation of exception handling code. */ + 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); + } + + /* Delay emitting hard_reg_initial_value sets until after EH landing pad + generation, which might create new sets. */ + emit_initial_value_sets (); + +#ifdef FINALIZE_PIC + /* If we are doing position-independent code generation, now + is the time to output special prologues and epilogues. + We do not want to do this earlier, because it just clutters + up inline functions with meaningless insns. */ + if (flag_pic) + FINALIZE_PIC; +#endif + + insns = get_insns (); + + /* Copy any shared structure that should not be shared. */ + unshare_all_rtl (current_function_decl, insns); + +#ifdef SETJMP_VIA_SAVE_AREA + /* This must be performed before virtual register instantiation. + Please be aware the everything in the compiler that can look + at the RTL up to this point must understand that REG_SAVE_AREA + is just like a use of the REG contained inside. */ + if (current_function_calls_alloca) + optimize_save_area_alloca (insns); +#endif + + /* Instantiate all virtual registers. */ + instantiate_virtual_regs (current_function_decl, insns); + + open_dump_file (DFI_jump, decl); + + /* Always do one jump optimization pass to ensure that JUMP_LABEL fields + are initialized and to compute whether control can drop off the end + of the function. */ + + timevar_push (TV_JUMP); + /* Turn NOTE_INSN_EXPECTED_VALUE into REG_BR_PROB. Do this + before jump optimization switches branch directions. */ + 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 (), rtl_dump_file); + delete_trivially_dead_insns (insns, max_reg_num ()); + if (rtl_dump_file) + dump_flow_info (rtl_dump_file); + cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_PRE_LOOP + | (flag_thread_jumps ? CLEANUP_THREADING : 0)); - if (warn_uninitialized) + if (optimize) { - uninitialized_vars_warning (DECL_INITIAL (decl)); - if (extra_warnings) - setjmp_args_warning (); + free_bb_for_insn (); + copy_loop_headers (insns); + find_basic_blocks (insns, max_reg_num (), rtl_dump_file); } + purge_line_number_notes (insns); + + timevar_pop (TV_JUMP); + close_dump_file (DFI_jump, print_rtl, insns); + + /* Now is when we stop if -fsyntax-only and -Wreturn-type. */ + if (rtl_dump_and_exit || flag_syntax_only || DECL_DEFER_OUTPUT (decl)) + goto exit_rest_of_compilation; + + /* Long term, this should probably move before the jump optimizer too, + but I didn't want to disturb the rtl_dump_and_exit and related + stuff at this time. */ + if (optimize > 0 && flag_ssa) + insns = rest_of_handle_ssa (decl, insns); + + timevar_push (TV_JUMP); if (optimize) - { - if (!flag_new_regalloc && initialize_uninitialized_subregs ()) - { - /* Insns were inserted, and possibly pseudos created, so - things might look a bit different. */ - 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); - } - } + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP); - no_new_pseudos = 1; + if (flag_delete_null_pointer_checks) + rest_of_handle_null_pointer (decl, insns); - close_dump_file (DFI_life, print_rtl_with_bb, insns); + /* Jump optimization, and the removal of NULL pointer checks, may + have reduced the number of instructions substantially. CSE, and + future passes, allocate arrays whose dimensions involve the + maximum instruction UID, so if we can reduce the maximum UID + we'll save big on memory. */ + renumber_insns (rtl_dump_file); + timevar_pop (TV_JUMP); + + close_dump_file (DFI_jump, print_rtl_with_bb, insns); ggc_collect (); - /* If -opt, try combining insns through substitution. */ + if (optimize > 0) + rest_of_handle_cse (decl, insns); + + rest_of_handle_addresof (decl, insns); + + ggc_collect (); if (optimize > 0) { - int rebuild_jump_labels_after_combine = 0; + if (flag_gcse) + rest_of_handle_gcse (decl, insns); - timevar_push (TV_COMBINE); - open_dump_file (DFI_combine, decl); + if (flag_loop_optimize) + rest_of_handle_loop_optimize (decl, insns); - rebuild_jump_labels_after_combine - = combine_instructions (insns, max_reg_num ()); + if (flag_gcse) + rest_of_handle_jump_bypass (decl, insns); + } - /* Combining insns may have turned an indirect jump into a - direct jump. Rebuild the JUMP_LABEL fields of jumping - instructions. */ - if (rebuild_jump_labels_after_combine) - { - timevar_push (TV_JUMP); - rebuild_jump_labels (insns); - timevar_pop (TV_JUMP); + timevar_push (TV_FLOW); - cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE); - } + rest_of_handle_cfg (decl, insns); - close_dump_file (DFI_combine, print_rtl_with_bb, insns); - timevar_pop (TV_COMBINE); + if (optimize > 0 + || profile_arc_flag || flag_test_coverage || flag_branch_probabilities) + rest_of_handle_branch_prob (decl, insns); - ggc_collect (); - } + if (optimize > 0) + rest_of_handle_if_conversion (decl, insns); - /* Rerun if-conversion, as combine may have simplified things enough to - now meet sequence length restrictions. */ - if (flag_if_conversion) - { - timevar_push (TV_IFCVT); - open_dump_file (DFI_ce2, decl); + if (flag_tracer) + rest_of_handle_tracer (decl, insns); - no_new_pseudos = 0; - if_convert (1); - no_new_pseudos = 1; + if (optimize > 0 + && (flag_unswitch_loops + || flag_peel_loops + || flag_unroll_loops)) + rest_of_handle_loop2 (decl, insns); - close_dump_file (DFI_ce2, print_rtl_with_bb, insns); - timevar_pop (TV_IFCVT); - } + if (flag_rerun_cse_after_loop) + rest_of_handle_cse2 (decl, insns); - /* Register allocation pre-pass, to reduce number of moves - necessary for two-address machines. */ - if (optimize > 0 && (flag_regmove || flag_expensive_optimizations)) - { - timevar_push (TV_REGMOVE); - open_dump_file (DFI_regmove, decl); + cse_not_expected = 1; - regmove_optimize (insns, max_reg_num (), rtl_dump_file); + rest_of_handle_life (decl, insns); - cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE); - close_dump_file (DFI_regmove, print_rtl_with_bb, insns); - timevar_pop (TV_REGMOVE); + if (optimize > 0) + rest_of_handle_combine (decl, insns); - ggc_collect (); - } + if (flag_if_conversion) + rest_of_handle_if_after_combine (decl, insns); + + if (optimize > 0 && (flag_regmove || flag_expensive_optimizations)) + rest_of_handle_regmove (decl, insns); /* Do unconditional splitting before register allocation to allow machine description to add extra information not needed previously. */ @@ -3334,27 +3768,7 @@ rest_of_compilation (decl) (see handling of reg_known_equiv in init_alias_analysis). */ recompute_reg_usage (insns, !optimize_size); - timevar_push (TV_SCHED); - -#ifdef INSN_SCHEDULING - - /* Print function header into sched dump now - because doing the sched analysis makes some of the dump. */ - if (optimize > 0 && flag_schedule_insns) - { - open_dump_file (DFI_sched, decl); - - /* Do control and data sched analysis, - and write some of the results to dump file. */ - - schedule_insns (rtl_dump_file); - - close_dump_file (DFI_sched, print_rtl_with_bb, insns); - } -#endif - timevar_pop (TV_SCHED); - - ggc_collect (); + rest_of_handle_sched (decl, insns); /* Determine if the current function is a leaf before running reload since this can impact optimizations done by the prologue and @@ -3364,104 +3778,16 @@ rest_of_compilation (decl) timevar_push (TV_LOCAL_ALLOC); open_dump_file (DFI_lreg, decl); - /* Allocate pseudo-regs that are used only within 1 basic block. - - RUN_JUMP_AFTER_RELOAD records whether or not we need to rerun the - jump optimizer after register allocation and reloading are finished. */ - if (flag_new_regalloc) { - delete_trivially_dead_insns (insns, max_reg_num ()); - reg_alloc (); - - timevar_pop (TV_LOCAL_ALLOC); - if (dump_file[DFI_lreg].enabled) - { - timevar_push (TV_DUMP); - - close_dump_file (DFI_lreg, NULL, NULL); - timevar_pop (TV_DUMP); - } - - /* XXX clean up the whole mess to bring live info in shape again. */ - 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[DFI_greg].enabled) - { - timevar_push (TV_DUMP); - - dump_global_regs (rtl_dump_file); - - close_dump_file (DFI_greg, print_rtl_with_bb, insns); - timevar_pop (TV_DUMP); - } - - if (failure) - goto exit_rest_of_compilation; - reload_completed = 1; - rebuild_label_notes_after_reload = 0; + if (rest_of_handle_new_regalloc (decl, insns, + &rebuild_label_notes_after_reload)) + goto exit_rest_of_compilation; } else { - /* Allocate the reg_renumber array. */ - allocate_reg_info (max_regno, FALSE, TRUE); - - /* And the reg_equiv_memory_loc array. */ - reg_equiv_memory_loc = (rtx *) xcalloc (max_regno, sizeof (rtx)); - - allocate_initial_values (reg_equiv_memory_loc); - - regclass (insns, max_reg_num (), rtl_dump_file); - rebuild_label_notes_after_reload = local_alloc (); - - timevar_pop (TV_LOCAL_ALLOC); - - if (dump_file[DFI_lreg].enabled) - { - timevar_push (TV_DUMP); - - dump_flow_info (rtl_dump_file); - dump_local_alloc (rtl_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 optimizing, allocate remaining pseudo-regs. Do the reload - pass fixing up any insns that are invalid. */ - - if (optimize) - failure = global_alloc (rtl_dump_file); - else - { - build_insn_chain (insns); - failure = reload (insns, 0); - } - - timevar_pop (TV_GLOBAL_ALLOC); - - if (dump_file[DFI_greg].enabled) - { - timevar_push (TV_DUMP); - - dump_global_regs (rtl_dump_file); - - close_dump_file (DFI_greg, print_rtl_with_bb, insns); - timevar_pop (TV_DUMP); - } - - if (failure) + if (rest_of_handle_old_regalloc (decl, insns, + &rebuild_label_notes_after_reload)) goto exit_rest_of_compilation; } @@ -3551,40 +3877,12 @@ rest_of_compilation (decl) } #endif - if (optimize > 0 && (flag_rename_registers || flag_cprop_registers)) - { - 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); - } - if (optimize > 0) { - timevar_push (TV_REORDER_BLOCKS); - open_dump_file (DFI_bbro, decl); - - /* Last attempt to optimize CFG, as scheduling, peepholing and insn - splitting possibly introduced more crossjumping opportunities. */ - cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE - | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0)); + if (flag_rename_registers || flag_cprop_registers) + rest_of_handle_regrename (decl, insns); - if (flag_sched2_use_traces && flag_schedule_insns_after_reload) - tracer (); - if (flag_reorder_blocks) - reorder_basic_blocks (); - if (flag_reorder_blocks - || (flag_sched2_use_traces && flag_schedule_insns_after_reload)) - cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE); - - close_dump_file (DFI_bbro, print_rtl_with_bb, insns); - timevar_pop (TV_REORDER_BLOCKS); + rest_of_handle_reorder_blocks (decl, insns); } if (flag_if_conversion2) @@ -3600,31 +3898,7 @@ rest_of_compilation (decl) #ifdef INSN_SCHEDULING if (optimize > 0 && flag_schedule_insns_after_reload) - { - timevar_push (TV_SCHED2); - open_dump_file (DFI_sched2, decl); - - /* Do control and data sched analysis again, - and write some more of the results to dump file. */ - - split_all_insns (1); - - if (flag_sched2_use_superblocks || flag_sched2_use_traces) - { - schedule_ebbs (rtl_dump_file); - /* No liveness updating code yet, but it should be easy to do. - reg-stack recompute the liveness when needed for now. */ - count_or_remove_death_notes (NULL, 1); - cleanup_cfg (CLEANUP_EXPENSIVE); - } - else - schedule_insns (rtl_dump_file); - - close_dump_file (DFI_sched2, print_rtl_with_bb, insns); - timevar_pop (TV_SCHED2); - - ggc_collect (); - } + rest_of_handle_sched2 (decl, insns); #endif #ifdef LEAF_REGISTERS @@ -3633,63 +3907,23 @@ rest_of_compilation (decl) #endif #ifdef STACK_REGS - timevar_push (TV_REG_STACK); - open_dump_file (DFI_stack, decl); - - if (reg_to_stack (insns, rtl_dump_file) && optimize) - { - if (cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_POST_REGSTACK - | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0)) - && flag_reorder_blocks) - { - 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 (); + rest_of_handle_stack_regs (decl, insns); #endif + compute_alignments (); /* CFG is no longer maintained up-to-date. */ free_bb_for_insn (); - /* If a machine dependent reorganization is needed, call it. */ if (targetm.machine_dependent_reorg != 0) - { - 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 (); - } + rest_of_handle_machine_reorg (decl, insns); purge_line_number_notes (insns); cleanup_barriers (); - /* If a scheduling pass for delayed branches is to be done, - call the scheduling code. */ - #ifdef DELAY_SLOTS if (optimize > 0 && flag_delayed_branch) - { - timevar_push (TV_DBR_SCHED); - open_dump_file (DFI_dbr, decl); - - dbr_schedule (insns, rtl_dump_file); - - close_dump_file (DFI_dbr, print_rtl, insns); - timevar_pop (TV_DBR_SCHED); - - ggc_collect (); - } + rest_of_handle_delay_slots (decl, insns); #endif #if defined (HAVE_ATTR_length) && !defined (STACK_REGS) @@ -3711,54 +3945,7 @@ rest_of_compilation (decl) of other functions later in this translation unit. */ TREE_NOTHROW (current_function_decl) = 1; - /* Now turn the rtl into assembler code. */ - - timevar_push (TV_FINAL); - { - rtx x; - const char *fnname; - - /* Get the function's name, as described by its RTL. This may be - different from the DECL_NAME name used in the source file. */ - - 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 - /* ??? The IA-64 ".handlerdata" directive must be issued before - the ".endp" directive that closes the procedure descriptor. */ - output_function_exception_table (); -#endif - - assemble_end_function (decl, fnname); - -#ifndef IA64_UNWIND_INFO - /* Otherwise, it feels unclean to switch sections in the middle. */ - output_function_exception_table (); -#endif - - if (! quiet_flag) - fflush (asm_out_file); - - /* Release all memory allocated by flow. */ - free_basic_block_vars (0); - - /* Release all memory held by regsets now. */ - regset_release_memory (); - } - timevar_pop (TV_FINAL); - - ggc_collect (); + rest_of_handle_final (decl, insns); /* Write DBX symbols if requested. */ @@ -3842,7 +4029,8 @@ rest_of_compilation (decl) timevar_pop (TV_REST_OF_COMPILATION); } - + +/* Display help for generic options. */ static void display_help () { @@ -3976,6 +4164,7 @@ display_help () display_target_options (); } +/* Display help for target options. */ static void display_target_options () { @@ -4045,7 +4234,7 @@ display_target_options () } } } - + /* Parse a -d... command line switch. */ static void @@ -4662,7 +4851,7 @@ independent_decode_option (argc, argv) return 1; } - + /* Decode -m switches. */ /* Decode the switch -mNAME. */ @@ -4717,7 +4906,7 @@ set_target_switch (name) if (!valid_target_option) error ("invalid option `%s'", name); } - + /* Print version information to FILE. Each line begins with INDENT (for the case where FILE is the assembler output file). */ @@ -4858,7 +5047,7 @@ print_switch_values (file, pos, max, indent, sep, term) fprintf (file, "%s", term); } - + /* Open assembly code output file. Do this even if -fsyntax-only is on, because then the driver will have provided the name of a temporary file or bit bucket for us. NAME is the file specified on @@ -4913,7 +5102,7 @@ init_asm_output (name) #endif } } - + /* Initialization of the front end environment, before command line options are parsed. Signal handlers, internationalization etc. ARGV0 is main's argv[0]. */ @@ -4967,7 +5156,7 @@ general_init (argv0) init_stringpool (); init_ttree (); } - + /* Parse command line options and set default flag values, called after language-independent option-independent initialization. Do minimal options processing. Outputting diagnostics is OK, but GC @@ -5217,7 +5406,7 @@ parse_options_and_default_flags (argc, argv) if (flag_really_no_inline == 2) flag_really_no_inline = flag_no_inline; } - + /* Process the options that have been parsed. */ static void process_options () @@ -5428,7 +5617,7 @@ process_options () if (flag_signaling_nans) flag_trapping_math = 1; } - + /* Initialize the compiler back end. */ static void backend_init () @@ -5459,7 +5648,7 @@ backend_init () init_caller_save (); expand_dummy_function_end (); } - + /* Language-dependent initialization. Returns nonzero on success. */ static int lang_dependent_init (name) @@ -5505,7 +5694,7 @@ lang_dependent_init (name) return 1; } - + /* Clean up: close opened files, etc. */ static void @@ -5562,7 +5751,7 @@ finalize () /* Language-specific end of compilation actions. */ (*lang_hooks.finish) (); } - + /* Initialize the compiler, and compile the input file. */ static void do_compile () @@ -5593,7 +5782,7 @@ do_compile () timevar_stop (TV_TOTAL); timevar_print (stderr); } - + /* Entry point of cc1, cc1plus, jc1, f771, etc. Decode command args, then call compile_file. Exit code is FATAL_EXIT_CODE if can't open files or if there were diff --git a/gcc/toplev.h b/gcc/toplev.h index 9271b6d..1f77e32 100644 --- a/gcc/toplev.h +++ b/gcc/toplev.h @@ -84,9 +84,6 @@ extern void output_clean_symbol_name PARAMS ((FILE *, const char *)); extern void output_quoted_string PARAMS ((FILE *, const char *)); extern void output_file_directive PARAMS ((FILE *, const char *)); #endif -extern void do_abort PARAMS ((void)) ATTRIBUTE_NORETURN; -extern void botch PARAMS ((const char *)) - ATTRIBUTE_NORETURN; #ifdef BUFSIZ /* N.B. Unlike all the others, fnotice is just gettext+fprintf, and