X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fflow.c;h=2ebcdda0073ab2faace2efbe676e3b7612a5ef56;hb=3c012385060f9699890873ca0d954563b8bf3cc9;hp=ff1d861dbe525c967adb9026a0611d29cfac6df0;hpb=89f18f7391b8c45c76213fce7e8f1fbf557d4982;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/flow.c b/gcc/flow.c index ff1d861dbe5..2ebcdda0073 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -16,8 +16,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ /* This file contains the data flow analysis pass of the compiler. It computes data flow information which tells combine_instructions @@ -140,6 +140,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "obstack.h" #include "splay-tree.h" +#include "tree-pass.h" #ifndef HAVE_epilogue #define HAVE_epilogue 0 @@ -416,7 +417,7 @@ life_analysis (FILE *file, int flags) allocate_bb_life_data (); /* Find the set of registers live on function exit. */ - mark_regs_live_at_end (EXIT_BLOCK_PTR->global_live_at_start); + mark_regs_live_at_end (EXIT_BLOCK_PTR->il.rtl->global_live_at_start); /* "Update" life info from zero. It'd be nice to begin the relaxation with just the exit and noreturn blocks, but that set @@ -504,7 +505,8 @@ verify_local_live_at_start (regset new_live_at_start, basic_block bb) { /* After reload, there are no pseudos, nor subregs of multi-word registers. The regsets should exactly match. */ - if (! REG_SET_EQUAL_P (new_live_at_start, bb->global_live_at_start)) + if (! REG_SET_EQUAL_P (new_live_at_start, + bb->il.rtl->global_live_at_start)) { if (dump_file) { @@ -524,12 +526,12 @@ verify_local_live_at_start (regset new_live_at_start, basic_block bb) reg_set_iterator rsi; /* Find the set of changed registers. */ - XOR_REG_SET (new_live_at_start, bb->global_live_at_start); + XOR_REG_SET (new_live_at_start, bb->il.rtl->global_live_at_start); EXECUTE_IF_SET_IN_REG_SET (new_live_at_start, 0, i, rsi) { /* No registers should die. */ - if (REGNO_REG_SET_P (bb->global_live_at_start, i)) + if (REGNO_REG_SET_P (bb->il.rtl->global_live_at_start, i)) { if (dump_file) { @@ -570,7 +572,7 @@ update_life_info (sbitmap blocks, enum update_life_extent extent, int prop_flags) { regset tmp; - unsigned i; + unsigned i = 0; int stabilized_prop_flags = prop_flags; basic_block bb; @@ -608,7 +610,7 @@ update_life_info (sbitmap blocks, enum update_life_extent extent, in turn may allow for further dead code detection / removal. */ FOR_EACH_BB_REVERSE (bb) { - COPY_REG_SET (tmp, bb->global_live_at_end); + COPY_REG_SET (tmp, bb->il.rtl->global_live_at_end); changed |= propagate_block (bb, tmp, NULL, NULL, prop_flags & (PROP_SCAN_DEAD_CODE | PROP_SCAN_DEAD_STORES @@ -637,8 +639,8 @@ update_life_info (sbitmap blocks, enum update_life_extent extent, in the code being marked live at entry. */ FOR_EACH_BB (bb) { - CLEAR_REG_SET (bb->global_live_at_start); - CLEAR_REG_SET (bb->global_live_at_end); + CLEAR_REG_SET (bb->il.rtl->global_live_at_start); + CLEAR_REG_SET (bb->il.rtl->global_live_at_end); } } @@ -653,22 +655,24 @@ update_life_info (sbitmap blocks, enum update_life_extent extent, if (blocks) { - EXECUTE_IF_SET_IN_SBITMAP (blocks, 0, i, + sbitmap_iterator sbi; + + EXECUTE_IF_SET_IN_SBITMAP (blocks, 0, i, sbi) { bb = BASIC_BLOCK (i); - COPY_REG_SET (tmp, bb->global_live_at_end); + COPY_REG_SET (tmp, bb->il.rtl->global_live_at_end); propagate_block (bb, tmp, NULL, NULL, stabilized_prop_flags); if (extent == UPDATE_LIFE_LOCAL) verify_local_live_at_start (tmp, bb); - }); + }; } else { FOR_EACH_BB_REVERSE (bb) { - COPY_REG_SET (tmp, bb->global_live_at_end); + COPY_REG_SET (tmp, bb->il.rtl->global_live_at_end); propagate_block (bb, tmp, NULL, NULL, stabilized_prop_flags); @@ -687,7 +691,7 @@ update_life_info (sbitmap blocks, enum update_life_extent extent, are those that were not set anywhere in the function. local-alloc doesn't know how to handle these correctly, so mark them as not local to any one basic block. */ - EXECUTE_IF_SET_IN_REG_SET (ENTRY_BLOCK_PTR->global_live_at_end, + EXECUTE_IF_SET_IN_REG_SET (ENTRY_BLOCK_PTR->il.rtl->global_live_at_end, FIRST_PSEUDO_REGISTER, i, rsi) REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL; @@ -765,9 +769,9 @@ free_basic_block_vars (void) label_to_block_map = NULL; ENTRY_BLOCK_PTR->aux = NULL; - ENTRY_BLOCK_PTR->global_live_at_end = NULL; + ENTRY_BLOCK_PTR->il.rtl->global_live_at_end = NULL; EXIT_BLOCK_PTR->aux = NULL; - EXIT_BLOCK_PTR->global_live_at_start = NULL; + EXIT_BLOCK_PTR->il.rtl->global_live_at_start = NULL; } /* Delete any insns that copy a register to itself. */ @@ -1032,7 +1036,7 @@ calculate_global_regs_live (sbitmap blocks_in, sbitmap blocks_out, int flags) In other words, regs that are set only as part of a COND_EXEC. */ regset *cond_local_sets; - int i; + unsigned int i; /* Some passes used to forget clear aux field of basic block causing sick behavior here. */ @@ -1184,10 +1188,10 @@ calculate_global_regs_live (sbitmap blocks_in, sbitmap blocks_out, int flags) confused by sibling call edges, which crashes reg-stack. */ if (e->flags & EDGE_EH) bitmap_ior_and_compl_into (new_live_at_end, - sb->global_live_at_start, + sb->il.rtl->global_live_at_start, invalidated_by_call); else - IOR_REG_SET (new_live_at_end, sb->global_live_at_start); + IOR_REG_SET (new_live_at_end, sb->il.rtl->global_live_at_start); /* If a target saves one register in another (instead of on the stack) the save register will need to be live for EH. */ @@ -1234,7 +1238,7 @@ calculate_global_regs_live (sbitmap blocks_in, sbitmap blocks_out, int flags) if (bb == ENTRY_BLOCK_PTR) { - COPY_REG_SET (bb->global_live_at_end, new_live_at_end); + COPY_REG_SET (bb->il.rtl->global_live_at_end, new_live_at_end); continue; } @@ -1257,7 +1261,7 @@ calculate_global_regs_live (sbitmap blocks_in, sbitmap blocks_out, int flags) rescan the block. This wouldn't be necessary if we had precalculated local_live, however with PROP_SCAN_DEAD_CODE local_live is really dependent on live_at_end. */ - rescan = bitmap_intersect_compl_p (bb->global_live_at_end, + rescan = bitmap_intersect_compl_p (bb->il.rtl->global_live_at_end, new_live_at_end); if (!rescan) @@ -1282,7 +1286,7 @@ calculate_global_regs_live (sbitmap blocks_in, sbitmap blocks_out, int flags) /* Find the set of changed bits. Take this opportunity to notice that this set is empty and early out. */ - bitmap_xor (tmp, bb->global_live_at_end, new_live_at_end); + bitmap_xor (tmp, bb->il.rtl->global_live_at_end, new_live_at_end); if (bitmap_empty_p (tmp)) continue; @@ -1303,16 +1307,16 @@ calculate_global_regs_live (sbitmap blocks_in, sbitmap blocks_out, int flags) /* Add to live_at_start the set of all registers in new_live_at_end that aren't in the old live_at_end. */ - changed = bitmap_ior_and_compl_into (bb->global_live_at_start, + changed = bitmap_ior_and_compl_into (bb->il.rtl->global_live_at_start, new_live_at_end, - bb->global_live_at_end); - COPY_REG_SET (bb->global_live_at_end, new_live_at_end); + bb->il.rtl->global_live_at_end); + COPY_REG_SET (bb->il.rtl->global_live_at_end, new_live_at_end); if (! changed) continue; } else { - COPY_REG_SET (bb->global_live_at_end, new_live_at_end); + COPY_REG_SET (bb->il.rtl->global_live_at_end, new_live_at_end); /* Rescan the block insn by insn to turn (a copy of) live_at_end into live_at_start. */ @@ -1322,14 +1326,15 @@ calculate_global_regs_live (sbitmap blocks_in, sbitmap blocks_out, int flags) flags); /* If live_at start didn't change, no need to go farther. */ - if (REG_SET_EQUAL_P (bb->global_live_at_start, new_live_at_end)) + if (REG_SET_EQUAL_P (bb->il.rtl->global_live_at_start, + new_live_at_end)) continue; if (failure_strategy_required) { /* Get the list of registers that were removed from the bb->global_live_at_start set. */ - bitmap_and_compl (tmp, bb->global_live_at_start, + bitmap_and_compl (tmp, bb->il.rtl->global_live_at_start, new_live_at_end); if (!bitmap_empty_p (tmp)) { @@ -1348,11 +1353,13 @@ calculate_global_regs_live (sbitmap blocks_in, sbitmap blocks_out, int flags) pbb_changed = false; pbb_changed - |= bitmap_and_compl_into (pbb->global_live_at_start, - registers_made_dead); + |= bitmap_and_compl_into + (pbb->il.rtl->global_live_at_start, + registers_made_dead); pbb_changed - |= bitmap_and_compl_into (pbb->global_live_at_end, - registers_made_dead); + |= bitmap_and_compl_into + (pbb->il.rtl->global_live_at_end, + registers_made_dead); if (!pbb_changed) continue; @@ -1381,7 +1388,7 @@ calculate_global_regs_live (sbitmap blocks_in, sbitmap blocks_out, int flags) } } /* end of failure_strategy_required */ - COPY_REG_SET (bb->global_live_at_start, new_live_at_end); + COPY_REG_SET (bb->il.rtl->global_live_at_start, new_live_at_end); } /* Queue all predecessors of BB so that we may re-examine @@ -1406,12 +1413,14 @@ calculate_global_regs_live (sbitmap blocks_in, sbitmap blocks_out, int flags) if (blocks_out) { - EXECUTE_IF_SET_IN_SBITMAP (blocks_out, 0, i, + sbitmap_iterator sbi; + + EXECUTE_IF_SET_IN_SBITMAP (blocks_out, 0, i, sbi) { basic_block bb = BASIC_BLOCK (i); FREE_REG_SET (local_sets[bb->index - (INVALID_BLOCK + 1)]); FREE_REG_SET (cond_local_sets[bb->index - (INVALID_BLOCK + 1)]); - }); + }; } else { @@ -1500,7 +1509,7 @@ initialize_uninitialized_subregs (void) FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs) { basic_block bb = e->dest; - regset map = bb->global_live_at_start; + regset map = bb->il.rtl->global_live_at_start; reg_set_iterator rsi; EXECUTE_IF_SET_IN_REG_SET (map, FIRST_PSEUDO_REGISTER, reg, rsi) @@ -1552,8 +1561,8 @@ allocate_bb_life_data (void) FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) { - bb->global_live_at_start = ALLOC_REG_SET (®_obstack); - bb->global_live_at_end = ALLOC_REG_SET (®_obstack); + bb->il.rtl->global_live_at_start = ALLOC_REG_SET (®_obstack); + bb->il.rtl->global_live_at_end = ALLOC_REG_SET (®_obstack); } regs_live_at_setjmp = ALLOC_REG_SET (®_obstack); @@ -1692,8 +1701,12 @@ propagate_one_insn (struct propagate_block_info *pbi, rtx insn) fatal_insn ("Attempt to delete prologue/epilogue insn:", insn); /* Record sets. Do this even for dead instructions, since they - would have killed the values if they hadn't been deleted. */ + would have killed the values if they hadn't been deleted. To + be consistent, we also have to emit a clobber when we delete + an insn that clobbers a live register. */ + pbi->flags |= PROP_DEAD_INSN; mark_set_regs (pbi, PATTERN (insn), insn); + pbi->flags &= ~PROP_DEAD_INSN; /* CC0 is now known to be dead. Either this insn used it, in which case it doesn't anymore, or clobbered it, @@ -1848,7 +1861,7 @@ propagate_one_insn (struct propagate_block_info *pbi, rtx insn) except for return values. */ sibcall_p = SIBLING_CALL_P (insn); - live_at_end = EXIT_BLOCK_PTR->global_live_at_start; + live_at_end = EXIT_BLOCK_PTR->il.rtl->global_live_at_start; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i) && ! (sibcall_p @@ -1983,8 +1996,8 @@ init_propagate_block_info (basic_block bb, regset live, regset local_set, } /* Compute which register lead different lives in the successors. */ - bitmap_xor (diff, bb_true->global_live_at_start, - bb_false->global_live_at_start); + bitmap_xor (diff, bb_true->il.rtl->global_live_at_start, + bb_false->il.rtl->global_live_at_start); if (!bitmap_empty_p (diff)) { @@ -2029,7 +2042,8 @@ init_propagate_block_info (basic_block bb, regset live, regset local_set, rcli = xmalloc (sizeof (*rcli)); - if (REGNO_REG_SET_P (bb_true->global_live_at_start, i)) + if (REGNO_REG_SET_P (bb_true->il.rtl->global_live_at_start, + i)) cond = cond_false; else cond = cond_true; @@ -2460,7 +2474,8 @@ regno_clobbered_at_setjmp (int regno) return 0; return ((REG_N_SETS (regno) > 1 - || REGNO_REG_SET_P (ENTRY_BLOCK_PTR->global_live_at_end, regno)) + || REGNO_REG_SET_P (ENTRY_BLOCK_PTR->il.rtl->global_live_at_end, + regno)) && REGNO_REG_SET_P (regs_live_at_setjmp, regno)); } @@ -2960,6 +2975,8 @@ mark_set_1 (struct propagate_block_info *pbi, enum rtx_code code, rtx reg, rtx c } CLEAR_REGNO_REG_SET (pbi->reg_live, i); } + if (flags & PROP_DEAD_INSN) + emit_insn_after (gen_rtx_CLOBBER (VOIDmode, reg), insn); } } else if (REG_P (reg)) @@ -4341,6 +4358,23 @@ recompute_reg_usage (void) update_life_info (NULL, UPDATE_LIFE_LOCAL, PROP_REG_INFO | PROP_DEATH_NOTES); } +struct tree_opt_pass pass_recompute_reg_usage = +{ + NULL, /* name */ + NULL, /* gate */ + recompute_reg_usage, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ + 0 /* letter */ +}; + /* Optionally removes all the REG_DEAD and REG_UNUSED notes from a set of blocks. If BLOCKS is NULL, assume the universal set. Returns a count of the number of registers that died. */ @@ -4349,7 +4383,7 @@ int count_or_remove_death_notes (sbitmap blocks, int kill) { int count = 0; - int i; + unsigned int i = 0; basic_block bb; /* This used to be a loop over all the blocks with a membership test @@ -4361,10 +4395,12 @@ count_or_remove_death_notes (sbitmap blocks, int kill) than an sbitmap. */ if (blocks) { - EXECUTE_IF_SET_IN_SBITMAP (blocks, 0, i, + sbitmap_iterator sbi; + + EXECUTE_IF_SET_IN_SBITMAP (blocks, 0, i, sbi) { count += count_or_remove_death_notes_bb (BASIC_BLOCK (i), kill); - }); + }; } else { @@ -4444,7 +4480,6 @@ static void clear_log_links (sbitmap blocks) { rtx insn; - int i; if (!blocks) { @@ -4453,15 +4488,20 @@ clear_log_links (sbitmap blocks) free_INSN_LIST_list (&LOG_LINKS (insn)); } else - EXECUTE_IF_SET_IN_SBITMAP (blocks, 0, i, - { - basic_block bb = BASIC_BLOCK (i); + { + unsigned int i = 0; + sbitmap_iterator sbi; + + EXECUTE_IF_SET_IN_SBITMAP (blocks, 0, i, sbi) + { + basic_block bb = BASIC_BLOCK (i); - for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); - insn = NEXT_INSN (insn)) - if (INSN_P (insn)) - free_INSN_LIST_list (&LOG_LINKS (insn)); - }); + for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); + insn = NEXT_INSN (insn)) + if (INSN_P (insn)) + free_INSN_LIST_list (&LOG_LINKS (insn)); + } + } } /* Given a register bitmap, turn on the bits in a HARD_REG_SET that @@ -4482,3 +4522,131 @@ reg_set_to_hard_reg_set (HARD_REG_SET *to, bitmap from) SET_HARD_REG_BIT (*to, i); } } + + +static bool +gate_remove_death_notes (void) +{ + return flag_profile_values; +} + +static void +rest_of_handle_remove_death_notes (void) +{ + count_or_remove_death_notes (NULL, 1); +} + +struct tree_opt_pass pass_remove_death_notes = +{ + NULL, /* name */ + gate_remove_death_notes, /* gate */ + rest_of_handle_remove_death_notes, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ + 0 /* letter */ +}; + +/* Perform life analysis. */ +static void +rest_of_handle_life (void) +{ + regclass_init (); + + life_analysis (dump_file, PROP_FINAL); + if (optimize) + cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE | CLEANUP_LOG_LINKS + | (flag_thread_jumps ? CLEANUP_THREADING : 0)); + + if (extra_warnings) + { + setjmp_vars_warning (DECL_INITIAL (current_function_decl)); + setjmp_args_warning (); + } + + if (optimize) + { + if (initialize_uninitialized_subregs ()) + { + /* Insns were inserted, and possibly pseudos created, so + things might look a bit different. */ + 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; +} + +struct tree_opt_pass pass_life = +{ + "life", /* name */ + NULL, /* gate */ + rest_of_handle_life, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_FLOW, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + TODO_verify_flow, /* todo_flags_start */ + TODO_dump_func | + TODO_ggc_collect, /* todo_flags_finish */ + 'f' /* letter */ +}; + +static void +rest_of_handle_flow2 (void) +{ + /* Re-create the death notes which were deleted during reload. */ +#ifdef ENABLE_CHECKING + verify_flow_info (); +#endif + + /* If optimizing, then go ahead and split insns now. */ +#ifndef STACK_REGS + if (optimize > 0) +#endif + split_all_insns (0); + + if (flag_branch_target_load_optimize) + branch_target_load_optimize (epilogue_completed); + + if (optimize) + 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; + flow2_completed = 1; +} + +struct tree_opt_pass pass_flow2 = +{ + "flow2", /* name */ + NULL, /* gate */ + rest_of_handle_flow2, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_FLOW2, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + TODO_verify_flow, /* todo_flags_start */ + TODO_dump_func | + TODO_ggc_collect, /* todo_flags_finish */ + 'w' /* letter */ +}; +