/* Reload pseudo regs into hard regs for insns that require hard regs.
- Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
This file is part of GNU CC.
as part of a group, even if it seems to be otherwise ok. */
static HARD_REG_SET counted_for_nongroups;
+/* Indexed by pseudo reg number N,
+ says may not delete stores into the real (memory) home of pseudo N.
+ This is set if we already substituted a memory equivalent in some uses,
+ which happens when we have to eliminate the fp from it. */
+static char *cannot_omit_stores;
+
/* Nonzero if indirect addressing is supported on the machine; this means
that spilling (REG n) does not require reloading it into a register in
order to do (MEM (REG n)) or (MEM (PLUS (REG n) (CONST_INT c))). The
FILE *));
static void delete_dead_insn PROTO((rtx));
static void alter_reg PROTO((int, int));
+static void mark_scratch_live PROTO((rtx));
static void set_label_offsets PROTO((rtx, rtx, int));
static int eliminate_regs_in_insn PROTO((rtx, int));
static void mark_not_eliminable PROTO((rtx, rtx));
struct hard_reg_n_uses *));
static void order_regs_for_reload PROTO((void));
static void reload_as_needed PROTO((rtx, int));
-static void forget_old_reloads_1 PROTO((rtx));
+static void forget_old_reloads_1 PROTO((rtx, rtx));
static int reload_reg_class_lower PROTO((short *, short *));
static void mark_reload_reg_in_use PROTO((int, int, enum reload_type,
enum machine_mode));
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
mark_home_live (i);
+ for (i = 0; i < scratch_list_length; i++)
+ if (scratch_list[i])
+ mark_scratch_live (scratch_list[i]);
+
/* Make sure that the last insn in the chain
is not something that needs reloading. */
emit_note (NULL_PTR, NOTE_INSN_DELETED);
bzero (reg_equiv_address, max_regno * sizeof (rtx));
reg_max_ref_width = (int *) alloca (max_regno * sizeof (int));
bzero (reg_max_ref_width, max_regno * sizeof (int));
+ cannot_omit_stores = (char *) alloca (max_regno);
+ bzero (cannot_omit_stores, max_regno);
/* Look for REG_EQUIV notes; record what each pseudo is equivalent to.
Also find all paradoxical subregs
and constant, it is probably not addressable because the constant is
out of range, in that case record the address; we will generate
hairy code to compute the address in a register each time it is
- needed.
+ needed. Similarly if it is a hard register, but one that is not
+ valid as an address register.
If the location is not addressable, but does not have one of the
above forms, assign a stack slot. We have to do this to avoid the
XEXP (x, 0)))
reg_equiv_mem[i] = x, reg_equiv_address[i] = 0;
else if (CONSTANT_P (XEXP (x, 0))
+ || (GET_CODE (XEXP (x, 0)) == REG
+ && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)
|| (GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
&& (REGNO (XEXP (XEXP (x, 0), 0))
if (i == FIRST_PSEUDO_REGISTER)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
+ int k;
j = potential_reload_regs[i];
+ /* Verify that J+1 is a potential reload reg. */
+ for (k = 0; k < FIRST_PSEUDO_REGISTER; k++)
+ if (potential_reload_regs[k] == j + 1)
+ break;
if (j >= 0 && j + 1 < FIRST_PSEUDO_REGISTER
+ && k < FIRST_PSEUDO_REGISTER
&& spill_reg_order[j] < 0 && spill_reg_order[j + 1] < 0
&& TEST_HARD_REG_BIT (reg_class_contents[class], j)
&& TEST_HARD_REG_BIT (reg_class_contents[class], j + 1)
&& HARD_REGNO_MODE_OK (j, group_mode[class])
&& ! TEST_HARD_REG_BIT (counted_for_nongroups,
- j + 1))
+ j + 1)
+ && ! TEST_HARD_REG_BIT (bad_spill_regs, j + 1))
break;
}
while (max_needs[class] > 0 || max_nongroups[class] > 0)
{
+#ifdef SMALL_REGISTER_CLASSES
+ /* This should be right for all machines, but only the 386
+ is known to need it, so this conditional plays safe.
+ ??? For 2.5, try making this unconditional. */
+ /* If we spilled enough regs, but they weren't counted
+ against the non-group need, see if we can count them now.
+ If so, we can avoid some actual spilling. */
+ if (max_needs[class] <= 0 && max_nongroups[class] > 0)
+ for (i = 0; i < n_spills; i++)
+ if (TEST_HARD_REG_BIT (reg_class_contents[class],
+ spill_regs[i])
+ && !TEST_HARD_REG_BIT (counted_for_groups,
+ spill_regs[i])
+ && !TEST_HARD_REG_BIT (counted_for_nongroups,
+ spill_regs[i])
+ && max_nongroups[class] > 0)
+ {
+ register enum reg_class *p;
+
+ SET_HARD_REG_BIT (counted_for_nongroups, spill_regs[i]);
+ max_nongroups[class]--;
+ p = reg_class_superclasses[class];
+ while (*p != LIM_REG_CLASSES)
+ max_nongroups[(int) *p++]--;
+ }
+ if (max_needs[class] <= 0 && max_nongroups[class] <= 0)
+ break;
+#endif
+
/* Consider the potential reload regs that aren't
yet in use as reload regs, in order of preference.
Find the most preferred one that's in this class. */
reg_equiv_constant = 0;
reg_equiv_memory_loc = 0;
+ free (scratch_list);
+ scratch_list = 0;
+ free (scratch_block);
+ scratch_block = 0;
+
return failure;
}
\f
while (i < lim)
regs_ever_live[i++] = 1;
}
+
+/* Mark the registers used in SCRATCH as being live. */
+
+static void
+mark_scratch_live (scratch)
+ rtx scratch;
+{
+ register int i;
+ int regno = REGNO (scratch);
+ int lim = regno + HARD_REGNO_NREGS (regno, GET_MODE (scratch));
+
+ for (i = regno; i < lim; i++)
+ regs_ever_live[i] = 1;
+}
\f
/* This function handles the tracking of elimination offsets around branches.
new = eliminate_regs (reg_equiv_memory_loc[regno],
mem_mode, NULL_RTX);
if (new != reg_equiv_memory_loc[regno])
- return copy_rtx (new);
+ {
+ cannot_omit_stores[regno] = 1;
+ return copy_rtx (new);
+ }
}
return x;
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
if (ep->to_rtx == XEXP (x, 0))
{
+ int size = GET_MODE_SIZE (mem_mode);
+
+ /* If more bytes than MEM_MODE are pushed, account for them. */
+#ifdef PUSH_ROUNDING
+ if (ep->to_rtx == stack_pointer_rtx)
+ size = PUSH_ROUNDING (size);
+#endif
if (code == PRE_DEC || code == POST_DEC)
- ep->offset += GET_MODE_SIZE (mem_mode);
+ ep->offset += size;
else
- ep->offset -= GET_MODE_SIZE (mem_mode);
+ ep->offset -= size;
}
/* Fall through to generic unary operation case. */
{
if (GET_CODE (new) == MEM
&& (GET_MODE_SIZE (GET_MODE (x))
- <= GET_MODE_SIZE (GET_MODE (new))))
+ <= GET_MODE_SIZE (GET_MODE (new)))
+#if defined(BYTE_LOADS_ZERO_EXTEND) || defined(BYTE_LOADS_SIGN_EXTEND)
+ /* On these machines we will be reloading what is
+ inside the SUBREG if it originally was a pseudo and
+ the inner and outer modes are both a word or
+ smaller. So leave the SUBREG then. */
+ && ! (GET_CODE (SUBREG_REG (x)) == REG
+ && GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
+ && GET_MODE_SIZE (GET_MODE (new)) <= UNITS_PER_WORD)
+#endif
+ )
{
int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
enum machine_mode mode = GET_MODE (x);
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS];
ep++)
if (ep->from_rtx == XEXP (SET_SRC (old_body), 0)
- && ep->can_eliminate
- && ep->offset == - INTVAL (XEXP (SET_SRC (old_body), 1)))
+ && ep->can_eliminate)
{
- PATTERN (insn) = gen_rtx (SET, VOIDmode,
- SET_DEST (old_body), ep->to_rtx);
- INSN_CODE (insn) = -1;
- val = 1;
- goto done;
+ /* We must stop at the first elimination that will be used.
+ If this one would replace the PLUS with a REG, do it
+ now. Otherwise, quit the loop and let eliminate_regs
+ do its normal replacement. */
+ if (ep->offset == - INTVAL (XEXP (SET_SRC (old_body), 1)))
+ {
+ PATTERN (insn) = gen_rtx (SET, VOIDmode,
+ SET_DEST (old_body), ep->to_rtx);
+ INSN_CODE (insn) = -1;
+ val = 1;
+ goto done;
+ }
+
+ break;
}
}
FILE *dumpfile;
int cant_eliminate;
{
+ enum reg_class class = REGNO_REG_CLASS (regno);
int something_changed = 0;
register int i;
PSEUDO_REGNO_MODE (i))
> regno))
{
- enum reg_class class = REGNO_REG_CLASS (regno);
-
/* If this register belongs solely to a basic block which needed no
spilling of any class that this register is contained in,
leave it be, unless we are spilling this register because
i, reg_renumber[i]);
}
}
+ for (i = 0; i < scratch_list_length; i++)
+ {
+ if (scratch_list[i] && REGNO (scratch_list[i]) == regno)
+ {
+ if (! cant_eliminate && basic_block_needs[0]
+ && ! basic_block_needs[(int) class][scratch_block[i]])
+ {
+ enum reg_class *p;
+
+ for (p = reg_class_superclasses[(int) class];
+ *p != LIM_REG_CLASSES; p++)
+ if (basic_block_needs[(int) *p][scratch_block[i]] > 0)
+ break;
+
+ if (*p == LIM_REG_CLASSES)
+ continue;
+ }
+ PUT_CODE (scratch_list[i], SCRATCH);
+ scratch_list[i] = 0;
+ something_changed = 1;
+ continue;
+ }
+ }
return something_changed;
}
break;
if (i == n_reloads)
- forget_old_reloads_1 (XEXP (x, 0));
+ forget_old_reloads_1 (XEXP (x, 0), NULL_RTX);
}
#endif
}
or it may be a pseudo reg that was reloaded from. */
static void
-forget_old_reloads_1 (x)
+forget_old_reloads_1 (x, ignored)
rtx x;
+ rtx ignored;
{
register int regno;
int nr;
/* Index of last register assigned as a spill register. We allocate in
a round-robin fashio. */
-static last_spill_reg = 0;
+static int last_spill_reg = 0;
/* Find a spill register to use as a reload register for reload R.
LAST_RELOAD is non-zero if this is the last reload for the insn being
if (k == nr)
{
- /* Mark the register as in use for this part of
- the insn. */
- mark_reload_reg_in_use (spill_regs[i],
- reload_opnum[r],
- reload_when_needed[r],
- reload_mode[r]);
- reload_reg_rtx[r] = reg_last_reload_reg[regno];
- reload_inherited[r] = 1;
- reload_inheritance_insn[r] = reg_reloaded_insn[i];
- reload_spill_index[r] = i;
- SET_HARD_REG_BIT (reload_reg_used_for_inherit,
- spill_regs[i]);
+ int i1;
+
+ /* We found a register that contains the
+ value we need. If this register is the
+ same as an `earlyclobber' operand of the
+ current insn, just mark it as a place to
+ reload from since we can't use it as the
+ reload register itself. */
+
+ for (i1 = 0; i1 < n_earlyclobbers; i1++)
+ if (reg_overlap_mentioned_for_reload_p
+ (reg_last_reload_reg[regno],
+ reload_earlyclobbers[i1]))
+ break;
+
+ if (i1 != n_earlyclobbers
+ /* Don't really use the inherited spill reg
+ if we need it wider than we've got it. */
+ || (GET_MODE_SIZE (reload_mode[r])
+ > GET_MODE_SIZE (mode)))
+ reload_override_in[r] = reg_last_reload_reg[regno];
+ else
+ {
+ /* We can use this as a reload reg. */
+ /* Mark the register as in use for this part of
+ the insn. */
+ mark_reload_reg_in_use (spill_regs[i],
+ reload_opnum[r],
+ reload_when_needed[r],
+ reload_mode[r]);
+ reload_reg_rtx[r] = reg_last_reload_reg[regno];
+ reload_inherited[r] = 1;
+ reload_inheritance_insn[r]
+ = reg_reloaded_insn[i];
+ reload_spill_index[r] = i;
+ SET_HARD_REG_BIT (reload_reg_used_for_inherit,
+ spill_regs[i]);
+ }
}
}
}
&& GET_CODE (PATTERN (PREV_INSN (before_insn))) == USE)
before_insn = PREV_INSN (before_insn);
- /* If this insn is followed by any CLOBBER insns made by find_reloads,
+ /* If INSN is followed by any CLOBBER insns made by find_reloads,
put our reloads after them since they may otherwise be
misinterpreted. */
- while (NEXT_INSN (following_insn) != 0
- && GET_CODE (NEXT_INSN (following_insn)) == INSN
- && GET_MODE (NEXT_INSN (following_insn)) == DImode
- && GET_CODE (PATTERN (NEXT_INSN (following_insn))) == CLOBBER)
+ while (GET_CODE (following_insn) == INSN
+ && GET_MODE (following_insn) == DImode
+ && GET_CODE (PATTERN (following_insn)) == CLOBBER
+ && NEXT_INSN (following_insn) != 0)
following_insn = NEXT_INSN (following_insn);
/* Now output the instructions to copy the data into and out of the
oldequiv_reg = SUBREG_REG (oldequiv);
/* Encapsulate both RELOADREG and OLDEQUIV into that mode,
- then load RELOADREG from OLDEQUIV. */
+ then load RELOADREG from OLDEQUIV. Note that we cannot use
+ gen_lowpart_common since it can do the wrong thing when
+ RELOADREG has a multi-word mode. Note that RELOADREG
+ must always be a REG here. */
if (GET_MODE (reloadreg) != mode)
- reloadreg = gen_lowpart_common (mode, reloadreg);
+ reloadreg = gen_rtx (REG, mode, REGNO (reloadreg));
while (GET_CODE (oldequiv) == SUBREG && GET_MODE (oldequiv) != mode)
oldequiv = SUBREG_REG (oldequiv);
if (GET_MODE (oldequiv) != VOIDmode
if (new_icode == CODE_FOR_nothing)
new_mode = mode;
else
- new_mode = insn_operand_mode[new_icode][2];
+ new_mode = insn_operand_mode[(int) new_icode][2];
if (GET_MODE (second_reload_reg) != new_mode)
{
}
if (GET_MODE (reloadreg) != mode)
- reloadreg = gen_lowpart_common (mode, reloadreg);
+ reloadreg = gen_rtx (REG, mode, REGNO (reloadreg));
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
return;
}
+ if (cannot_omit_stores[REGNO (reg)])
+ return;
+
/* If this insn will store in the pseudo again,
the previous store can be removed. */
if (reload_out[j] == reload_in[j])