diff options
Diffstat (limited to 'gcc/flow.c')
-rw-r--r-- | gcc/flow.c | 124 |
1 files changed, 104 insertions, 20 deletions
diff --git a/gcc/flow.c b/gcc/flow.c index 6c3cd564d7d..5b43c6be065 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -167,6 +167,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #ifndef EPILOGUE_USES #define EPILOGUE_USES(REGNO) 0 #endif +#ifndef EH_USES +#define EH_USES(REGNO) 0 +#endif #ifdef HAVE_conditional_execution #ifndef REVERSE_CONDEXEC_PREDICATES_P @@ -496,6 +499,9 @@ life_analysis (f, file, flags) } } #endif + + rebuild_jump_labels (get_insns ()); + /* Removing dead insns should've made jumptables really dead. */ delete_dead_jumptables (); } @@ -633,6 +639,7 @@ update_life_info (blocks, extent, prop_flags) regset tmp; regset_head tmp_head; int i; + int stabilized_prop_flags = prop_flags; tmp = INITIALIZE_REG_SET (tmp_head); @@ -676,8 +683,21 @@ update_life_info (blocks, extent, prop_flags) | PROP_KILL_DEAD_CODE)); } - if (! changed || ! cleanup_cfg (CLEANUP_EXPENSIVE)) + /* Don't pass PROP_SCAN_DEAD_CODE or PROP_KILL_DEAD_CODE to + subsequent propagate_block calls, since removing or acting as + removing dead code can affect global register liveness, which + is supposed to be finalized for this call after this loop. */ + stabilized_prop_flags + &= ~(PROP_SCAN_DEAD_CODE | PROP_KILL_DEAD_CODE); + + if (! changed) break; + + /* We repeat regardless of what cleanup_cfg says. If there were + instructions deleted above, that might have been only a + partial improvement (see MAX_MEM_SET_LIST_LEN usage). + Further improvement may be possible. */ + cleanup_cfg (CLEANUP_EXPENSIVE); } /* If asked, remove notes from the blocks we'll update. */ @@ -692,7 +712,7 @@ update_life_info (blocks, extent, prop_flags) basic_block bb = BASIC_BLOCK (i); COPY_REG_SET (tmp, bb->global_live_at_end); - propagate_block (bb, tmp, NULL, NULL, prop_flags); + propagate_block (bb, tmp, NULL, NULL, stabilized_prop_flags); if (extent == UPDATE_LIFE_LOCAL) verify_local_live_at_start (tmp, bb); @@ -705,7 +725,8 @@ update_life_info (blocks, extent, prop_flags) basic_block bb = BASIC_BLOCK (i); COPY_REG_SET (tmp, bb->global_live_at_end); - propagate_block (bb, tmp, NULL, NULL, prop_flags); + + propagate_block (bb, tmp, NULL, NULL, stabilized_prop_flags); if (extent == UPDATE_LIFE_LOCAL) verify_local_live_at_start (tmp, bb); @@ -1077,6 +1098,11 @@ calculate_global_regs_live (blocks_in, blocks_out, flags) } } + /* We clean aux when we remove the initially-enqueued bbs, but we + don't enqueue ENTRY and EXIT initially, so clean them upfront and + unconditionally. */ + ENTRY_BLOCK_PTR->aux = EXIT_BLOCK_PTR->aux = NULL; + if (blocks_out) sbitmap_zero (blocks_out); @@ -1111,21 +1137,40 @@ calculate_global_regs_live (blocks_in, blocks_out, flags) /* Begin by propagating live_at_start from the successor blocks. */ CLEAR_REG_SET (new_live_at_end); - for (e = bb->succ; e; e = e->succ_next) - { - basic_block sb = e->dest; - /* Call-clobbered registers die across exception and call edges. */ - /* ??? Abnormal call edges ignored for the moment, as this gets - confused by sibling call edges, which crashes reg-stack. */ - if (e->flags & EDGE_EH) - { - bitmap_operation (tmp, sb->global_live_at_start, - call_used, BITMAP_AND_COMPL); - IOR_REG_SET (new_live_at_end, tmp); - } - else - IOR_REG_SET (new_live_at_end, sb->global_live_at_start); + if (bb->succ) + for (e = bb->succ; e; e = e->succ_next) + { + basic_block sb = e->dest; + + /* Call-clobbered registers die across exception and + call edges. */ + /* ??? Abnormal call edges ignored for the moment, as this gets + confused by sibling call edges, which crashes reg-stack. */ + if (e->flags & EDGE_EH) + { + bitmap_operation (tmp, sb->global_live_at_start, + call_used, BITMAP_AND_COMPL); + IOR_REG_SET (new_live_at_end, tmp); + } + else + IOR_REG_SET (new_live_at_end, sb->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. */ + if (e->flags & EDGE_EH) + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (EH_USES (i)) + SET_REGNO_REG_SET (new_live_at_end, i); + } + else + { + /* This might be a noreturn function that throws. And + even if it isn't, getting the unwind info right helps + debugging. */ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (EH_USES (i)) + SET_REGNO_REG_SET (new_live_at_end, i); } /* The all-important stack pointer must always be live. */ @@ -1584,7 +1629,42 @@ propagate_one_insn (pbi, insn) if (libcall_is_dead) prev = propagate_block_delete_libcall ( insn, note); else - propagate_block_delete_insn (pbi->bb, insn); + { + + /* If INSN contains a RETVAL note and is dead, but the libcall + as a whole is not dead, then we want to remove INSN, but + not the whole libcall sequence. + + However, we need to also remove the dangling REG_LIBCALL + note so that we do not have mis-matched LIBCALL/RETVAL + notes. In theory we could find a new location for the + REG_RETVAL note, but it hardly seems worth the effort. + + NOTE at this point will be the RETVAL note if it exists. */ + if (note) + { + rtx libcall_note; + + libcall_note + = find_reg_note (XEXP (note, 0), REG_LIBCALL, NULL_RTX); + remove_note (XEXP (note, 0), libcall_note); + } + + /* Similarly if INSN contains a LIBCALL note, remove the + dangling REG_RETVAL note. */ + note = find_reg_note (insn, REG_LIBCALL, NULL_RTX); + if (note) + { + rtx retval_note; + + retval_note + = find_reg_note (XEXP (note, 0), REG_RETVAL, NULL_RTX); + remove_note (XEXP (note, 0), retval_note); + } + + /* Now delete INSN. */ + propagate_block_delete_insn (pbi->bb, insn); + } return prev; } @@ -3543,6 +3623,10 @@ mark_used_reg (pbi, reg, cond, insn) /* Mark the register as being live. */ for (i = regno_first; i <= regno_last; ++i) { +#ifdef HAVE_conditional_execution + int this_was_live = REGNO_REG_SET_P (pbi->reg_live, i); +#endif + SET_REGNO_REG_SET (pbi->reg_live, i); #ifdef HAVE_conditional_execution @@ -3554,7 +3638,7 @@ mark_used_reg (pbi, reg, cond, insn) struct reg_cond_life_info *rcli; rtx ncond; - if (some_was_live) + if (this_was_live) { node = splay_tree_lookup (pbi->reg_cond_dead, i); if (node == NULL) @@ -3596,7 +3680,7 @@ mark_used_reg (pbi, reg, cond, insn) SET_REGNO_REG_SET (pbi->reg_cond_reg, REGNO (XEXP (cond, 0))); } } - else if (some_was_live) + else if (this_was_live) { /* The register may have been conditionally live previously, but is now unconditionally live. Remove it from the conditionally |