static int reload_cse_simplify_operands PROTO((rtx));
static void reload_cse_check_clobber PROTO((rtx, rtx));
static void reload_cse_record_set PROTO((rtx, rtx));
-static void reload_cse_delete_death_notes PROTO((rtx));
-static void reload_cse_no_longer_dead PROTO((int, enum machine_mode));
static void reload_combine PROTO((void));
static void reload_combine_note_use PROTO((rtx *, rtx));
static void reload_combine_note_store PROTO((rtx, rtx));
}
/* Make a pass over all the insns and delete all USEs which we inserted
- only to tag a REG_EQUAL note on them; if PRESERVE_DEATH_INFO_REGNO_P
- is defined, also remove death notes for things that are no longer
- registers or no longer die in the insn (e.g., an input and output
- pseudo being tied). */
+ only to tag a REG_EQUAL note on them. Also remove all REG_DEAD and
+ REG_UNUSED notes. */
for (insn = first; insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
-#ifdef PRESERVE_DEATH_INFO_REGNO_P
- rtx note, next;
-#endif
+ rtx *pnote;
if (GET_CODE (PATTERN (insn)) == USE
&& find_reg_note (insn, REG_EQUAL, NULL_RTX))
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
continue;
}
-#ifdef PRESERVE_DEATH_INFO_REGNO_P
- for (note = REG_NOTES (insn); note; note = next)
+
+ pnote = ®_NOTES (insn);
+ while (*pnote != 0)
{
- next = XEXP (note, 1);
- if (REG_NOTE_KIND (note) == REG_DEAD
- && (GET_CODE (XEXP (note, 0)) != REG
- || reg_set_p (XEXP (note, 0), PATTERN (insn))))
- remove_note (insn, note);
+ if (REG_NOTE_KIND (*pnote) == REG_DEAD
+ || REG_NOTE_KIND (*pnote) == REG_UNUSED)
+ *pnote = XEXP (*pnote, 1);
+ else
+ pnote = &XEXP (*pnote, 1);
}
-#endif
}
/* If we are doing stack checking, give a warning if this function's
gen_reload (reloadreg, oldequiv, reload_opnum[j],
reload_when_needed[j]);
-#if defined(SECONDARY_INPUT_RELOAD_CLASS) && defined(PRESERVE_DEATH_INFO_REGNO_P)
- /* We may have to make a REG_DEAD note for the secondary reload
- register in the insns we just made. Find the last insn that
- mentioned the register. */
- if (! special && second_reload_reg
- && PRESERVE_DEATH_INFO_REGNO_P (REGNO (second_reload_reg)))
- {
- rtx prev;
-
- for (prev = get_last_insn (); prev;
- prev = PREV_INSN (prev))
- if (GET_RTX_CLASS (GET_CODE (prev) == 'i')
- && reg_overlap_mentioned_for_reload_p (second_reload_reg,
- PATTERN (prev)))
- {
- REG_NOTES (prev) = gen_rtx_EXPR_LIST (REG_DEAD,
- second_reload_reg,
- REG_NOTES (prev));
- break;
- }
- }
-#endif
}
this_reload_insn = get_last_insn ();
reload_in[j]
= regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]];
}
- /* Add a note saying the input reload reg
- dies in this insn, if anyone cares. */
-#ifdef PRESERVE_DEATH_INFO_REGNO_P
- if (old != 0
- && reload_reg_rtx[j] != old
- && reload_reg_rtx[j] != 0
- && reload_out[j] == 0
- && ! reload_inherited[j]
- && PRESERVE_DEATH_INFO_REGNO_P (REGNO (reload_reg_rtx[j])))
- {
- register rtx reloadreg = reload_reg_rtx[j];
-
-#if 0
- /* We can't abort here because we need to support this for sched.c.
- It's not terrible to miss a REG_DEAD note, but we should try
- to figure out how to do this correctly. */
- /* The code below is incorrect for address-only reloads. */
- if (reload_when_needed[j] != RELOAD_OTHER
- && reload_when_needed[j] != RELOAD_FOR_INPUT)
- abort ();
-#endif
-
- /* Add a death note to this insn, for an input reload. */
-
- if ((reload_when_needed[j] == RELOAD_OTHER
- || reload_when_needed[j] == RELOAD_FOR_INPUT)
- && ! dead_or_set_p (insn, reloadreg))
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_DEAD,
- reloadreg, REG_NOTES (insn));
- }
-
- /* When we inherit a reload, the last marked death of the reload reg
- may no longer really be a death. */
- if (reload_reg_rtx[j] != 0
- && PRESERVE_DEATH_INFO_REGNO_P (REGNO (reload_reg_rtx[j]))
- && reload_inherited[j])
- {
- /* Handle inheriting an output reload.
- Remove the death note from the output reload insn. */
- if (reload_spill_index[j] >= 0
- && GET_CODE (reload_in[j]) == REG
- && spill_reg_store[reload_spill_index[j]] != 0
- && find_regno_note (spill_reg_store[reload_spill_index[j]],
- REG_DEAD, REGNO (reload_reg_rtx[j])))
- remove_death (REGNO (reload_reg_rtx[j]),
- spill_reg_store[reload_spill_index[j]]);
- /* Likewise for input reloads that were inherited. */
- else if (reload_spill_index[j] >= 0
- && GET_CODE (reload_in[j]) == REG
- && spill_reg_store[reload_spill_index[j]] == 0
- && reload_inheritance_insn[j] != 0
- && find_regno_note (reload_inheritance_insn[j], REG_DEAD,
- REGNO (reload_reg_rtx[j])))
- remove_death (REGNO (reload_reg_rtx[j]),
- reload_inheritance_insn[j]);
- else
- {
- rtx prev;
-
- /* We got this register from find_equiv_reg.
- Search back for its last death note and get rid of it.
- But don't search back too far.
- Don't go past a place where this reg is set,
- since a death note before that remains valid. */
- for (prev = PREV_INSN (insn);
- prev && GET_CODE (prev) != CODE_LABEL;
- prev = PREV_INSN (prev))
- if (GET_RTX_CLASS (GET_CODE (prev)) == 'i'
- && dead_or_set_p (prev, reload_reg_rtx[j]))
- {
- if (find_regno_note (prev, REG_DEAD,
- REGNO (reload_reg_rtx[j])))
- remove_death (REGNO (reload_reg_rtx[j]), prev);
- break;
- }
- }
- }
-
- /* We might have used find_equiv_reg above to choose an alternate
- place from which to reload. If so, and it died, we need to remove
- that death and move it to one of the insns we just made. */
-
- if (oldequiv_reg != 0
- && PRESERVE_DEATH_INFO_REGNO_P (true_regnum (oldequiv_reg)))
- {
- rtx prev, prev1;
-
- for (prev = PREV_INSN (insn); prev && GET_CODE (prev) != CODE_LABEL;
- prev = PREV_INSN (prev))
- if (GET_RTX_CLASS (GET_CODE (prev)) == 'i'
- && dead_or_set_p (prev, oldequiv_reg))
- {
- if (find_regno_note (prev, REG_DEAD, REGNO (oldequiv_reg)))
- {
- for (prev1 = this_reload_insn;
- prev1; prev1 = PREV_INSN (prev1))
- if (GET_RTX_CLASS (GET_CODE (prev1) == 'i')
- && reg_overlap_mentioned_for_reload_p (oldequiv_reg,
- PATTERN (prev1)))
- {
- REG_NOTES (prev1) = gen_rtx_EXPR_LIST (REG_DEAD,
- oldequiv_reg,
- REG_NOTES (prev1));
- break;
- }
- remove_death (REGNO (oldequiv_reg), prev);
- }
- break;
- }
- }
-#endif
/* If we are reloading a register that was recently stored in with an
output-reload, see if we can prove there was
reload_when_needed[j]);
}
-#ifdef PRESERVE_DEATH_INFO_REGNO_P
- /* If final will look at death notes for this reg,
- put one on the last output-reload insn to use it. Similarly
- for any secondary register. */
- if (PRESERVE_DEATH_INFO_REGNO_P (REGNO (reloadreg)))
- for (p = get_last_insn (); p; p = PREV_INSN (p))
- if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
- && reg_overlap_mentioned_for_reload_p (reloadreg,
- PATTERN (p)))
- REG_NOTES (p) = gen_rtx_EXPR_LIST (REG_DEAD,
- reloadreg, REG_NOTES (p));
-
-#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
- if (! special && second_reloadreg
- && PRESERVE_DEATH_INFO_REGNO_P (REGNO (second_reloadreg)))
- for (p = get_last_insn (); p; p = PREV_INSN (p))
- if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
- && reg_overlap_mentioned_for_reload_p (second_reloadreg,
- PATTERN (p)))
- REG_NOTES (p) = gen_rtx_EXPR_LIST (REG_DEAD,
- second_reloadreg,
- REG_NOTES (p));
-#endif
-#endif
/* Look at all insns we emitted, just to be safe. */
for (p = get_insns (); p; p = NEXT_INSN (p))
if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
basic_block_end[chain->block] = PREV_INSN (following_insn);
}
- /* Move death notes from INSN
- to output-operand-address and output reload insns. */
-#ifdef PRESERVE_DEATH_INFO_REGNO_P
- {
- rtx insn1;
- /* Loop over those insns, last ones first. */
- for (insn1 = PREV_INSN (following_insn); insn1 != insn;
- insn1 = PREV_INSN (insn1))
- if (GET_CODE (insn1) == INSN && GET_CODE (PATTERN (insn1)) == SET)
- {
- rtx source = SET_SRC (PATTERN (insn1));
- rtx dest = SET_DEST (PATTERN (insn1));
-
- /* The note we will examine next. */
- rtx reg_notes = REG_NOTES (insn);
- /* The place that pointed to this note. */
- rtx *prev_reg_note = ®_NOTES (insn);
-
- /* If the note is for something used in the source of this
- reload insn, or in the output address, move the note. */
- while (reg_notes)
- {
- rtx next_reg_notes = XEXP (reg_notes, 1);
- if (REG_NOTE_KIND (reg_notes) == REG_DEAD
- && GET_CODE (XEXP (reg_notes, 0)) == REG
- && ((GET_CODE (dest) != REG
- && reg_overlap_mentioned_for_reload_p (XEXP (reg_notes, 0),
- dest))
- || reg_overlap_mentioned_for_reload_p (XEXP (reg_notes, 0),
- source)))
- {
- *prev_reg_note = next_reg_notes;
- XEXP (reg_notes, 1) = REG_NOTES (insn1);
- REG_NOTES (insn1) = reg_notes;
- }
- else
- prev_reg_note = &XEXP (reg_notes, 1);
-
- reg_notes = next_reg_notes;
- }
- }
- }
-#endif
-
/* For all the spill regs newly reloaded in this instruction,
record what they were reloaded from, so subsequent instructions
can inherit the reloads.
static rtx invalidate_regno_rtx;
-/* This is a set of registers for which we must remove REG_DEAD notes in
- previous insns, because our modifications made them invalid. That can
- happen if we introduced the register into the current insn, or we deleted
- the current insn which used to set the register. */
-
-static HARD_REG_SET no_longer_dead_regs;
-
/* Invalidate any entries in reg_values which depend on REGNO,
including those for REGNO itself. This is called if REGNO is
changing. If CLOBBER is true, then always forget anything we
reload_cse_invalidate_mem (dest);
}
-/* Possibly delete death notes on the insns before INSN if modifying INSN
- extended the lifespan of the registers. */
-
-static void
-reload_cse_delete_death_notes (insn)
- rtx insn;
-{
- int dreg;
-
- for (dreg = 0; dreg < FIRST_PSEUDO_REGISTER; dreg++)
- {
- rtx trial;
-
- if (! TEST_HARD_REG_BIT (no_longer_dead_regs, dreg))
- continue;
-
- for (trial = prev_nonnote_insn (insn);
- (trial
- && GET_CODE (trial) != CODE_LABEL
- && GET_CODE (trial) != BARRIER);
- trial = prev_nonnote_insn (trial))
- {
- if (find_regno_note (trial, REG_DEAD, dreg))
- {
- remove_death (dreg, trial);
- break;
- }
- }
- }
-}
-
-/* Record that the current insn uses hard reg REGNO in mode MODE. This
- will be used in reload_cse_delete_death_notes to delete prior REG_DEAD
- notes for this register. */
-
-static void
-reload_cse_no_longer_dead (regno, mode)
- int regno;
- enum machine_mode mode;
-{
- int nregs = HARD_REGNO_NREGS (regno, mode);
- while (nregs-- > 0)
- {
- SET_HARD_REG_BIT (no_longer_dead_regs, regno);
- regno++;
- }
-}
-
-
/* Do a very simple CSE pass over the hard registers.
This function detects no-op moves where we happened to assign two
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
continue;
- CLEAR_HARD_REG_SET (no_longer_dead_regs);
-
/* If this is a call instruction, forget anything stored in a
call clobbered register, or, if this is not a const call, in
memory. */
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
}
- reload_cse_delete_death_notes (insn);
/* We're done with this insn. */
continue;
}
/* It's not a no-op, but we can try to simplify it. */
- CLEAR_HARD_REG_SET (no_longer_dead_regs);
count += reload_cse_simplify_set (body, insn);
- if (count > 0 && apply_change_group ())
- reload_cse_delete_death_notes (insn);
- else if (reload_cse_simplify_operands (insn))
- reload_cse_delete_death_notes (insn);
+ if (count > 0)
+ apply_change_group ();
+ else
+ reload_cse_simplify_operands (insn);
reload_cse_record_set (body, body);
}
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
}
- reload_cse_delete_death_notes (insn);
/* We're done with this insn. */
continue;
}
/* It's not a no-op, but we can try to simplify it. */
- CLEAR_HARD_REG_SET (no_longer_dead_regs);
for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
if (GET_CODE (XVECEXP (body, 0, i)) == SET)
count += reload_cse_simplify_set (XVECEXP (body, 0, i), insn);
- if (count > 0 && apply_change_group ())
- reload_cse_delete_death_notes (insn);
- else if (reload_cse_simplify_operands (insn))
- reload_cse_delete_death_notes (insn);
+ if (count > 0)
+ apply_change_group ();
+ else
+ reload_cse_simplify_operands (insn);
/* Look through the PARALLEL and record the values being
set, if possible. Also handle any CLOBBERs. */
ret = 1;
}
- /* If we can delete this SET, then we need to look for an earlier
- REG_DEAD note on DREG, and remove it if it exists. */
- if (ret && dreg >= 0)
- {
- if (! find_regno_note (insn, REG_UNUSED, dreg))
- reload_cse_no_longer_dead (dreg, dest_mode);
- }
-
return ret;
}
storage. */
push_obstacks (&reload_obstack, &reload_obstack);
- if (validated && ! find_regno_note (insn, REG_UNUSED, i))
- {
- reload_cse_no_longer_dead (i, dest_mode);
- return 1;
- }
+ if (validated)
+ return 1;
}
}
return 0;
/* Substitute the operands as determined by op_alt_regno for the best
alternative. */
j = alternative_order[0];
- CLEAR_HARD_REG_SET (no_longer_dead_regs);
/* Pop back to the real obstacks while changing the insn. */
pop_obstacks ();
if (op_alt_regno[i][j] == -1)
continue;
- reload_cse_no_longer_dead (op_alt_regno[i][j], mode);
validate_change (insn, recog_operand_loc[i],
gen_rtx_REG (mode, op_alt_regno[i][j]), 1);
}
if (op_alt_regno[op][j] == -1)
continue;
- reload_cse_no_longer_dead (op_alt_regno[op][j], mode);
validate_change (insn, recog_dup_loc[i],
gen_rtx_REG (mode, op_alt_regno[op][j]), 1);
}
static enum machine_mode reg_mode[FIRST_PSEUDO_REGISTER];
/* move2add_luid is linearily increased while scanning the instructions
from first to last. It is used to set reg_set_luid in
- reload_cse_move2add and move2add_note_store, and to set reg_death_luid
- (local variable of reload_cse_move2add) . */
+ reload_cse_move2add and move2add_note_store. */
static int move2add_luid;
static void
int i;
rtx insn;
int last_label_luid;
- /* reg_death and reg_death_luid are solely used to remove stale REG_DEAD
- notes. */
- int reg_death_luid[FIRST_PSEUDO_REGISTER];
- rtx reg_death[FIRST_PSEUDO_REGISTER];
for (i = FIRST_PSEUDO_REGISTER-1; i >= 0; i--)
- {
- reg_set_luid[i] = 0;
- reg_death_luid[i] = 0;
- }
+ reg_set_luid[i] = 0;
+
last_label_luid = 0;
move2add_luid = 1;
for (insn = first; insn; insn = NEXT_INSN (insn), move2add_luid++)
&& have_add2_insn (GET_MODE (reg)))
success = validate_change (insn, &PATTERN (insn),
gen_add2_insn (reg, new_src), 0);
- if (success && reg_death_luid[regno] > reg_set_luid[regno])
- remove_death (regno, reg_death[regno]);
reg_set_luid[regno] = move2add_luid;
reg_mode[regno] = GET_MODE (reg);
reg_offset[regno] = src;
gen_add2_insn (reg, new_src), 0);
if (success)
{
- if (reg_death_luid[regno] > reg_set_luid[regno])
- remove_death (regno, reg_death[regno]);
/* INSN might be the first insn in a basic block
if the preceding insn is a conditional jump
or a possible-throwing call. */
reg_offset[regno] = note;
}
}
- /* Remember any REG_DEAD notes so that we can remove them
- later if necessary. */
- else if (REG_NOTE_KIND (note) == REG_DEAD
- && GET_CODE (XEXP (note, 0)) == REG)
- {
- int regno = REGNO (XEXP (note, 0));
- if (regno < FIRST_PSEUDO_REGISTER)
- {
- reg_death[regno] = insn;
- reg_death_luid[regno] = move2add_luid;
- }
- }
}
note_stores (PATTERN (insn), move2add_note_store);
/* If this is a CALL_INSN, all call used registers are stored with