aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Wilson <wilson@gcc.gnu.org>1996-01-24 12:10:22 -0800
committerJim Wilson <wilson@gcc.gnu.org>1996-01-24 12:10:22 -0800
commitc170c8c2082ab34698e648b534c585e7eabcd3bc (patch)
tree94e19318124917df8806268ca4e0ab42ee0d820d
parent8516af930204c949aebf7e4aaf9bbde13010ff92 (diff)
downloadgcc-c170c8c2082ab34698e648b534c585e7eabcd3bc.zip
gcc-c170c8c2082ab34698e648b534c585e7eabcd3bc.tar.gz
gcc-c170c8c2082ab34698e648b534c585e7eabcd3bc.tar.bz2
(find_dead_or_set_registers): New function.
(mark_target_live_regs): Delete loop looking forward from target and instead call find_dead_or_set_registers. (fix_reg_dead_note): New function. (fill_slots_from_thread): Call it. From-SVN: r11091
-rw-r--r--gcc/reorg.c298
1 files changed, 220 insertions, 78 deletions
diff --git a/gcc/reorg.c b/gcc/reorg.c
index 2852f32..a9101a9 100644
--- a/gcc/reorg.c
+++ b/gcc/reorg.c
@@ -130,6 +130,9 @@ Boston, MA 02111-1307, USA. */
#include "obstack.h"
#include "insn-attr.h"
+/* Import list of registers used as spill regs from reload. */
+extern HARD_REG_SET used_spill_regs;
+
#ifdef DELAY_SLOTS
#define obstack_chunk_alloc xmalloc
@@ -252,6 +255,7 @@ static int find_basic_block PROTO((rtx));
static void update_block PROTO((rtx, rtx));
static int reorg_redirect_jump PROTO((rtx, rtx));
static void update_reg_dead_notes PROTO((rtx, rtx));
+static void fix_reg_dead_note PROTO((rtx, rtx));
static void update_reg_unused_notes PROTO((rtx, rtx));
static void update_live_status PROTO((rtx, rtx));
static rtx next_insn_no_annul PROTO((rtx));
@@ -2305,6 +2309,38 @@ update_reg_dead_notes (insn, delayed_insn)
}
}
+/* Called when an insn redundant with start_insn is deleted. If there
+ is a REG_DEAD note for the target of start_insn between start_insn
+ and stop_insn, then the REG_DEAD note needs to be deleted since the
+ value no longer dies there.
+
+ If the REG_DEAD note isn't deleted, then mark_target_live_regs may be
+ confused into thinking the register is dead. */
+
+static void
+fix_reg_dead_note (start_insn, stop_insn)
+ rtx start_insn, stop_insn;
+{
+ rtx p, link, next;
+
+ for (p = next_nonnote_insn (start_insn); p != stop_insn;
+ p = next_nonnote_insn (p))
+ for (link = REG_NOTES (p); link; link = next)
+ {
+ next = XEXP (link, 1);
+
+ if (REG_NOTE_KIND (link) != REG_DEAD
+ || GET_CODE (XEXP (link, 0)) != REG)
+ continue;
+
+ if (reg_set_p (XEXP (link, 0), PATTERN (start_insn)))
+ {
+ remove_note (p, link);
+ return;
+ }
+ }
+}
+
/* Delete any REG_UNUSED notes that exist on INSN but not on REDUNDANT_INSN.
This handles the case of udivmodXi4 instructions which optimize their
@@ -2400,6 +2436,185 @@ next_insn_no_annul (insn)
return insn;
}
+/* A subroutine of mark_target_live_regs. Search forward from TARGET
+ looking for registers that are set before they are used. These are dead.
+ Stop after passing a few conditional jumps, and/or a small
+ number of unconditional branches. */
+
+static rtx
+find_dead_or_set_registers (target, res, jump_target, jump_count, set, needed)
+ rtx target;
+ struct resources *res;
+ rtx *jump_target;
+ int jump_count;
+ struct resources set, needed;
+{
+ HARD_REG_SET scratch;
+ rtx insn, next;
+ rtx jump_insn = 0;
+ int i;
+
+ for (insn = target; insn; insn = next)
+ {
+ rtx this_jump_insn = insn;
+
+ next = NEXT_INSN (insn);
+ switch (GET_CODE (insn))
+ {
+ case CODE_LABEL:
+ /* After a label, any pending dead registers that weren't yet
+ used can be made dead. */
+ AND_COMPL_HARD_REG_SET (pending_dead_regs, needed.regs);
+ AND_COMPL_HARD_REG_SET (res->regs, pending_dead_regs);
+ CLEAR_HARD_REG_SET (pending_dead_regs);
+
+ /* All spill registers are dead at a label, so kill all of the
+ ones that aren't needed also. */
+ COPY_HARD_REG_SET (scratch, used_spill_regs);
+ AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+ AND_COMPL_HARD_REG_SET (res->regs, scratch);
+ continue;
+
+ case BARRIER:
+ case NOTE:
+ continue;
+
+ case INSN:
+ if (GET_CODE (PATTERN (insn)) == USE)
+ {
+ /* If INSN is a USE made by update_block, we care about the
+ underlying insn. Any registers set by the underlying insn
+ are live since the insn is being done somewhere else. */
+ if (GET_RTX_CLASS (GET_CODE (XEXP (PATTERN (insn), 0))) == 'i')
+ mark_set_resources (XEXP (PATTERN (insn), 0), res, 0, 1);
+
+ /* All other USE insns are to be ignored. */
+ continue;
+ }
+ else if (GET_CODE (PATTERN (insn)) == CLOBBER)
+ continue;
+ else if (GET_CODE (PATTERN (insn)) == SEQUENCE)
+ {
+ /* An unconditional jump can be used to fill the delay slot
+ of a call, so search for a JUMP_INSN in any position. */
+ for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
+ {
+ this_jump_insn = XVECEXP (PATTERN (insn), 0, i);
+ if (GET_CODE (this_jump_insn) == JUMP_INSN)
+ break;
+ }
+ }
+ }
+
+ if (GET_CODE (this_jump_insn) == JUMP_INSN)
+ {
+ if (jump_count++ < 10)
+ {
+ if (simplejump_p (this_jump_insn)
+ || GET_CODE (PATTERN (this_jump_insn)) == RETURN)
+ {
+ next = JUMP_LABEL (this_jump_insn);
+ if (jump_insn == 0)
+ {
+ jump_insn = insn;
+ if (jump_target)
+ *jump_target = JUMP_LABEL (this_jump_insn);
+ }
+ }
+ else if (condjump_p (this_jump_insn)
+ || condjump_in_parallel_p (this_jump_insn))
+ {
+ struct resources target_set, target_res;
+ struct resources fallthrough_res;
+
+ /* We can handle conditional branches here by following
+ both paths, and then IOR the results of the two paths
+ together, which will give us registers that are dead
+ on both paths. Since this is expensive, we give it
+ a much higher cost than unconditional branches. The
+ cost was chosen so that we will follow at most 1
+ conditional branch. */
+
+ jump_count += 4;
+ if (jump_count >= 10)
+ break;
+
+ mark_referenced_resources (insn, &needed, 1);
+
+ /* For an annulled branch, mark_set_resources ignores slots
+ filled by instructions from the target. This is correct
+ if the branch is not taken. Since we are following both
+ paths from the branch, we must also compute correct info
+ if the branch is taken. We do this by inverting all of
+ the INSN_FROM_TARGET_P bits, calling mark_set_resources,
+ and then inverting the INSN_FROM_TARGET_P bits again. */
+
+ if (GET_CODE (PATTERN (insn)) == SEQUENCE
+ && INSN_ANNULLED_BRANCH_P (this_jump_insn))
+ {
+ for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++)
+ INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i))
+ = ! INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i));
+
+ target_set = set;
+ mark_set_resources (insn, &target_set, 0, 1);
+
+ for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++)
+ INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i))
+ = ! INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i));
+
+ mark_set_resources (insn, &set, 0, 1);
+ }
+ else
+ {
+ mark_set_resources (insn, &set, 0, 1);
+ target_set = set;
+ }
+
+ target_res = *res;
+ COPY_HARD_REG_SET (scratch, target_set.regs);
+ AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+ AND_COMPL_HARD_REG_SET (target_res.regs, scratch);
+
+ fallthrough_res = *res;
+ COPY_HARD_REG_SET (scratch, set.regs);
+ AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+ AND_COMPL_HARD_REG_SET (fallthrough_res.regs, scratch);
+
+ find_dead_or_set_registers (JUMP_LABEL (this_jump_insn),
+ &target_res, 0, jump_count,
+ target_set, needed);
+ find_dead_or_set_registers (next,
+ &fallthrough_res, 0, jump_count,
+ set, needed);
+ IOR_HARD_REG_SET (fallthrough_res.regs, target_res.regs);
+ AND_HARD_REG_SET (res->regs, fallthrough_res.regs);
+ break;
+ }
+ else
+ break;
+ }
+ else
+ {
+ /* Don't try this optimization if we expired our jump count
+ above, since that would mean there may be an infinite loop
+ in the function being compiled. */
+ jump_insn = 0;
+ break;
+ }
+ }
+
+ mark_referenced_resources (insn, &needed, 1);
+ mark_set_resources (insn, &set, 0, 1);
+
+ COPY_HARD_REG_SET (scratch, set.regs);
+ AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+ AND_COMPL_HARD_REG_SET (res->regs, scratch);
+ }
+
+ return jump_insn;
+}
+
/* Set the resources that are live at TARGET.
If TARGET is zero, we refer to the end of the current function and can
@@ -2670,92 +2885,18 @@ mark_target_live_regs (target, res)
in use. This should happen only extremely rarely. */
SET_HARD_REG_SET (res->regs);
- /* Now step forward from TARGET looking for registers that are set before
- they are used. These are dead. If we pass a label, any pending dead
- registers that weren't yet used can be made dead. Stop when we pass a
- conditional JUMP_INSN; follow the first few unconditional branches. */
-
CLEAR_RESOURCE (&set);
CLEAR_RESOURCE (&needed);
- for (insn = target; insn; insn = next)
- {
- rtx this_jump_insn = insn;
-
- next = NEXT_INSN (insn);
- switch (GET_CODE (insn))
- {
- case CODE_LABEL:
- AND_COMPL_HARD_REG_SET (pending_dead_regs, needed.regs);
- AND_COMPL_HARD_REG_SET (res->regs, pending_dead_regs);
- CLEAR_HARD_REG_SET (pending_dead_regs);
- continue;
-
- case BARRIER:
- case NOTE:
- continue;
-
- case INSN:
- if (GET_CODE (PATTERN (insn)) == USE)
- {
- /* If INSN is a USE made by update_block, we care about the
- underlying insn. Any registers set by the underlying insn
- are live since the insn is being done somewhere else. */
- if (GET_RTX_CLASS (GET_CODE (XEXP (PATTERN (insn), 0))) == 'i')
- mark_set_resources (XEXP (PATTERN (insn), 0), res, 0, 1);
-
- /* All other USE insns are to be ignored. */
- continue;
- }
- else if (GET_CODE (PATTERN (insn)) == CLOBBER)
- continue;
- else if (GET_CODE (PATTERN (insn)) == SEQUENCE)
- {
- /* An unconditional jump can be used to fill the delay slot
- of a call, so search for a JUMP_INSN in any position. */
- for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
- {
- this_jump_insn = XVECEXP (PATTERN (insn), 0, i);
- if (GET_CODE (this_jump_insn) == JUMP_INSN)
- break;
- }
- }
- }
-
- if (GET_CODE (this_jump_insn) == JUMP_INSN)
- {
- if (jump_count++ < 10
- && (simplejump_p (this_jump_insn)
- || GET_CODE (PATTERN (this_jump_insn)) == RETURN))
- {
- next = next_active_insn (JUMP_LABEL (this_jump_insn));
- if (jump_insn == 0)
- {
- jump_insn = insn;
- jump_target = JUMP_LABEL (this_jump_insn);
- }
- }
- else
- break;
- }
-
- mark_referenced_resources (insn, &needed, 1);
- mark_set_resources (insn, &set, 0, 1);
-
- COPY_HARD_REG_SET (scratch, set.regs);
- AND_COMPL_HARD_REG_SET (scratch, needed.regs);
- AND_COMPL_HARD_REG_SET (res->regs, scratch);
- }
+ jump_insn = find_dead_or_set_registers (target, res, &jump_target, 0,
+ set, needed);
/* If we hit an unconditional branch, we have another way of finding out
what is live: we can see what is live at the branch target and include
anything used but not set before the branch. The only things that are
- live are those that are live using the above test and the test below.
-
- Don't try this if we expired our jump count above, since that would
- mean there may be an infinite loop in the function being compiled. */
+ live are those that are live using the above test and the test below. */
- if (jump_insn && jump_count < 10)
+ if (jump_insn)
{
struct resources new_resources;
rtx stop_insn = next_active_insn (jump_insn);
@@ -3361,6 +3502,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
we did. */
if (prior_insn = redundant_insn (trial, insn, delay_list))
{
+ fix_reg_dead_note (prior_insn, insn);
if (own_thread)
{
update_block (trial, thread);