/* 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.
#endif
\f
/* During reload_as_needed, element N contains a REG rtx for the hard reg
- into which pseudo reg N has been reloaded (perhaps for a previous insn). */
+ into which reg N has been reloaded (perhaps for a previous insn). */
static rtx *reg_last_reload_reg;
/* Elt N nonzero if reg_last_reload_reg[N] has been set in this insn
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));
+static void clear_reload_reg_in_use PROTO((int, int, enum reload_type,
+ enum machine_mode));
static int reload_reg_free_p PROTO((int, int, enum reload_type));
static int reload_reg_free_before_p PROTO((int, int, enum reload_type));
static int reload_reg_reaches_end_p PROTO((int, int, enum reload_type));
/* Initialize obstack for our rtl allocation. */
gcc_obstack_init (&reload_obstack);
reload_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
-
-#ifdef HAVE_SECONDARY_RELOADS
-
- /* Initialize the optabs for doing special input and output reloads. */
-
- for (i = 0; i < NUM_MACHINE_MODES; i++)
- reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
-
-#ifdef HAVE_reload_inqi
- if (HAVE_reload_inqi)
- reload_in_optab[(int) QImode] = CODE_FOR_reload_inqi;
-#endif
-#ifdef HAVE_reload_inhi
- if (HAVE_reload_inhi)
- reload_in_optab[(int) HImode] = CODE_FOR_reload_inhi;
-#endif
-#ifdef HAVE_reload_insi
- if (HAVE_reload_insi)
- reload_in_optab[(int) SImode] = CODE_FOR_reload_insi;
-#endif
-#ifdef HAVE_reload_indi
- if (HAVE_reload_indi)
- reload_in_optab[(int) DImode] = CODE_FOR_reload_indi;
-#endif
-#ifdef HAVE_reload_inti
- if (HAVE_reload_inti)
- reload_in_optab[(int) TImode] = CODE_FOR_reload_inti;
-#endif
-#ifdef HAVE_reload_inqf
- if (HAVE_reload_inqf)
- reload_in_optab[(int) QFmode] = CODE_FOR_reload_inqf;
-#endif
-#ifdef HAVE_reload_inhf
- if (HAVE_reload_inhf)
- reload_in_optab[(int) HFmode] = CODE_FOR_reload_inhf;
-#endif
-#ifdef HAVE_reload_insf
- if (HAVE_reload_insf)
- reload_in_optab[(int) SFmode] = CODE_FOR_reload_insf;
-#endif
-#ifdef HAVE_reload_indf
- if (HAVE_reload_indf)
- reload_in_optab[(int) DFmode] = CODE_FOR_reload_indf;
-#endif
-#ifdef HAVE_reload_inxf
- if (HAVE_reload_inxf)
- reload_in_optab[(int) XFmode] = CODE_FOR_reload_inxf;
-#endif
-#ifdef HAVE_reload_intf
- if (HAVE_reload_intf)
- reload_in_optab[(int) TFmode] = CODE_FOR_reload_intf;
-#endif
-
-#ifdef HAVE_reload_outqi
- if (HAVE_reload_outqi)
- reload_out_optab[(int) QImode] = CODE_FOR_reload_outqi;
-#endif
-#ifdef HAVE_reload_outhi
- if (HAVE_reload_outhi)
- reload_out_optab[(int) HImode] = CODE_FOR_reload_outhi;
-#endif
-#ifdef HAVE_reload_outsi
- if (HAVE_reload_outsi)
- reload_out_optab[(int) SImode] = CODE_FOR_reload_outsi;
-#endif
-#ifdef HAVE_reload_outdi
- if (HAVE_reload_outdi)
- reload_out_optab[(int) DImode] = CODE_FOR_reload_outdi;
-#endif
-#ifdef HAVE_reload_outti
- if (HAVE_reload_outti)
- reload_out_optab[(int) TImode] = CODE_FOR_reload_outti;
-#endif
-#ifdef HAVE_reload_outqf
- if (HAVE_reload_outqf)
- reload_out_optab[(int) QFmode] = CODE_FOR_reload_outqf;
-#endif
-#ifdef HAVE_reload_outhf
- if (HAVE_reload_outhf)
- reload_out_optab[(int) HFmode] = CODE_FOR_reload_outhf;
-#endif
-#ifdef HAVE_reload_outsf
- if (HAVE_reload_outsf)
- reload_out_optab[(int) SFmode] = CODE_FOR_reload_outsf;
-#endif
-#ifdef HAVE_reload_outdf
- if (HAVE_reload_outdf)
- reload_out_optab[(int) DFmode] = CODE_FOR_reload_outdf;
-#endif
-#ifdef HAVE_reload_outxf
- if (HAVE_reload_outxf)
- reload_out_optab[(int) XFmode] = CODE_FOR_reload_outxf;
-#endif
-#ifdef HAVE_reload_outtf
- if (HAVE_reload_outtf)
- reload_out_optab[(int) TFmode] = CODE_FOR_reload_outtf;
-#endif
-
-#endif /* HAVE_SECONDARY_RELOADS */
-
}
/* Main entry point for the reload pass.
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;
}
and perhaps store insns after insns that modify the reloaded pseudo reg.
reg_last_reload_reg and reg_reloaded_contents keep track of
- which pseudo-registers are already available in reload registers.
+ which registers are already available in reload registers.
We update these for the reloads that we perform,
as the insns are scanned. */
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;
/* If reg is in use as a reload reg for any sort of reload. */
static HARD_REG_SET reload_reg_used_at_all;
+/* If reg is use as an inherited reload. We just mark the first register
+ in the group. */
+static HARD_REG_SET reload_reg_used_for_inherit;
+
/* Mark reg REGNO as in use for a reload of the sort spec'd by OPNUM and
TYPE. MODE is used to indicate how many consecutive regs are
actually used. */
}
}
+/* Similarly, but show REGNO is no longer in use for a reload. */
+
+static void
+clear_reload_reg_in_use (regno, opnum, type, mode)
+ int regno;
+ int opnum;
+ enum reload_type type;
+ enum machine_mode mode;
+{
+ int nregs = HARD_REGNO_NREGS (regno, mode);
+ int i;
+
+ for (i = regno; i < nregs + regno; i++)
+ {
+ switch (type)
+ {
+ case RELOAD_OTHER:
+ CLEAR_HARD_REG_BIT (reload_reg_used, i);
+ break;
+
+ case RELOAD_FOR_INPUT_ADDRESS:
+ CLEAR_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i);
+ break;
+
+ case RELOAD_FOR_OUTPUT_ADDRESS:
+ CLEAR_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i);
+ break;
+
+ case RELOAD_FOR_OPERAND_ADDRESS:
+ CLEAR_HARD_REG_BIT (reload_reg_used_in_op_addr, i);
+ break;
+
+ case RELOAD_FOR_OTHER_ADDRESS:
+ CLEAR_HARD_REG_BIT (reload_reg_used_in_other_addr, i);
+ break;
+
+ case RELOAD_FOR_INPUT:
+ CLEAR_HARD_REG_BIT (reload_reg_used_in_input[opnum], i);
+ break;
+
+ case RELOAD_FOR_OUTPUT:
+ CLEAR_HARD_REG_BIT (reload_reg_used_in_output[opnum], i);
+ break;
+
+ case RELOAD_FOR_INSN:
+ CLEAR_HARD_REG_BIT (reload_reg_used_in_insn, i);
+ break;
+ }
+ }
+}
+
/* 1 if reg REGNO is free as a reload reg for a reload of the sort
specified by OPNUM and TYPE. */
/* 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
reload_when_needed[r])
&& TEST_HARD_REG_BIT (reg_class_contents[class], spill_regs[i])
&& HARD_REGNO_MODE_OK (spill_regs[i], reload_mode[r])
- /* Look first for regs to share, then for unshared. */
- && (pass || TEST_HARD_REG_BIT (reload_reg_used_at_all,
- spill_regs[i])))
+ /* Look first for regs to share, then for unshared. But
+ don't share regs used for inherited reloads; they are
+ the ones we want to preserve. */
+ && (pass
+ || (TEST_HARD_REG_BIT (reload_reg_used_at_all,
+ spill_regs[i])
+ && ! TEST_HARD_REG_BIT (reload_reg_used_for_inherit,
+ spill_regs[i]))))
{
int nr = HARD_REGNO_NREGS (spill_regs[i], reload_mode[r]);
/* Avoid the problem where spilling a GENERAL_OR_FP_REG
goto failure;
}
- last_spill_reg = i;
-
- /* Mark as in use for this insn the reload regs we use for this. */
- mark_reload_reg_in_use (spill_regs[i], reload_opnum[r],
- reload_when_needed[r], reload_mode[r]);
+ /* I is the index in SPILL_REG_RTX of the reload register we are to
+ allocate. Get an rtx for it and find its register number. */
new = spill_reg_rtx[i];
if (new == 0 || GET_MODE (new) != reload_mode[r])
- spill_reg_rtx[i] = new = gen_rtx (REG, reload_mode[r], spill_regs[i]);
-
- reload_reg_rtx[r] = new;
- reload_spill_index[r] = i;
+ spill_reg_rtx[i] = new
+ = gen_rtx (REG, reload_mode[r], spill_regs[i]);
+
regno = true_regnum (new);
/* Detect when the reload reg can't hold the reload mode.
&& ! HARD_REGNO_MODE_OK (regno, test_mode)))
if (! (reload_out[r] != 0
&& ! HARD_REGNO_MODE_OK (regno, GET_MODE (reload_out[r]))))
- /* The reg is OK. */
- return 1;
+ {
+ /* The reg is OK. */
+ last_spill_reg = i;
+
+ /* Mark as in use for this insn the reload regs we use
+ for this. */
+ mark_reload_reg_in_use (spill_regs[i], reload_opnum[r],
+ reload_when_needed[r], reload_mode[r]);
+
+ reload_reg_rtx[r] = new;
+ reload_spill_index[r] = i;
+ return 1;
+ }
}
/* The reg is not OK. */
Then make a second pass over the reloads to allocate any reloads
that haven't been given registers yet. */
+ CLEAR_HARD_REG_SET (reload_reg_used_for_inherit);
+
for (j = 0; j < n_reloads; j++)
{
register int r = reload_order[j];
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;
+ 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]);
+ }
}
}
}
mark the spill reg as in use for this insn. */
i = spill_reg_order[regno];
if (i >= 0)
- mark_reload_reg_in_use (regno, reload_opnum[r],
- reload_when_needed[r],
- reload_mode[r]);
+ {
+ mark_reload_reg_in_use (regno, reload_opnum[r],
+ reload_when_needed[r],
+ reload_mode[r]);
+ SET_HARD_REG_BIT (reload_reg_used_for_inherit, regno);
+ }
}
}
optional and not inherited, clear reload_reg_rtx so other
routines (such as subst_reloads) don't get confused. */
for (j = 0; j < n_reloads; j++)
- if ((reload_optional[j] && ! reload_inherited[j])
- || (reload_in[j] == 0 && reload_out[j] == 0
- && ! reload_secondary_p[j]))
- reload_reg_rtx[j] = 0;
+ if (reload_reg_rtx[j] != 0
+ && ((reload_optional[j] && ! reload_inherited[j])
+ || (reload_in[j] == 0 && reload_out[j] == 0
+ && ! reload_secondary_p[j])))
+ {
+ int regno = true_regnum (reload_reg_rtx[j]);
+
+ if (spill_reg_order[regno] >= 0)
+ clear_reload_reg_in_use (regno, reload_opnum[j],
+ reload_when_needed[j], reload_mode[j]);
+ reload_reg_rtx[j] = 0;
+ }
/* Record which pseudos and which spill regs have output reloads. */
for (j = 0; j < n_reloads; j++)
&& 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
if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
{
register int nregno = REGNO (reload_out[r]);
+ int nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
+ : HARD_REGNO_NREGS (nregno,
+ GET_MODE (reload_reg_rtx[r])));
spill_reg_store[i] = new_spill_reg_store[i];
reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+ /* If NREGNO is a hard register, it may occupy more than
+ one register. If it does, say what is in the
+ rest of the registers assuming that both registers
+ agree on how many words the object takes. If not,
+ invalidate the subsequent registers. */
+
+ if (nregno < FIRST_PSEUDO_REGISTER)
+ for (k = 1; k < nnr; k++)
+ reg_last_reload_reg[nregno + k]
+ = (nr == nnr ? gen_rtx (REG, word_mode,
+ REGNO (reload_reg_rtx[r]) + k)
+ : 0);
+
+ /* Now do the inverse operation. */
for (k = 0; k < nr; k++)
{
reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
- = nregno;
+ = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr ? nregno
+ : nregno + k);
reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = insn;
}
}
- /* Maybe the spill reg contains a copy of reload_in. */
+ /* Maybe the spill reg contains a copy of reload_in. Only do
+ something if there will not be an output reload for
+ the register being reloaded. */
else if (reload_out[r] == 0
&& reload_in[r] != 0
- && (GET_CODE (reload_in[r]) == REG
- || GET_CODE (reload_in_reg[r]) == REG))
+ && ((GET_CODE (reload_in[r]) == REG
+ && ! reg_has_output_reload[REGNO (reload_in[r])]
+ || (GET_CODE (reload_in_reg[r]) == REG
+ && ! reg_has_output_reload[REGNO (reload_in_reg[r])]))))
{
register int nregno;
+ int nnr;
+
if (GET_CODE (reload_in[r]) == REG)
nregno = REGNO (reload_in[r]);
else
nregno = REGNO (reload_in_reg[r]);
+ nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
+ : HARD_REGNO_NREGS (nregno,
+ GET_MODE (reload_reg_rtx[r])));
+
reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+ if (nregno < FIRST_PSEUDO_REGISTER)
+ for (k = 1; k < nnr; k++)
+ reg_last_reload_reg[nregno + k]
+ = (nr == nnr ? gen_rtx (REG, word_mode,
+ REGNO (reload_reg_rtx[r]) + k)
+ : 0);
+
/* Unless we inherited this reload, show we haven't
recently done a store. */
if (! reload_inherited[r])
for (k = 0; k < nr; k++)
{
reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
- = nregno;
+ = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr ? nregno
+ : nregno + k);
reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]]
= insn;
}
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])