X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fpasses.c;h=9d8e2dade617f9af63c9dc735ca12ba823a82001;hb=44fcef54e407a058a5a1ed8f9e372deb3bff9d10;hp=4b50a1f5a4112cc43073e11de475a79e09b54736;hpb=011e6b51aaaaa628b204812a1714ada9e8092c87;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/passes.c b/gcc/passes.c index 4b50a1f5a41..9d8e2dade61 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -1,6 +1,6 @@ /* 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. @@ -60,7 +60,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "intl.h" #include "ggc.h" #include "graph.h" -#include "loop.h" #include "regs.h" #include "timevar.h" #include "diagnostic.h" @@ -79,8 +78,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "opts.h" #include "coverage.h" #include "value-prof.h" -#include "alloc-pool.h" #include "tree-pass.h" +#include "tree-dump.h" #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO) #include "dwarf2out.h" @@ -108,166 +107,26 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #define DUMPFILE_FORMAT ".%02d." #endif -/* Describes a dump file. */ - -struct dump_file_info -{ - /* The unique extension to apply, e.g. ".jump". */ - const char *const extension; - - /* The -d character that enables this dump file. */ - char const debug_switch; - - /* True if there is a corresponding graph dump file. */ - char const graph_dump_p; - - /* True if the user selected this dump. */ - char enabled; - - /* True if the files have been initialized (ie truncated). */ - char initialized; -}; - -/* Enumerate the extant dump files. */ - -enum dump_file_index -{ - DFI_cgraph, - DFI_rtl, - DFI_sibling, - DFI_eh, - DFI_jump, - DFI_null, - DFI_cse, - DFI_gcse, - DFI_loop, - DFI_bypass, - DFI_cfg, - DFI_bp, - DFI_vpt, - DFI_ce1, - DFI_tracer, - DFI_loop2, - DFI_web, - DFI_cse2, - DFI_life, - DFI_combine, - DFI_ce2, - DFI_regmove, - DFI_sms, - DFI_sched, - DFI_lreg, - DFI_greg, - DFI_postreload, - DFI_gcse2, - DFI_flow2, - DFI_peephole2, - DFI_ce3, - DFI_rnreg, - DFI_bbro, - DFI_branch_target_load, - DFI_sched2, - DFI_stack, - DFI_vartrack, - DFI_mach, - DFI_dbr, - DFI_MAX -}; - -/* Describes all the dump files. Should be kept in order of the - pass and in sync with dump_file_index above. - - Remaining -d letters: - - " e q " - " F K O Q WXY " -*/ - -static struct dump_file_info dump_file_tbl[DFI_MAX] = -{ - { "cgraph", 'U', 0, 0, 0 }, - { "rtl", 'r', 0, 0, 0 }, - { "sibling", 'i', 0, 0, 0 }, - { "eh", 'h', 0, 0, 0 }, - { "jump", 'j', 0, 0, 0 }, - { "null", 'u', 0, 0, 0 }, - { "cse", 's', 0, 0, 0 }, - { "gcse", 'G', 1, 0, 0 }, - { "loop", 'L', 1, 0, 0 }, - { "bypass", 'G', 1, 0, 0 }, /* Yes, duplicate enable switch. */ - { "cfg", 'f', 1, 0, 0 }, - { "bp", 'b', 1, 0, 0 }, - { "vpt", 'V', 1, 0, 0 }, - { "ce1", 'C', 1, 0, 0 }, - { "tracer", 'T', 1, 0, 0 }, - { "loop2", 'L', 1, 0, 0 }, - { "web", 'Z', 0, 0, 0 }, - { "cse2", 't', 1, 0, 0 }, - { "life", 'f', 1, 0, 0 }, /* Yes, duplicate enable switch. */ - { "combine", 'c', 1, 0, 0 }, - { "ce2", 'C', 1, 0, 0 }, - { "regmove", 'N', 1, 0, 0 }, - { "sms", 'm', 0, 0, 0 }, - { "sched", 'S', 1, 0, 0 }, - { "lreg", 'l', 1, 0, 0 }, - { "greg", 'g', 1, 0, 0 }, - { "postreload", 'o', 1, 0, 0 }, - { "gcse2", 'J', 0, 0, 0 }, - { "flow2", 'w', 1, 0, 0 }, - { "peephole2", 'z', 1, 0, 0 }, - { "ce3", 'E', 1, 0, 0 }, - { "rnreg", 'n', 1, 0, 0 }, - { "bbro", 'B', 1, 0, 0 }, - { "btl", 'd', 1, 0, 0 }, /* Yes, duplicate enable switch. */ - { "sched2", 'R', 1, 0, 0 }, - { "stack", 'k', 1, 0, 0 }, - { "vartrack", 'V', 1, 0, 0 }, /* Yes, duplicate enable switch. */ - { "mach", 'M', 1, 0, 0 }, - { "dbr", 'd', 0, 0, 0 }, -}; +static int initializing_dump = 0; /* Routine to open a dump file. Return true if the dump file is enabled. */ static int -open_dump_file (enum dump_file_index index, tree decl) +open_dump_file (enum tree_dump_index index, tree decl) { - char *dump_name; - const char *open_arg; - char seq[16]; - - if (! dump_file_tbl[index].enabled) + if (! dump_enabled_p (index)) return 0; timevar_push (TV_DUMP); - if (dump_file != NULL) - fclose (dump_file); - - sprintf (seq, DUMPFILE_FORMAT, index); - if (! dump_file_tbl[index].initialized) - { - /* If we've not initialized the files, do so now. */ - if (graph_dump_format != no_graph - && dump_file_tbl[index].graph_dump_p) - { - dump_name = concat (seq, dump_file_tbl[index].extension, NULL); - clean_graph_dump_file (dump_base_name, dump_name); - free (dump_name); - } - dump_file_tbl[index].initialized = 1; - open_arg = "w"; - } - else - open_arg = "a"; + gcc_assert (!dump_file && !dump_file_name); - dump_name = concat (dump_base_name, seq, - dump_file_tbl[index].extension, NULL); + dump_file_name = get_dump_file_name (index); + initializing_dump = !dump_initialized_p (index); + dump_file = dump_begin (index, NULL); - dump_file = fopen (dump_name, open_arg); if (dump_file == NULL) - fatal_error ("can't open %s: %m", dump_name); - - free (dump_name); + fatal_error ("can't open %s: %m", dump_file_name); if (decl) fprintf (dump_file, "\n;; Function %s%s\n\n", @@ -285,7 +144,7 @@ open_dump_file (enum dump_file_index index, tree decl) /* Routine to close a dump file. */ static void -close_dump_file (enum dump_file_index index, +close_dump_file (enum tree_dump_index index, void (*func) (FILE *, rtx), rtx insns) { @@ -294,25 +153,23 @@ close_dump_file (enum dump_file_index index, timevar_push (TV_DUMP); if (insns - && graph_dump_format != no_graph - && dump_file_tbl[index].graph_dump_p) + && graph_dump_format != no_graph) { - char seq[16]; - char *suffix; + /* If we've not initialized the files, do so now. */ + if (initializing_dump) + clean_graph_dump_file (dump_file_name); - sprintf (seq, DUMPFILE_FORMAT, index); - suffix = concat (seq, dump_file_tbl[index].extension, NULL); - print_rtl_graph_with_bb (dump_base_name, suffix, insns); - free (suffix); + print_rtl_graph_with_bb (dump_file_name, insns); } if (func && insns) func (dump_file, insns); - fflush (dump_file); - fclose (dump_file); + dump_end (index, dump_file); + free ((char *) dump_file_name); dump_file = NULL; + dump_file_name = NULL; timevar_pop (TV_DUMP); } @@ -320,18 +177,16 @@ close_dump_file (enum dump_file_index index, and TYPE_DECL nodes. This does nothing for local (non-static) variables, unless the - variable is a register variable with an ASMSPEC. In that case, or - if the variable is not an automatic, it sets up the RTL and - outputs any assembler code (label definition, storage allocation - and initialization). + variable is a register variable with DECL_ASSEMBLER_NAME set. In + that case, or if the variable is not an automatic, it sets up the + RTL and outputs any assembler code (label definition, storage + allocation and initialization). - DECL is the declaration. If ASMSPEC is nonzero, it specifies - the assembler symbol name to be used. TOP_LEVEL is nonzero + DECL is the declaration. TOP_LEVEL is nonzero if this declaration is not within a function. */ void rest_of_decl_compilation (tree decl, - const char *asmspec, int top_level, int at_end) { @@ -348,6 +203,11 @@ rest_of_decl_compilation (tree decl, } } + /* Can't defer this, because it needs to happen before any + later function definitions are processed. */ + if (DECL_REGISTER (decl) && DECL_ASSEMBLER_NAME_SET_P (decl)) + make_decl_rtl (decl); + /* Forward declarations for nested functions are not "external", but we need to treat them as if they were. */ if (TREE_STATIC (decl) || DECL_EXTERNAL (decl) @@ -355,9 +215,6 @@ rest_of_decl_compilation (tree decl, { timevar_push (TV_VARCONST); - if (asmspec) - make_decl_rtl (decl, asmspec); - /* Don't output anything when a tentative file-scope definition is seen. But at end of compilation, do output code for them. @@ -366,18 +223,11 @@ rest_of_decl_compilation (tree decl, (see gcc.c-torture/compile/920624-1.c) */ if ((at_end || !DECL_DEFER_OUTPUT (decl) - || (flag_unit_at_a_time && DECL_INITIAL (decl))) + || DECL_INITIAL (decl)) && !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); @@ -393,28 +243,16 @@ rest_of_decl_compilation (tree decl, timevar_pop (TV_VARCONST); } - else if (DECL_REGISTER (decl) && asmspec != 0) - { - if (decode_reg_name (asmspec) >= 0) - { - SET_DECL_RTL (decl, NULL_RTX); - make_decl_rtl (decl, asmspec); - } - else - { - error ("%Hinvalid register name `%s' for register variable", - &DECL_SOURCE_LOCATION (decl), asmspec); - DECL_REGISTER (decl) = 0; - if (!top_level) - expand_decl (decl); - } - } else if (TREE_CODE (decl) == TYPE_DECL) { timevar_push (TV_SYMOUT); debug_hooks->type_decl (decl, !top_level); timevar_pop (TV_SYMOUT); } + + /* Let cgraph know about the existence of variables. */ + if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)) + cgraph_varpool_node (decl); } /* Called after finishing a record, union or enumeral type. */ @@ -445,16 +283,14 @@ rest_of_handle_final (void) different from the DECL_NAME name used in the source file. */ x = DECL_RTL (current_function_decl); - if (!MEM_P (x)) - abort (); + gcc_assert (MEM_P (x)); x = XEXP (x, 0); - if (GET_CODE (x) != SYMBOL_REF) - abort (); + gcc_assert (GET_CODE (x) == SYMBOL_REF); fnname = XSTR (x, 0); assemble_start_function (current_function_decl, fnname); final_start_function (get_insns (), asm_out_file, optimize); - final (get_insns (), asm_out_file, optimize, 0); + final (get_insns (), asm_out_file, optimize); final_end_function (); #ifdef TARGET_UNWIND_INFO @@ -470,14 +306,13 @@ rest_of_handle_final (void) output_function_exception_table (); #endif + user_defined_section_attribute = false; + if (! quiet_flag) fflush (asm_out_file); /* 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. */ @@ -493,6 +328,7 @@ rest_of_handle_final (void) timevar_push (TV_SYMOUT); (*debug_hooks->function_decl) (current_function_decl); + timevar_pop (TV_SYMOUT); ggc_collect (); @@ -561,7 +397,7 @@ rest_of_handle_stack_regs (void) } #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) { @@ -590,49 +426,6 @@ rest_of_handle_machine_reorg (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_file_tbl[DFI_greg].enabled) - { - 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 @@ -666,12 +459,13 @@ rest_of_handle_old_regalloc (void) timevar_push (TV_JUMP); rebuild_jump_labels (get_insns ()); - purge_all_dead_edges (0); + purge_all_dead_edges (); + delete_unreachable_blocks (); timevar_pop (TV_JUMP); } - if (dump_file_tbl[DFI_lreg].enabled) + if (dump_enabled_p (DFI_lreg)) { timevar_push (TV_DUMP); dump_flow_info (dump_file); @@ -697,7 +491,7 @@ rest_of_handle_old_regalloc (void) failure = reload (get_insns (), 0); } - if (dump_file_tbl[DFI_greg].enabled) + if (dump_enabled_p (DFI_greg)) { timevar_push (TV_DUMP); dump_global_regs (dump_file); @@ -778,24 +572,38 @@ rest_of_handle_partition_blocks (void) static void rest_of_handle_sms (void) { + basic_block bb; + sbitmap blocks; + timevar_push (TV_SMS); open_dump_file (DFI_sms, current_function_decl); /* We want to be able to create new pseudos. */ no_new_pseudos = 0; + /* Collect loop information to be used in SMS. */ + cfg_layout_initialize (CLEANUP_UPDATE_LIFE); sms_schedule (dump_file); close_dump_file (DFI_sms, print_rtl, get_insns ()); - /* 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; + /* Finalize layout changes. */ + FOR_EACH_BB (bb) + if (bb->next_bb != EXIT_BLOCK_PTR) + bb->rbi->next = bb->next_bb; + cfg_layout_finalize (); + free_dominance_info (CDI_DOMINATORS); ggc_collect (); timevar_pop (TV_SMS); } @@ -855,10 +663,10 @@ rest_of_handle_sched2 (void) static void rest_of_handle_gcse2 (void) { - timevar_push (TV_RELOAD_CSE_REGS); + timevar_push (TV_GCSE_AFTER_RELOAD); open_dump_file (DFI_gcse2, current_function_decl); - gcse_after_reload_main (get_insns (), dump_file); + gcse_after_reload_main (get_insns ()); rebuild_jump_labels (get_insns ()); delete_trivially_dead_insns (get_insns (), max_reg_num ()); close_dump_file (DFI_gcse2, print_rtl_with_bb, get_insns ()); @@ -869,7 +677,7 @@ rest_of_handle_gcse2 (void) verify_flow_info (); #endif - timevar_pop (TV_RELOAD_CSE_REGS); + timevar_pop (TV_GCSE_AFTER_RELOAD); } /* Register allocation pre-pass, to reduce number of moves necessary @@ -898,7 +706,7 @@ rest_of_handle_tracer (void) 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 ()); } @@ -914,13 +722,13 @@ rest_of_handle_if_conversion (void) 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 ()); @@ -971,7 +779,7 @@ rest_of_handle_web (void) 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. */ @@ -988,7 +796,7 @@ rest_of_handle_branch_prob (void) /* 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); @@ -1035,12 +843,19 @@ rest_of_handle_cfg (void) 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 (); } @@ -1055,7 +870,7 @@ rest_of_handle_jump_bypass (void) 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)) { @@ -1095,6 +910,7 @@ rest_of_handle_combine (void) rebuild_jump_labels (get_insns ()); timevar_pop (TV_JUMP); + delete_dead_jumptables (); cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE); } @@ -1116,8 +932,7 @@ rest_of_handle_life (void) #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) @@ -1128,7 +943,7 @@ rest_of_handle_life (void) 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. */ @@ -1158,12 +973,12 @@ rest_of_handle_cse (void) 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 (), 0, dump_file); + tem = cse_main (get_insns (), max_reg_num (), dump_file); if (tem) rebuild_jump_labels (get_insns ()); - if (purge_all_dead_edges (0)) + if (purge_all_dead_edges ()) delete_unreachable_blocks (); delete_trivially_dead_insns (get_insns (), max_reg_num ()); @@ -1172,6 +987,9 @@ rest_of_handle_cse (void) 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); @@ -1192,7 +1010,7 @@ rest_of_handle_cse2 (void) if (dump_file) dump_flow_info (dump_file); /* CFG is no longer maintained up-to-date. */ - tem = cse_main (get_insns (), max_reg_num (), 1, dump_file); + tem = cse_main (get_insns (), max_reg_num (), dump_file); /* Run a pass to eliminate duplicated assignments to condition code registers. We have to run this after bypass_jumps, because it @@ -1200,17 +1018,18 @@ rest_of_handle_cse2 (void) bypassed safely. */ cse_condition_code_reg (); - purge_all_dead_edges (0); + purge_all_dead_edges (); delete_trivially_dead_insns (get_insns (), max_reg_num ()); if (tem) { timevar_push (TV_JUMP); rebuild_jump_labels (get_insns ()); + delete_dead_jumptables (); cleanup_cfg (CLEANUP_EXPENSIVE); timevar_pop (TV_JUMP); } - reg_scan (get_insns (), max_reg_num (), 0); + reg_scan (get_insns (), max_reg_num ()); close_dump_file (DFI_cse2, print_rtl_with_bb, get_insns ()); timevar_pop (TV_CSE2); @@ -1240,33 +1059,23 @@ rest_of_handle_gcse (void) if (flag_expensive_optimizations) { timevar_push (TV_CSE); - reg_scan (get_insns (), max_reg_num (), 1); - tem2 = cse_main (get_insns (), max_reg_num (), 0, dump_file); - purge_all_dead_edges (0); + reg_scan (get_insns (), max_reg_num ()); + tem2 = cse_main (get_insns (), max_reg_num (), dump_file); + purge_all_dead_edges (); delete_trivially_dead_insns (get_insns (), max_reg_num ()); timevar_pop (TV_CSE); cse_not_expected = !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) + 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 (), 0, 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 ()); @@ -1284,20 +1093,15 @@ rest_of_handle_gcse (void) 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) @@ -1305,8 +1109,7 @@ rest_of_handle_loop_optimize (void) 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 @@ -1316,14 +1119,14 @@ rest_of_handle_loop_optimize (void) /* 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); @@ -1389,7 +1192,7 @@ rest_of_handle_loop2 (void) 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 ()); @@ -1409,7 +1212,7 @@ rest_of_handle_branch_target_load_optimize (void) && flag_branch_target_load_optimize2 && !warned) { - warning ("branch target register load optimization is not intended " + warning (0, "branch target register load optimization is not intended " "to be run twice"); warned = 1; @@ -1443,31 +1246,15 @@ rest_of_handle_jump (void) timevar_push (TV_JUMP); open_dump_file (DFI_sibling, current_function_decl); - /* ??? We may get caled 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 (); #endif + + if (cfun->tail_call_emit) + fixup_tail_calls (); + + close_dump_file (DFI_sibling, print_rtl, get_insns ()); timevar_pop (TV_JUMP); } @@ -1492,24 +1279,6 @@ rest_of_handle_eh (void) } } - -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) { @@ -1545,10 +1314,21 @@ rest_of_handle_flow2 (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 (); @@ -1578,7 +1358,7 @@ rest_of_handle_jump2 (void) 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 @@ -1629,7 +1409,7 @@ rest_of_handle_postreload (void) /* reload_cse_regs can eliminate potentially-trapping MEMs. Remove any EH edges associated with them. */ if (flag_non_call_exceptions) - purge_all_dead_edges (0); + purge_all_dead_edges (); close_dump_file (DFI_postreload, print_rtl_with_bb, get_insns ()); timevar_pop (TV_RELOAD_CSE_REGS); @@ -1647,8 +1427,20 @@ rest_of_handle_shorten_branches (void) static void rest_of_clean_state (void) { + rtx insn, next; coverage_end_function (); + /* It is very important to decompose the RTL instruction chain here: + debug information keeps pointing into CODE_LABEL insns inside the function + body. If these remain pointing to the other insns, we end up preserving + whole RTL chain and attached detailed debug info in memory. */ + for (insn = get_insns (); insn; insn = next) + { + next = NEXT_INSN (insn); + NEXT_INSN (insn) = NULL; + PREV_INSN (insn) = NULL; + } + /* In case the function was not output, don't leave any temporary anonymous types queued up for sdb output. */ @@ -1679,8 +1471,7 @@ rest_of_clean_state (void) 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; @@ -1699,6 +1490,7 @@ rest_of_clean_state (void) /* We're done with this function. Free up memory if we can. */ free_after_parsing (cfun); + free_after_compilation (cfun); } @@ -1706,37 +1498,14 @@ rest_of_clean_state (void) 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) { - /* There's no need to defer outputting this function any more; we - know we want to output it. */ - DECL_DEFER_OUTPUT (current_function_decl) = 0; - - /* Now that we're done expanding trees to RTL, 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; - - finalize_block_changes (); - - /* Dump the rtl code if we are dumping rtl. */ - if (open_dump_file (DFI_rtl, current_function_decl)) - close_dump_file (DFI_rtl, print_rtl, get_insns ()); - - /* 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 we're emitting a nested function, make sure its parent gets emitted as well. Doing otherwise confuses debug info. */ { @@ -1771,9 +1540,6 @@ rest_of_compilation (void) rest_of_handle_jump (); - if (cfun->tail_call_emit) - fixup_tail_calls (); - rest_of_handle_eh (); /* Delay emitting hard_reg_initial_value sets until after EH landing pad @@ -1834,7 +1600,8 @@ rest_of_compilation (void) if (flag_branch_probabilities && flag_profile_values - && flag_value_profile_transformations) + && (flag_value_profile_transformations + || flag_speculative_prefetching)) rest_of_handle_value_profile_transformations (); /* Remove the death notes created for vpt. */ @@ -1870,13 +1637,16 @@ rest_of_compilation (void) rest_of_handle_if_after_combine (); /* The optimization to partition hot/cold basic blocks into separate - sections of the .o file does not work well with exception handling. - Don't call it if there are exceptions. */ + sections of the .o file does not work well with linkonce or with + user defined section attributes. Don't call it if either case + arises. */ - if (optimize > 0 && flag_reorder_blocks_and_partition && !flag_exceptions) + if (flag_reorder_blocks_and_partition + && !DECL_ONE_ONLY (current_function_decl) + && !user_defined_section_attribute) rest_of_handle_partition_blocks (); - if (optimize > 0 && (flag_regmove || flag_expensive_optimizations)) + if (optimize > 0 && flag_regmove) rest_of_handle_regmove (); /* Do unconditional splitting before register allocation to allow machine @@ -1890,7 +1660,7 @@ rest_of_compilation (void) /* 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) @@ -1905,16 +1675,8 @@ rest_of_compilation (void) 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 (); @@ -1948,9 +1710,6 @@ rest_of_compilation (void) = 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 (); @@ -1962,6 +1721,11 @@ rest_of_compilation (void) 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 (); @@ -1999,16 +1763,12 @@ rest_of_compilation (void) } void -init_optimization_passes (void) -{ - open_dump_file (DFI_cgraph, NULL); - cgraph_dump_file = dump_file; - dump_file = NULL; -} - -void finish_optimization_passes (void) { + enum tree_dump_index i; + struct dump_file_info *dfi; + char *name; + timevar_push (TV_DUMP); if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities) { @@ -2023,59 +1783,23 @@ finish_optimization_passes (void) close_dump_file (DFI_combine, NULL, NULL_RTX); } - dump_file = cgraph_dump_file; - cgraph_dump_file = NULL; - close_dump_file (DFI_cgraph, NULL, NULL_RTX); - /* Do whatever is necessary to finish printing the graphs. */ if (graph_dump_format != no_graph) - { - int i; - - for (i = 0; i < (int) DFI_MAX; ++i) - if (dump_file_tbl[i].initialized && dump_file_tbl[i].graph_dump_p) - { - char seq[16]; - char *suffix; - - sprintf (seq, DUMPFILE_FORMAT, i); - suffix = concat (seq, dump_file_tbl[i].extension, NULL); - finish_graph_dump_file (dump_base_name, suffix); - free (suffix); - } - } + for (i = DFI_MIN; (dfi = get_dump_file_info (i)) != NULL; ++i) + if (dump_initialized_p (i) + && (dfi->flags & TDF_RTL) != 0 + && (name = get_dump_file_name (i)) != NULL) + { + finish_graph_dump_file (name); + free (name); + } timevar_pop (TV_DUMP); } -bool -enable_rtl_dump_file (int letter) -{ - bool matched = false; - int i; - - if (letter == 'a') - { - for (i = 0; i < (int) DFI_MAX; ++i) - dump_file_tbl[i].enabled = 1; - matched = true; - } - else - { - for (i = 0; i < (int) DFI_MAX; ++i) - if (letter == dump_file_tbl[i].debug_switch) - { - dump_file_tbl[i].enabled = 1; - matched = true; - } - } - - return matched; -} - struct tree_opt_pass pass_rest_of_compilation = { - "rest of compilation", /* name */ + NULL, /* name */ NULL, /* gate */ rest_of_compilation, /* execute */ NULL, /* sub */ @@ -2086,7 +1810,8 @@ struct tree_opt_pass pass_rest_of_compilation = 0, /* properties_provided */ PROP_rtl, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_ggc_collect /* todo_flags_finish */ + TODO_ggc_collect, /* todo_flags_finish */ + 0 /* letter */ };