static void reload_cse_invalidate_rtx PROTO((rtx, rtx));
static void reload_cse_regs PROTO((rtx));
static int reload_cse_regno_equal_p PROTO((int, rtx, enum machine_mode));
-static int reload_cse_noop_set_p PROTO((rtx));
+static int reload_cse_noop_set_p PROTO((rtx, rtx));
static void reload_cse_simplify_set PROTO((rtx, rtx));
static void reload_cse_check_clobber PROTO((rtx, rtx));
static void reload_cse_record_set PROTO((rtx, rtx));
as homes for pseudo registers.
This is done here rather than (eg) in global_alloc
because this point is reached even if not optimizing. */
-
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
mark_home_live (i);
+ /* A function that receives a nonlocal goto must save all call-saved
+ registers. */
+ if (current_function_has_nonlocal_label)
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ if (! call_used_regs[i] && ! fixed_regs[i])
+ regs_ever_live[i] = 1;
+ }
+
for (i = 0; i < scratch_list_length; i++)
if (scratch_list[i])
mark_scratch_live (scratch_list[i]);
static rtx *reg_values;
+/* This is a preallocated REG rtx which we use as a temporary in
+ reload_cse_invalidate_regno, so that we don't need to allocate a
+ new one each time through a loop in that function. */
+
+static rtx invalidate_regno_rtx;
+
/* 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
for (x = reg_values[i]; x; x = XEXP (x, 1))
{
if (XEXP (x, 0) != 0
- && refers_to_regno_p (regno, endregno, XEXP (x, 0), NULL_RTX))
+ && refers_to_regno_p (regno, endregno, XEXP (x, 0), NULL_PTR))
{
/* If this is the only entry on the list, clear
reg_values[i]. Otherwise, just clear this entry on
}
}
}
+
+ /* We must look at earlier registers, in case REGNO is part of a
+ multi word value but is not the first register. If an earlier
+ register has a value in a mode which overlaps REGNO, then we must
+ invalidate that earlier register. Note that we do not need to
+ check REGNO or later registers (we must not check REGNO itself,
+ because we would incorrectly conclude that there was a conflict). */
+
+ for (i = 0; i < regno; i++)
+ {
+ rtx x;
+
+ for (x = reg_values[i]; x; x = XEXP (x, 1))
+ {
+ if (XEXP (x, 0) != 0)
+ {
+ PUT_MODE (invalidate_regno_rtx, GET_MODE (x));
+ REGNO (invalidate_regno_rtx) = i;
+ if (refers_to_regno_p (regno, endregno, invalidate_regno_rtx,
+ NULL_PTR))
+ {
+ reload_cse_invalidate_regno (i, VOIDmode, 1);
+ break;
+ }
+ }
+ }
+ }
}
/* The memory at address (plus MEM_BASE MEM_OFFSET), where MEM_OFFSET
{
/* Get rid of a few simple cases quickly. */
case REG:
- case SUBREG:
case PC:
case CC0:
case SCRATCH:
memory for a non-const call instruction. */
callmem = gen_rtx (MEM, BLKmode, const0_rtx);
+ /* This is used in reload_cse_invalidate_regno to avoid consing a
+ new REG in a loop in that function. */
+ invalidate_regno_rtx = gen_rtx (REG, VOIDmode, 0);
+
for (insn = first; insn; insn = NEXT_INSN (insn))
{
rtx body;
body = PATTERN (insn);
if (GET_CODE (body) == SET)
{
- if (reload_cse_noop_set_p (body))
+ if (reload_cse_noop_set_p (body, insn))
{
- /* If we were preserving death notes, then we would want
- to remove any existing death note for the register
- being set. */
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
the entire PARALLEL. */
for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
if (GET_CODE (XVECEXP (body, 0, i)) != SET
- || ! reload_cse_noop_set_p (XVECEXP (body, 0, i)))
+ || ! reload_cse_noop_set_p (XVECEXP (body, 0, i), insn))
break;
if (i < 0)
{
- /* If we were preserving death notes, then we would want
- to remove any existing death notes for the registers
- being set. */
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
return 0;
}
-/* See whether a single SET instruction is a nooop. */
+/* See whether a single set is a noop. SET is the set instruction we
+ are should check, and INSN is the instruction from which it came. */
static int
-reload_cse_noop_set_p (set)
+reload_cse_noop_set_p (set, insn)
rtx set;
+ rtx insn;
{
rtx src, dest;
enum machine_mode dest_mode;
int dreg, sreg;
+ int ret;
src = SET_SRC (set);
dest = SET_DEST (set);
dreg = true_regnum (dest);
sreg = true_regnum (src);
+ /* Check for setting a register to itself. In this case, we don't
+ have to worry about REG_DEAD notes. */
+ if (dreg >= 0 && dreg == sreg)
+ return 1;
+
+ ret = 0;
if (dreg >= 0)
{
/* Check for setting a register to itself. */
if (dreg == sreg)
- return 1;
+ ret = 1;
/* Check for setting a register to a value which we already know
is in the register. */
- if (reload_cse_regno_equal_p (dreg, src, dest_mode))
- return 1;
+ else if (reload_cse_regno_equal_p (dreg, src, dest_mode))
+ ret = 1;
/* Check for setting a register DREG to another register SREG
where SREG is equal to a value which is already in DREG. */
- if (sreg >= 0)
+ else if (sreg >= 0)
{
rtx x;
for (x = reg_values[sreg]; x; x = XEXP (x, 1))
- if (XEXP (x, 0) != 0
- && reload_cse_regno_equal_p (dreg, XEXP (x, 0), dest_mode))
- return 1;
+ {
+ rtx tmp;
+
+ if (XEXP (x, 0) == 0)
+ continue;
+
+ if (dest_mode == GET_MODE (x))
+ tmp = XEXP (x, 0);
+ else if (GET_MODE_BITSIZE (dest_mode)
+ < GET_MODE_BITSIZE (GET_MODE (x)))
+ tmp = gen_lowpart_common (dest_mode, XEXP (x, 0));
+ else
+ continue;
+
+ if (tmp
+ && reload_cse_regno_equal_p (dreg, tmp, dest_mode))
+ {
+ ret = 1;
+ break;
+ }
+ }
}
}
else if (GET_CODE (dest) == MEM)
if (sreg >= 0
&& reload_cse_regno_equal_p (sreg, dest, dest_mode)
&& ! side_effects_p (dest))
- return 1;
+ ret = 1;
}
- return 0;
+ /* 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)
+ {
+ if (! find_regno_note (insn, REG_UNUSED, dreg))
+ {
+ rtx trial;
+
+ 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;
+ }
+ }
+ }
+ }
+
+ return ret;
}
/* Try to simplify a single SET instruction. SET is the set pattern.
push_obstacks (&reload_obstack, &reload_obstack);
if (validated)
- return;
+ {
+ /* We need to look for an earlier REG_DEAD note on I,
+ and remove it if it exists. */
+ if (! find_regno_note (insn, REG_UNUSED, i))
+ {
+ rtx trial;
+
+ 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, i))
+ {
+ remove_death (i, trial);
+ break;
+ }
+ }
+ }
+
+ return;
+ }
}
}
}
rtx set;
rtx body;
{
- rtx dest, src;
+ rtx dest, src, x;
int dreg, sreg;
enum machine_mode dest_mode;
sreg = true_regnum (src);
dest_mode = GET_MODE (dest);
+ /* Some machines don't define AUTO_INC_DEC, but they still use push
+ instructions. We need to catch that case here in order to
+ invalidate the stack pointer correctly. Note that invalidating
+ the stack pointer is different from invalidating DEST. */
+ x = dest;
+ while (GET_CODE (x) == SUBREG
+ || GET_CODE (x) == ZERO_EXTRACT
+ || GET_CODE (x) == SIGN_EXTRACT
+ || GET_CODE (x) == STRICT_LOW_PART)
+ x = XEXP (x, 0);
+ if (push_operand (x, GET_MODE (x)))
+ {
+ reload_cse_invalidate_rtx (stack_pointer_rtx, NULL_RTX);
+ reload_cse_invalidate_rtx (dest, NULL_RTX);
+ return;
+ }
+
/* We can only handle an assignment to a register, or a store of a
register to a memory location. For other cases, we just clobber
the destination. We also have to just clobber if there are side
/* This is an assignment to a register. Update the value we
have stored for the register. */
if (sreg >= 0)
- reg_values[dreg] = reg_values[sreg];
+ {
+ rtx x;
+
+ /* This is a copy from one register to another. Any values
+ which were valid for SREG are now valid for DREG. If the
+ mode changes, we use gen_lowpart_common to extract only
+ the part of the value that is copied. */
+ reg_values[dreg] = 0;
+ for (x = reg_values[sreg]; x; x = XEXP (x, 1))
+ {
+ rtx tmp;
+
+ if (XEXP (x, 0) == 0)
+ continue;
+ if (dest_mode == GET_MODE (XEXP (x, 0)))
+ tmp = XEXP (x, 0);
+ else
+ tmp = gen_lowpart_common (dest_mode, XEXP (x, 0));
+ if (tmp)
+ reg_values[dreg] = gen_rtx (EXPR_LIST, dest_mode, tmp,
+ reg_values[dreg]);
+ }
+ }
else
reg_values[dreg] = gen_rtx (EXPR_LIST, dest_mode, src, NULL_RTX);