aboutsummaryrefslogtreecommitdiff
path: root/gcc/flow.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/flow.c')
-rw-r--r--gcc/flow.c124
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