Commit 367b1cf5 by Bernd Schmidt Committed by Bernd Schmidt

Break up emit_reload_insns.

From-SVN: r31052
parent ca098a1d
1999-12-21 Bernd Schmidt <bernds@cygnus.co.uk>
* reload1.c (emit_reload_insns): Break out code and variables into...
(input_reload_insns, other_input_address_reload_insns,
other_input_reload_insns, input_address_reload_insns,
inpaddr_address_reload_insns, output_reload_insns,
output_address_reload_insns, outaddr_address_reload_insns,
operand_reload_insns, other_operand_reload_insns,
other_output_reload_insns): ... new static variables, and...
(emit_input_reload_insns, emit_output_reload_insns, do_input_reload,
do_output_reload): ... new functions.
Tue Dec 21 07:06:36 1999 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* pa.h (FUNCTION_ARG_BOUNDARY): Never return 0.
......
......@@ -414,6 +414,14 @@ static int set_reload_reg PROTO((int, int));
static void choose_reload_regs_init PROTO((struct insn_chain *, rtx *));
static void choose_reload_regs PROTO((struct insn_chain *));
static void merge_assigned_reloads PROTO((rtx));
static void emit_input_reload_insns PROTO((struct insn_chain *,
struct reload *, rtx, int));
static void emit_output_reload_insns PROTO((struct insn_chain *,
struct reload *, int));
static void do_input_reload PROTO((struct insn_chain *,
struct reload *, int));
static void do_output_reload PROTO((struct insn_chain *,
struct reload *, int));
static void emit_reload_insns PROTO((struct insn_chain *));
static void delete_output_reload PROTO((rtx, int, int));
static void delete_address_reloads PROTO((rtx, rtx));
......@@ -5834,867 +5842,891 @@ merge_assigned_reloads (insn)
}
/* Output insns to reload values in and out of the chosen reload regs. */
/* These arrays are filled by emit_reload_insns and its subroutines. */
static rtx input_reload_insns[MAX_RECOG_OPERANDS];
static rtx other_input_address_reload_insns = 0;
static rtx other_input_reload_insns = 0;
static rtx input_address_reload_insns[MAX_RECOG_OPERANDS];
static rtx inpaddr_address_reload_insns[MAX_RECOG_OPERANDS];
static rtx output_reload_insns[MAX_RECOG_OPERANDS];
static rtx output_address_reload_insns[MAX_RECOG_OPERANDS];
static rtx outaddr_address_reload_insns[MAX_RECOG_OPERANDS];
static rtx operand_reload_insns = 0;
static rtx other_operand_reload_insns = 0;
static rtx other_output_reload_insns[MAX_RECOG_OPERANDS];
/* Values to be put in spill_reg_store are put here first. */
static rtx new_spill_reg_store[FIRST_PSEUDO_REGISTER];
static HARD_REG_SET reg_reloaded_died;
/* Generate insns to perform reload RL, which is for the insn in CHAIN and
has the number J. OLD contains the value to be used as input. */
static void
emit_reload_insns (chain)
emit_input_reload_insns (chain, rl, old, j)
struct insn_chain *chain;
struct reload *rl;
rtx old;
int j;
{
rtx insn = chain->insn;
register rtx reloadreg = rl->reg_rtx;
rtx oldequiv_reg = 0;
rtx oldequiv = 0;
int special = 0;
enum machine_mode mode;
rtx *where;
/* Determine the mode to reload in.
This is very tricky because we have three to choose from.
There is the mode the insn operand wants (rl->inmode).
There is the mode of the reload register RELOADREG.
There is the intrinsic mode of the operand, which we could find
by stripping some SUBREGs.
It turns out that RELOADREG's mode is irrelevant:
we can change that arbitrarily.
Consider (SUBREG:SI foo:QI) as an operand that must be SImode;
then the reload reg may not support QImode moves, so use SImode.
If foo is in memory due to spilling a pseudo reg, this is safe,
because the QImode value is in the least significant part of a
slot big enough for a SImode. If foo is some other sort of
memory reference, then it is impossible to reload this case,
so previous passes had better make sure this never happens.
Then consider a one-word union which has SImode and one of its
members is a float, being fetched as (SUBREG:SF union:SI).
We must fetch that as SFmode because we could be loading into
a float-only register. In this case OLD's mode is correct.
Consider an immediate integer: it has VOIDmode. Here we need
to get a mode from something else.
In some cases, there is a fourth mode, the operand's
containing mode. If the insn specifies a containing mode for
this operand, it overrides all others.
I am not sure whether the algorithm here is always right,
but it does the right things in those cases. */
mode = GET_MODE (old);
if (mode == VOIDmode)
mode = rl->inmode;
register int j;
rtx input_reload_insns[MAX_RECOG_OPERANDS];
rtx other_input_address_reload_insns = 0;
rtx other_input_reload_insns = 0;
rtx input_address_reload_insns[MAX_RECOG_OPERANDS];
rtx inpaddr_address_reload_insns[MAX_RECOG_OPERANDS];
rtx output_reload_insns[MAX_RECOG_OPERANDS];
rtx output_address_reload_insns[MAX_RECOG_OPERANDS];
rtx outaddr_address_reload_insns[MAX_RECOG_OPERANDS];
rtx operand_reload_insns = 0;
rtx other_operand_reload_insns = 0;
rtx other_output_reload_insns[MAX_RECOG_OPERANDS];
rtx following_insn = NEXT_INSN (insn);
rtx before_insn = PREV_INSN (insn);
int special;
/* Values to be put in spill_reg_store are put here first. */
rtx new_spill_reg_store[FIRST_PSEUDO_REGISTER];
HARD_REG_SET reg_reloaded_died;
#ifdef SECONDARY_INPUT_RELOAD_CLASS
/* If we need a secondary register for this operation, see if
the value is already in a register in that class. Don't
do this if the secondary register will be used as a scratch
register. */
if (rl->secondary_in_reload >= 0
&& rl->secondary_in_icode == CODE_FOR_nothing
&& optimize)
oldequiv
= find_equiv_reg (old, insn,
rld[rl->secondary_in_reload].class,
-1, NULL_PTR, 0, mode);
#endif
CLEAR_HARD_REG_SET (reg_reloaded_died);
/* If reloading from memory, see if there is a register
that already holds the same value. If so, reload from there.
We can pass 0 as the reload_reg_p argument because
any other reload has either already been emitted,
in which case find_equiv_reg will see the reload-insn,
or has yet to be emitted, in which case it doesn't matter
because we will use this equiv reg right away. */
if (oldequiv == 0 && optimize
&& (GET_CODE (old) == MEM
|| (GET_CODE (old) == REG
&& REGNO (old) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (old)] < 0)))
oldequiv = find_equiv_reg (old, insn, ALL_REGS,
-1, NULL_PTR, 0, mode);
if (oldequiv)
{
int regno = true_regnum (oldequiv);
/* Don't use OLDEQUIV if any other reload changes it at an
earlier stage of this insn or at this stage. */
if (! reload_reg_free_for_value_p (regno, rl->opnum,
rl->when_needed,
rl->in, const0_rtx, j,
0))
oldequiv = 0;
/* If it is no cheaper to copy from OLDEQUIV into the
reload register than it would be to move from memory,
don't use it. Likewise, if we need a secondary register
or memory. */
if (oldequiv != 0
&& ((REGNO_REG_CLASS (regno) != rl->class
&& (REGISTER_MOVE_COST (REGNO_REG_CLASS (regno),
rl->class)
>= MEMORY_MOVE_COST (mode, rl->class, 1)))
#ifdef SECONDARY_INPUT_RELOAD_CLASS
|| (SECONDARY_INPUT_RELOAD_CLASS (rl->class,
mode, oldequiv)
!= NO_REGS)
#endif
#ifdef SECONDARY_MEMORY_NEEDED
|| SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (regno),
rl->class,
mode)
#endif
))
oldequiv = 0;
}
for (j = 0; j < reload_n_operands; j++)
input_reload_insns[j] = input_address_reload_insns[j]
= inpaddr_address_reload_insns[j]
= output_reload_insns[j] = output_address_reload_insns[j]
= outaddr_address_reload_insns[j]
= other_output_reload_insns[j] = 0;
/* delete_output_reload is only invoked properly if old contains
the original pseudo register. Since this is replaced with a
hard reg when RELOAD_OVERRIDE_IN is set, see if we can
find the pseudo in RELOAD_IN_REG. */
if (oldequiv == 0
&& reload_override_in[j]
&& GET_CODE (rl->in_reg) == REG)
{
oldequiv = old;
old = rl->in_reg;
}
if (oldequiv == 0)
oldequiv = old;
else if (GET_CODE (oldequiv) == REG)
oldequiv_reg = oldequiv;
else if (GET_CODE (oldequiv) == SUBREG)
oldequiv_reg = SUBREG_REG (oldequiv);
/* If we are reloading from a register that was recently stored in
with an output-reload, see if we can prove there was
actually no need to store the old value in it. */
if (optimize && GET_CODE (oldequiv) == REG
&& REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
&& spill_reg_store[REGNO (oldequiv)]
&& GET_CODE (old) == REG
&& (dead_or_set_p (insn, spill_reg_stored_to[REGNO (oldequiv)])
|| rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
rl->out_reg)))
delete_output_reload (insn, j, REGNO (oldequiv));
/* Encapsulate both RELOADREG and OLDEQUIV into that mode,
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_rtx_REG (mode, REGNO (reloadreg));
while (GET_CODE (oldequiv) == SUBREG && GET_MODE (oldequiv) != mode)
oldequiv = SUBREG_REG (oldequiv);
if (GET_MODE (oldequiv) != VOIDmode
&& mode != GET_MODE (oldequiv))
oldequiv = gen_rtx_SUBREG (mode, oldequiv, 0);
/* Switch to the right place to emit the reload insns. */
switch (rl->when_needed)
{
case RELOAD_OTHER:
where = &other_input_reload_insns;
break;
case RELOAD_FOR_INPUT:
where = &input_reload_insns[rl->opnum];
break;
case RELOAD_FOR_INPUT_ADDRESS:
where = &input_address_reload_insns[rl->opnum];
break;
case RELOAD_FOR_INPADDR_ADDRESS:
where = &inpaddr_address_reload_insns[rl->opnum];
break;
case RELOAD_FOR_OUTPUT_ADDRESS:
where = &output_address_reload_insns[rl->opnum];
break;
case RELOAD_FOR_OUTADDR_ADDRESS:
where = &outaddr_address_reload_insns[rl->opnum];
break;
case RELOAD_FOR_OPERAND_ADDRESS:
where = &operand_reload_insns;
break;
case RELOAD_FOR_OPADDR_ADDR:
where = &other_operand_reload_insns;
break;
case RELOAD_FOR_OTHER_ADDRESS:
where = &other_input_address_reload_insns;
break;
default:
abort ();
}
/* Now output the instructions to copy the data into and out of the
reload registers. Do these in the order that the reloads were reported,
since reloads of base and index registers precede reloads of operands
and the operands may need the base and index registers reloaded. */
push_to_sequence (*where);
for (j = 0; j < n_reloads; j++)
/* Auto-increment addresses must be reloaded in a special way. */
if (rl->out && ! rl->out_reg)
{
register rtx old;
rtx oldequiv_reg = 0;
rtx this_reload_insn = 0;
int expect_occurrences = 1;
if (rld[j].reg_rtx
&& REGNO (rld[j].reg_rtx) < FIRST_PSEUDO_REGISTER)
new_spill_reg_store[REGNO (rld[j].reg_rtx)] = 0;
/* We are not going to bother supporting the case where a
incremented register can't be copied directly from
OLDEQUIV since this seems highly unlikely. */
if (rl->secondary_in_reload >= 0)
abort ();
old = (rld[j].in && GET_CODE (rld[j].in) == MEM
? rld[j].in_reg : rld[j].in);
if (reload_inherited[j])
oldequiv = reloadreg;
if (old != 0
/* AUTO_INC reloads need to be handled even if inherited. We got an
AUTO_INC reload if reload_out is set but reload_out_reg isn't. */
&& (! reload_inherited[j] || (rld[j].out && ! rld[j].out_reg))
&& ! rtx_equal_p (rld[j].reg_rtx, old)
&& rld[j].reg_rtx != 0)
{
register rtx reloadreg = rld[j].reg_rtx;
rtx oldequiv = 0;
enum machine_mode mode;
rtx *where;
/* Determine the mode to reload in.
This is very tricky because we have three to choose from.
There is the mode the insn operand wants (rld[J].inmode).
There is the mode of the reload register RELOADREG.
There is the intrinsic mode of the operand, which we could find
by stripping some SUBREGs.
It turns out that RELOADREG's mode is irrelevant:
we can change that arbitrarily.
Consider (SUBREG:SI foo:QI) as an operand that must be SImode;
then the reload reg may not support QImode moves, so use SImode.
If foo is in memory due to spilling a pseudo reg, this is safe,
because the QImode value is in the least significant part of a
slot big enough for a SImode. If foo is some other sort of
memory reference, then it is impossible to reload this case,
so previous passes had better make sure this never happens.
Then consider a one-word union which has SImode and one of its
members is a float, being fetched as (SUBREG:SF union:SI).
We must fetch that as SFmode because we could be loading into
a float-only register. In this case OLD's mode is correct.
Consider an immediate integer: it has VOIDmode. Here we need
to get a mode from something else.
In some cases, there is a fourth mode, the operand's
containing mode. If the insn specifies a containing mode for
this operand, it overrides all others.
I am not sure whether the algorithm here is always right,
but it does the right things in those cases. */
mode = GET_MODE (old);
if (mode == VOIDmode)
mode = rld[j].inmode;
old = XEXP (rl->in_reg, 0);
#ifdef SECONDARY_INPUT_RELOAD_CLASS
/* If we need a secondary register for this operation, see if
the value is already in a register in that class. Don't
do this if the secondary register will be used as a scratch
register. */
if (rld[j].secondary_in_reload >= 0
&& rld[j].secondary_in_icode == CODE_FOR_nothing
&& optimize)
oldequiv
= find_equiv_reg (old, insn,
rld[rld[j].secondary_in_reload].class,
-1, NULL_PTR, 0, mode);
#endif
if (optimize && GET_CODE (oldequiv) == REG
&& REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
&& spill_reg_store[REGNO (oldequiv)]
&& GET_CODE (old) == REG
&& (dead_or_set_p (insn,
spill_reg_stored_to[REGNO (oldequiv)])
|| rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
old)))
delete_output_reload (insn, j, REGNO (oldequiv));
/* Prevent normal processing of this reload. */
special = 1;
/* Output a special code sequence for this case. */
new_spill_reg_store[REGNO (reloadreg)]
= inc_for_reload (reloadreg, oldequiv, rl->out,
rl->inc);
}
/* If reloading from memory, see if there is a register
that already holds the same value. If so, reload from there.
We can pass 0 as the reload_reg_p argument because
any other reload has either already been emitted,
in which case find_equiv_reg will see the reload-insn,
or has yet to be emitted, in which case it doesn't matter
because we will use this equiv reg right away. */
if (oldequiv == 0 && optimize
&& (GET_CODE (old) == MEM
|| (GET_CODE (old) == REG
&& REGNO (old) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (old)] < 0)))
oldequiv = find_equiv_reg (old, insn, ALL_REGS,
-1, NULL_PTR, 0, mode);
if (oldequiv)
/* If we are reloading a pseudo-register that was set by the previous
insn, see if we can get rid of that pseudo-register entirely
by redirecting the previous insn into our reload register. */
else if (optimize && GET_CODE (old) == REG
&& REGNO (old) >= FIRST_PSEUDO_REGISTER
&& dead_or_set_p (insn, old)
/* This is unsafe if some other reload
uses the same reg first. */
&& reload_reg_free_for_value_p (REGNO (reloadreg),
rl->opnum,
rl->when_needed,
old, rl->out,
j, 0))
{
rtx temp = PREV_INSN (insn);
while (temp && GET_CODE (temp) == NOTE)
temp = PREV_INSN (temp);
if (temp
&& GET_CODE (temp) == INSN
&& GET_CODE (PATTERN (temp)) == SET
&& SET_DEST (PATTERN (temp)) == old
/* Make sure we can access insn_operand_constraint. */
&& asm_noperands (PATTERN (temp)) < 0
/* This is unsafe if prev insn rejects our reload reg. */
&& constraint_accepts_reg_p (insn_data[recog_memoized (temp)].operand[0].constraint,
reloadreg)
/* This is unsafe if operand occurs more than once in current
insn. Perhaps some occurrences aren't reloaded. */
&& count_occurrences (PATTERN (insn), old) == 1
/* Don't risk splitting a matching pair of operands. */
&& ! reg_mentioned_p (old, SET_SRC (PATTERN (temp))))
{
/* Store into the reload register instead of the pseudo. */
SET_DEST (PATTERN (temp)) = reloadreg;
/* If the previous insn is an output reload, the source is
a reload register, and its spill_reg_store entry will
contain the previous destination. This is now
invalid. */
if (GET_CODE (SET_SRC (PATTERN (temp))) == REG
&& REGNO (SET_SRC (PATTERN (temp))) < FIRST_PSEUDO_REGISTER)
{
int regno = true_regnum (oldequiv);
/* Don't use OLDEQUIV if any other reload changes it at an
earlier stage of this insn or at this stage. */
if (! reload_reg_free_for_value_p (regno, rld[j].opnum,
rld[j].when_needed,
rld[j].in, const0_rtx, j,
0))
oldequiv = 0;
/* If it is no cheaper to copy from OLDEQUIV into the
reload register than it would be to move from memory,
don't use it. Likewise, if we need a secondary register
or memory. */
if (oldequiv != 0
&& ((REGNO_REG_CLASS (regno) != rld[j].class
&& (REGISTER_MOVE_COST (REGNO_REG_CLASS (regno),
rld[j].class)
>= MEMORY_MOVE_COST (mode, rld[j].class, 1)))
#ifdef SECONDARY_INPUT_RELOAD_CLASS
|| (SECONDARY_INPUT_RELOAD_CLASS (rld[j].class,
mode, oldequiv)
!= NO_REGS)
#endif
#ifdef SECONDARY_MEMORY_NEEDED
|| SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (regno),
rld[j].class,
mode)
#endif
))
oldequiv = 0;
spill_reg_store[REGNO (SET_SRC (PATTERN (temp)))] = 0;
spill_reg_stored_to[REGNO (SET_SRC (PATTERN (temp)))] = 0;
}
/* delete_output_reload is only invoked properly if old contains
the original pseudo register. Since this is replaced with a
hard reg when RELOAD_OVERRIDE_IN is set, see if we can
find the pseudo in RELOAD_IN_REG. */
if (oldequiv == 0
&& reload_override_in[j]
&& GET_CODE (rld[j].in_reg) == REG)
/* If these are the only uses of the pseudo reg,
pretend for GDB it lives in the reload reg we used. */
if (REG_N_DEATHS (REGNO (old)) == 1
&& REG_N_SETS (REGNO (old)) == 1)
{
oldequiv = old;
old = rld[j].in_reg;
}
if (oldequiv == 0)
oldequiv = old;
else if (GET_CODE (oldequiv) == REG)
oldequiv_reg = oldequiv;
else if (GET_CODE (oldequiv) == SUBREG)
oldequiv_reg = SUBREG_REG (oldequiv);
/* If we are reloading from a register that was recently stored in
with an output-reload, see if we can prove there was
actually no need to store the old value in it. */
if (optimize && GET_CODE (oldequiv) == REG
&& REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
&& spill_reg_store[REGNO (oldequiv)]
&& GET_CODE (old) == REG
&& (dead_or_set_p (insn, spill_reg_stored_to[REGNO (oldequiv)])
|| rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
rld[j].out_reg)))
delete_output_reload (insn, j, REGNO (oldequiv));
/* Encapsulate both RELOADREG and OLDEQUIV into that mode,
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_rtx_REG (mode, REGNO (reloadreg));
while (GET_CODE (oldequiv) == SUBREG && GET_MODE (oldequiv) != mode)
oldequiv = SUBREG_REG (oldequiv);
if (GET_MODE (oldequiv) != VOIDmode
&& mode != GET_MODE (oldequiv))
oldequiv = gen_rtx_SUBREG (mode, oldequiv, 0);
/* Switch to the right place to emit the reload insns. */
switch (rld[j].when_needed)
{
case RELOAD_OTHER:
where = &other_input_reload_insns;
break;
case RELOAD_FOR_INPUT:
where = &input_reload_insns[rld[j].opnum];
break;
case RELOAD_FOR_INPUT_ADDRESS:
where = &input_address_reload_insns[rld[j].opnum];
break;
case RELOAD_FOR_INPADDR_ADDRESS:
where = &inpaddr_address_reload_insns[rld[j].opnum];
break;
case RELOAD_FOR_OUTPUT_ADDRESS:
where = &output_address_reload_insns[rld[j].opnum];
break;
case RELOAD_FOR_OUTADDR_ADDRESS:
where = &outaddr_address_reload_insns[rld[j].opnum];
break;
case RELOAD_FOR_OPERAND_ADDRESS:
where = &operand_reload_insns;
break;
case RELOAD_FOR_OPADDR_ADDR:
where = &other_operand_reload_insns;
break;
case RELOAD_FOR_OTHER_ADDRESS:
where = &other_input_address_reload_insns;
break;
default:
abort ();
reg_renumber[REGNO (old)] = REGNO (rl->reg_rtx);
alter_reg (REGNO (old), -1);
}
return;
}
}
push_to_sequence (*where);
special = 0;
/* We can't do that, so output an insn to load RELOADREG. */
/* Auto-increment addresses must be reloaded in a special way. */
if (rld[j].out && ! rld[j].out_reg)
{
/* We are not going to bother supporting the case where a
incremented register can't be copied directly from
OLDEQUIV since this seems highly unlikely. */
if (rld[j].secondary_in_reload >= 0)
abort ();
if (reload_inherited[j])
oldequiv = reloadreg;
old = XEXP (rld[j].in_reg, 0);
if (optimize && GET_CODE (oldequiv) == REG
&& REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
&& spill_reg_store[REGNO (oldequiv)]
&& GET_CODE (old) == REG
&& (dead_or_set_p (insn,
spill_reg_stored_to[REGNO (oldequiv)])
|| rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
old)))
delete_output_reload (insn, j, REGNO (oldequiv));
/* Prevent normal processing of this reload. */
special = 1;
/* Output a special code sequence for this case. */
new_spill_reg_store[REGNO (reloadreg)]
= inc_for_reload (reloadreg, oldequiv, rld[j].out,
rld[j].inc);
}
#ifdef SECONDARY_INPUT_RELOAD_CLASS
/* If we have a secondary reload, pick up the secondary register
and icode, if any. If OLDEQUIV and OLD are different or
if this is an in-out reload, recompute whether or not we
still need a secondary register and what the icode should
be. If we still need a secondary register and the class or
icode is different, go back to reloading from OLD if using
OLDEQUIV means that we got the wrong type of register. We
cannot have different class or icode due to an in-out reload
because we don't make such reloads when both the input and
output need secondary reload registers. */
if (rl->secondary_in_reload >= 0)
{
rtx second_reload_reg = 0;
int secondary_reload = rl->secondary_in_reload;
rtx real_oldequiv = oldequiv;
rtx real_old = old;
rtx tmp;
enum insn_code icode;
/* If OLDEQUIV is a pseudo with a MEM, get the real MEM
and similarly for OLD.
See comments in get_secondary_reload in reload.c. */
/* If it is a pseudo that cannot be replaced with its
equivalent MEM, we must fall back to reload_in, which
will have all the necessary substitutions registered.
Likewise for a pseudo that can't be replaced with its
equivalent constant.
Take extra care for subregs of such pseudos. Note that
we cannot use reg_equiv_mem in this case because it is
not in the right mode. */
tmp = oldequiv;
if (GET_CODE (tmp) == SUBREG)
tmp = SUBREG_REG (tmp);
if (GET_CODE (tmp) == REG
&& REGNO (tmp) >= FIRST_PSEUDO_REGISTER
&& (reg_equiv_memory_loc[REGNO (tmp)] != 0
|| reg_equiv_constant[REGNO (tmp)] != 0))
{
if (! reg_equiv_mem[REGNO (tmp)]
|| num_not_at_initial_offset
|| GET_CODE (oldequiv) == SUBREG)
real_oldequiv = rl->in;
else
real_oldequiv = reg_equiv_mem[REGNO (tmp)];
}
tmp = old;
if (GET_CODE (tmp) == SUBREG)
tmp = SUBREG_REG (tmp);
if (GET_CODE (tmp) == REG
&& REGNO (tmp) >= FIRST_PSEUDO_REGISTER
&& (reg_equiv_memory_loc[REGNO (tmp)] != 0
|| reg_equiv_constant[REGNO (tmp)] != 0))
{
if (! reg_equiv_mem[REGNO (tmp)]
|| num_not_at_initial_offset
|| GET_CODE (old) == SUBREG)
real_old = rl->in;
else
real_old = reg_equiv_mem[REGNO (tmp)];
}
second_reload_reg = rld[secondary_reload].reg_rtx;
icode = rl->secondary_in_icode;
if ((old != oldequiv && ! rtx_equal_p (old, oldequiv))
|| (rl->in != 0 && rl->out != 0))
{
enum reg_class new_class
= SECONDARY_INPUT_RELOAD_CLASS (rl->class,
mode, real_oldequiv);
/* If we are reloading a pseudo-register that was set by the previous
insn, see if we can get rid of that pseudo-register entirely
by redirecting the previous insn into our reload register. */
else if (optimize && GET_CODE (old) == REG
&& REGNO (old) >= FIRST_PSEUDO_REGISTER
&& dead_or_set_p (insn, old)
/* This is unsafe if some other reload
uses the same reg first. */
&& reload_reg_free_for_value_p (REGNO (reloadreg),
rld[j].opnum,
rld[j].when_needed,
old, rld[j].out,
j, 0))
if (new_class == NO_REGS)
second_reload_reg = 0;
else
{
rtx temp = PREV_INSN (insn);
while (temp && GET_CODE (temp) == NOTE)
temp = PREV_INSN (temp);
if (temp
&& GET_CODE (temp) == INSN
&& GET_CODE (PATTERN (temp)) == SET
&& SET_DEST (PATTERN (temp)) == old
/* Make sure we can access insn_operand_constraint. */
&& asm_noperands (PATTERN (temp)) < 0
/* This is unsafe if prev insn rejects our reload reg. */
&& constraint_accepts_reg_p (insn_data[recog_memoized (temp)].operand[0].constraint,
reloadreg)
/* This is unsafe if operand occurs more than once in current
insn. Perhaps some occurrences aren't reloaded. */
&& count_occurrences (PATTERN (insn), old) == 1
/* Don't risk splitting a matching pair of operands. */
&& ! reg_mentioned_p (old, SET_SRC (PATTERN (temp))))
enum insn_code new_icode;
enum machine_mode new_mode;
if (! TEST_HARD_REG_BIT (reg_class_contents[(int) new_class],
REGNO (second_reload_reg)))
oldequiv = old, real_oldequiv = real_old;
else
{
/* Store into the reload register instead of the pseudo. */
SET_DEST (PATTERN (temp)) = reloadreg;
/* If the previous insn is an output reload, the source is
a reload register, and its spill_reg_store entry will
contain the previous destination. This is now
invalid. */
if (GET_CODE (SET_SRC (PATTERN (temp))) == REG
&& REGNO (SET_SRC (PATTERN (temp))) < FIRST_PSEUDO_REGISTER)
{
spill_reg_store[REGNO (SET_SRC (PATTERN (temp)))] = 0;
spill_reg_stored_to[REGNO (SET_SRC (PATTERN (temp)))] = 0;
}
new_icode = reload_in_optab[(int) mode];
if (new_icode != CODE_FOR_nothing
&& ((insn_data[(int) new_icode].operand[0].predicate
&& ! ((*insn_data[(int) new_icode].operand[0].predicate)
(reloadreg, mode)))
|| (insn_data[(int) new_icode].operand[1].predicate
&& ! ((*insn_data[(int) new_icode].operand[1].predicate)
(real_oldequiv, mode)))))
new_icode = CODE_FOR_nothing;
if (new_icode == CODE_FOR_nothing)
new_mode = mode;
else
new_mode = insn_data[(int) new_icode].operand[2].mode;
/* If these are the only uses of the pseudo reg,
pretend for GDB it lives in the reload reg we used. */
if (REG_N_DEATHS (REGNO (old)) == 1
&& REG_N_SETS (REGNO (old)) == 1)
if (GET_MODE (second_reload_reg) != new_mode)
{
reg_renumber[REGNO (old)] = REGNO (rld[j].reg_rtx);
alter_reg (REGNO (old), -1);
if (!HARD_REGNO_MODE_OK (REGNO (second_reload_reg),
new_mode))
oldequiv = old, real_oldequiv = real_old;
else
second_reload_reg
= gen_rtx_REG (new_mode,
REGNO (second_reload_reg));
}
special = 1;
}
}
}
/* We can't do that, so output an insn to load RELOADREG. */
/* If we still need a secondary reload register, check
to see if it is being used as a scratch or intermediate
register and generate code appropriately. If we need
a scratch register, use REAL_OLDEQUIV since the form of
the insn may depend on the actual address if it is
a MEM. */
if (! special)
if (second_reload_reg)
{
if (icode != CODE_FOR_nothing)
{
#ifdef SECONDARY_INPUT_RELOAD_CLASS
rtx second_reload_reg = 0;
enum insn_code icode;
/* If we have a secondary reload, pick up the secondary register
and icode, if any. If OLDEQUIV and OLD are different or
if this is an in-out reload, recompute whether or not we
still need a secondary register and what the icode should
be. If we still need a secondary register and the class or
icode is different, go back to reloading from OLD if using
OLDEQUIV means that we got the wrong type of register. We
cannot have different class or icode due to an in-out reload
because we don't make such reloads when both the input and
output need secondary reload registers. */
if (rld[j].secondary_in_reload >= 0)
{
int secondary_reload = rld[j].secondary_in_reload;
rtx real_oldequiv = oldequiv;
rtx real_old = old;
rtx tmp;
/* If OLDEQUIV is a pseudo with a MEM, get the real MEM
and similarly for OLD.
See comments in get_secondary_reload in reload.c. */
/* If it is a pseudo that cannot be replaced with its
equivalent MEM, we must fall back to reload_in, which
will have all the necessary substitutions registered.
Likewise for a pseudo that can't be replaced with its
equivalent constant.
Take extra care for subregs of such pseudos. Note that
we cannot use reg_equiv_mem in this case because it is
not in the right mode. */
tmp = oldequiv;
if (GET_CODE (tmp) == SUBREG)
tmp = SUBREG_REG (tmp);
if (GET_CODE (tmp) == REG
&& REGNO (tmp) >= FIRST_PSEUDO_REGISTER
&& (reg_equiv_memory_loc[REGNO (tmp)] != 0
|| reg_equiv_constant[REGNO (tmp)] != 0))
{
if (! reg_equiv_mem[REGNO (tmp)]
|| num_not_at_initial_offset
|| GET_CODE (oldequiv) == SUBREG)
real_oldequiv = rld[j].in;
else
real_oldequiv = reg_equiv_mem[REGNO (tmp)];
}
emit_insn (GEN_FCN (icode) (reloadreg, real_oldequiv,
second_reload_reg));
return;
}
else
{
/* See if we need a scratch register to load the
intermediate register (a tertiary reload). */
enum insn_code tertiary_icode
= rld[secondary_reload].secondary_in_icode;
tmp = old;
if (GET_CODE (tmp) == SUBREG)
tmp = SUBREG_REG (tmp);
if (GET_CODE (tmp) == REG
&& REGNO (tmp) >= FIRST_PSEUDO_REGISTER
&& (reg_equiv_memory_loc[REGNO (tmp)] != 0
|| reg_equiv_constant[REGNO (tmp)] != 0))
{
if (! reg_equiv_mem[REGNO (tmp)]
|| num_not_at_initial_offset
|| GET_CODE (old) == SUBREG)
real_old = rld[j].in;
else
real_old = reg_equiv_mem[REGNO (tmp)];
}
if (tertiary_icode != CODE_FOR_nothing)
{
rtx third_reload_reg
= rld[rld[secondary_reload].secondary_in_reload].reg_rtx;
second_reload_reg = rld[secondary_reload].reg_rtx;
icode = rld[j].secondary_in_icode;
emit_insn ((GEN_FCN (tertiary_icode)
(second_reload_reg, real_oldequiv,
third_reload_reg)));
}
else
gen_reload (second_reload_reg, real_oldequiv,
rl->opnum,
rl->when_needed);
if ((old != oldequiv && ! rtx_equal_p (old, oldequiv))
|| (rld[j].in != 0 && rld[j].out != 0))
{
enum reg_class new_class
= SECONDARY_INPUT_RELOAD_CLASS (rld[j].class,
mode, real_oldequiv);
oldequiv = second_reload_reg;
}
}
}
#endif
if (new_class == NO_REGS)
second_reload_reg = 0;
else
{
enum insn_code new_icode;
enum machine_mode new_mode;
if (! rtx_equal_p (reloadreg, oldequiv))
{
rtx real_oldequiv = oldequiv;
if ((GET_CODE (oldequiv) == REG
&& REGNO (oldequiv) >= FIRST_PSEUDO_REGISTER
&& (reg_equiv_memory_loc[REGNO (oldequiv)] != 0
|| reg_equiv_constant[REGNO (oldequiv)] != 0))
|| (GET_CODE (oldequiv) == SUBREG
&& GET_CODE (SUBREG_REG (oldequiv)) == REG
&& (REGNO (SUBREG_REG (oldequiv))
>= FIRST_PSEUDO_REGISTER)
&& ((reg_equiv_memory_loc
[REGNO (SUBREG_REG (oldequiv))] != 0)
|| (reg_equiv_constant
[REGNO (SUBREG_REG (oldequiv))] != 0))))
real_oldequiv = rl->in;
gen_reload (reloadreg, real_oldequiv, rl->opnum,
rl->when_needed);
}
if (! TEST_HARD_REG_BIT (reg_class_contents[(int) new_class],
REGNO (second_reload_reg)))
oldequiv = old, real_oldequiv = real_old;
else
{
new_icode = reload_in_optab[(int) mode];
if (new_icode != CODE_FOR_nothing
&& ((insn_data[(int) new_icode].operand[0].predicate
&& ! ((*insn_data[(int) new_icode].operand[0].predicate)
(reloadreg, mode)))
|| (insn_data[(int) new_icode].operand[1].predicate
&& ! ((*insn_data[(int) new_icode].operand[1].predicate)
(real_oldequiv, mode)))))
new_icode = CODE_FOR_nothing;
if (new_icode == CODE_FOR_nothing)
new_mode = mode;
else
new_mode = insn_data[(int) new_icode].operand[2].mode;
/* End this sequence. */
*where = get_insns ();
end_sequence ();
if (GET_MODE (second_reload_reg) != new_mode)
{
if (!HARD_REGNO_MODE_OK (REGNO (second_reload_reg),
new_mode))
oldequiv = old, real_oldequiv = real_old;
else
second_reload_reg
= gen_rtx_REG (new_mode,
REGNO (second_reload_reg));
}
}
}
}
/* Update reload_override_in so that delete_address_reloads_1
can see the actual register usage. */
if (oldequiv_reg)
reload_override_in[j] = oldequiv;
}
/* If we still need a secondary reload register, check
to see if it is being used as a scratch or intermediate
register and generate code appropriately. If we need
a scratch register, use REAL_OLDEQUIV since the form of
the insn may depend on the actual address if it is
a MEM. */
/* Generate insns to for the output reload RL, which is for the insn described
by CHAIN and has the number J. */
static void
emit_output_reload_insns (chain, rl, j)
struct insn_chain *chain;
struct reload *rl;
int j;
{
rtx reloadreg = rl->reg_rtx;
rtx insn = chain->insn;
int special = 0;
rtx old = rl->out;
enum machine_mode mode = GET_MODE (old);
rtx p;
if (second_reload_reg)
{
if (icode != CODE_FOR_nothing)
{
emit_insn (GEN_FCN (icode) (reloadreg, real_oldequiv,
second_reload_reg));
special = 1;
}
else
{
/* See if we need a scratch register to load the
intermediate register (a tertiary reload). */
enum insn_code tertiary_icode
= rld[secondary_reload].secondary_in_icode;
if (rl->when_needed == RELOAD_OTHER)
start_sequence ();
else
push_to_sequence (output_reload_insns[rl->opnum]);
if (tertiary_icode != CODE_FOR_nothing)
{
rtx third_reload_reg
= rld[rld[secondary_reload].secondary_in_reload].reg_rtx;
/* Determine the mode to reload in.
See comments above (for input reloading). */
emit_insn ((GEN_FCN (tertiary_icode)
(second_reload_reg, real_oldequiv,
third_reload_reg)));
}
else
gen_reload (second_reload_reg, real_oldequiv,
rld[j].opnum,
rld[j].when_needed);
if (mode == VOIDmode)
{
/* VOIDmode should never happen for an output. */
if (asm_noperands (PATTERN (insn)) < 0)
/* It's the compiler's fault. */
fatal_insn ("VOIDmode on an output", insn);
error_for_asm (insn, "output operand is constant in `asm'");
/* Prevent crash--use something we know is valid. */
mode = word_mode;
old = gen_rtx_REG (mode, REGNO (reloadreg));
}
oldequiv = second_reload_reg;
}
}
}
#endif
if (GET_MODE (reloadreg) != mode)
reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
if (! special && ! rtx_equal_p (reloadreg, oldequiv))
{
rtx real_oldequiv = oldequiv;
if ((GET_CODE (oldequiv) == REG
&& REGNO (oldequiv) >= FIRST_PSEUDO_REGISTER
&& (reg_equiv_memory_loc[REGNO (oldequiv)] != 0
|| reg_equiv_constant[REGNO (oldequiv)] != 0))
|| (GET_CODE (oldequiv) == SUBREG
&& GET_CODE (SUBREG_REG (oldequiv)) == REG
&& (REGNO (SUBREG_REG (oldequiv))
>= FIRST_PSEUDO_REGISTER)
&& ((reg_equiv_memory_loc
[REGNO (SUBREG_REG (oldequiv))] != 0)
|| (reg_equiv_constant
[REGNO (SUBREG_REG (oldequiv))] != 0))))
real_oldequiv = rld[j].in;
gen_reload (reloadreg, real_oldequiv, rld[j].opnum,
rld[j].when_needed);
}
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
}
/* If we need two reload regs, set RELOADREG to the intermediate
one, since it will be stored into OLD. We might need a secondary
register only for an input reload, so check again here. */
this_reload_insn = get_last_insn ();
/* End this sequence. */
*where = get_insns ();
end_sequence ();
if (rl->secondary_out_reload >= 0)
{
rtx real_old = old;
/* Update reload_override_in so that delete_address_reloads_1
can see the actual register usage. */
if (oldequiv_reg)
reload_override_in[j] = oldequiv;
}
if (GET_CODE (old) == REG && REGNO (old) >= FIRST_PSEUDO_REGISTER
&& reg_equiv_mem[REGNO (old)] != 0)
real_old = reg_equiv_mem[REGNO (old)];
/* When inheriting a wider reload, we have a MEM in rld[j].in,
e.g. inheriting a SImode output reload for
(mem:HI (plus:SI (reg:SI 14 fp) (const_int 10))) */
if (optimize && reload_inherited[j] && rld[j].in
&& GET_CODE (rld[j].in) == MEM
&& GET_CODE (rld[j].in_reg) == MEM
&& reload_spill_index[j] >= 0
&& TEST_HARD_REG_BIT (reg_reloaded_valid, reload_spill_index[j]))
if ((SECONDARY_OUTPUT_RELOAD_CLASS (rl->class,
mode, real_old)
!= NO_REGS))
{
expect_occurrences
= count_occurrences (PATTERN (insn), rld[j].in) == 1 ? 0 : -1;
rld[j].in
= regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]];
}
/* If we are reloading a register that was recently stored in with an
output-reload, see if we can prove there was
actually no need to store the old value in it. */
rtx second_reloadreg = reloadreg;
reloadreg = rld[rl->secondary_out_reload].reg_rtx;
if (optimize
&& (reload_inherited[j] || reload_override_in[j])
&& rld[j].reg_rtx
&& GET_CODE (rld[j].reg_rtx) == REG
&& spill_reg_store[REGNO (rld[j].reg_rtx)] != 0
#if 0
/* There doesn't seem to be any reason to restrict this to pseudos
and doing so loses in the case where we are copying from a
register of the wrong class. */
&& (REGNO (spill_reg_stored_to[REGNO (rld[j].reg_rtx)])
>= FIRST_PSEUDO_REGISTER)
#endif
/* The insn might have already some references to stackslots
replaced by MEMs, while reload_out_reg still names the
original pseudo. */
&& (dead_or_set_p (insn,
spill_reg_stored_to[REGNO (rld[j].reg_rtx)])
|| rtx_equal_p (spill_reg_stored_to[REGNO (rld[j].reg_rtx)],
rld[j].out_reg)))
delete_output_reload (insn, j, REGNO (rld[j].reg_rtx));
/* See if RELOADREG is to be used as a scratch register
or as an intermediate register. */
if (rl->secondary_out_icode != CODE_FOR_nothing)
{
emit_insn ((GEN_FCN (rl->secondary_out_icode)
(real_old, second_reloadreg, reloadreg)));
special = 1;
}
else
{
/* See if we need both a scratch and intermediate reload
register. */
/* Input-reloading is done. Now do output-reloading,
storing the value from the reload-register after the main insn
if rld[j].out is nonzero.
int secondary_reload = rl->secondary_out_reload;
enum insn_code tertiary_icode
= rld[secondary_reload].secondary_out_icode;
??? At some point we need to support handling output reloads of
JUMP_INSNs or insns that set cc0. */
if (GET_MODE (reloadreg) != mode)
reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
/* If this is an output reload that stores something that is
not loaded in this same reload, see if we can eliminate a previous
store. */
{
rtx pseudo = rld[j].out_reg;
if (tertiary_icode != CODE_FOR_nothing)
{
rtx third_reloadreg
= rld[rld[secondary_reload].secondary_out_reload].reg_rtx;
rtx tem;
/* Copy primary reload reg to secondary reload reg.
(Note that these have been swapped above, then
secondary reload reg to OLD using our insn. */
/* If REAL_OLD is a paradoxical SUBREG, remove it
and try to put the opposite SUBREG on
RELOADREG. */
if (GET_CODE (real_old) == SUBREG
&& (GET_MODE_SIZE (GET_MODE (real_old))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (real_old))))
&& 0 != (tem = gen_lowpart_common
(GET_MODE (SUBREG_REG (real_old)),
reloadreg)))
real_old = SUBREG_REG (real_old), reloadreg = tem;
gen_reload (reloadreg, second_reloadreg,
rl->opnum, rl->when_needed);
emit_insn ((GEN_FCN (tertiary_icode)
(real_old, reloadreg, third_reloadreg)));
special = 1;
}
if (pseudo
&& GET_CODE (pseudo) == REG
&& ! rtx_equal_p (rld[j].in_reg, pseudo)
&& REGNO (pseudo) >= FIRST_PSEUDO_REGISTER
&& reg_last_reload_reg[REGNO (pseudo)])
{
int pseudo_no = REGNO (pseudo);
int last_regno = REGNO (reg_last_reload_reg[pseudo_no]);
/* We don't need to test full validity of last_regno for
inherit here; we only want to know if the store actually
matches the pseudo. */
if (reg_reloaded_contents[last_regno] == pseudo_no
&& spill_reg_store[last_regno]
&& rtx_equal_p (pseudo, spill_reg_stored_to[last_regno]))
delete_output_reload (insn, j, last_regno);
}
}
else
/* Copy between the reload regs here and then to
OUT later. */
old = rld[j].out_reg;
if (old != 0
&& rld[j].reg_rtx != old
&& rld[j].reg_rtx != 0)
{
register rtx reloadreg = rld[j].reg_rtx;
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
register rtx second_reloadreg = 0;
#endif
rtx note, p;
enum machine_mode mode;
int special = 0;
/* An output operand that dies right away does need a reload,
but need not be copied from it. Show the new location in the
REG_UNUSED note. */
if ((GET_CODE (old) == REG || GET_CODE (old) == SCRATCH)
&& (note = find_reg_note (insn, REG_UNUSED, old)) != 0)
{
XEXP (note, 0) = rld[j].reg_rtx;
continue;
}
/* Likewise for a SUBREG of an operand that dies. */
else if (GET_CODE (old) == SUBREG
&& GET_CODE (SUBREG_REG (old)) == REG
&& 0 != (note = find_reg_note (insn, REG_UNUSED,
SUBREG_REG (old))))
{
XEXP (note, 0) = gen_lowpart_common (GET_MODE (old),
rld[j].reg_rtx);
continue;
gen_reload (reloadreg, second_reloadreg,
rl->opnum, rl->when_needed);
}
else if (GET_CODE (old) == SCRATCH)
/* If we aren't optimizing, there won't be a REG_UNUSED note,
but we don't want to make an output reload. */
continue;
#if 0
/* Strip off of OLD any size-increasing SUBREGs such as
(SUBREG:SI foo:QI 0). */
while (GET_CODE (old) == SUBREG && SUBREG_WORD (old) == 0
&& (GET_MODE_SIZE (GET_MODE (old))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (old)))))
old = SUBREG_REG (old);
}
}
#endif
/* If is a JUMP_INSN, we can't support output reloads yet. */
if (GET_CODE (insn) == JUMP_INSN)
abort ();
/* Output the last reload insn. */
if (! special)
{
rtx set;
/* Don't output the last reload if OLD is not the dest of
INSN and is in the src and is clobbered by INSN. */
if (! flag_expensive_optimizations
|| GET_CODE (old) != REG
|| !(set = single_set (insn))
|| rtx_equal_p (old, SET_DEST (set))
|| !reg_mentioned_p (old, SET_SRC (set))
|| !regno_clobbered_p (REGNO (old), insn))
gen_reload (old, reloadreg, rl->opnum,
rl->when_needed);
}
if (rld[j].when_needed == RELOAD_OTHER)
start_sequence ();
else
push_to_sequence (output_reload_insns[rld[j].opnum]);
/* 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')
{
rtx pat = PATTERN (p);
old = rld[j].out;
/* If this output reload doesn't come from a spill reg,
clear any memory of reloaded copies of the pseudo reg.
If this output reload comes from a spill reg,
reg_has_output_reload will make this do nothing. */
note_stores (pat, forget_old_reloads_1, NULL);
/* Determine the mode to reload in.
See comments above (for input reloading). */
if (reg_mentioned_p (rl->reg_rtx, pat))
{
rtx set = single_set (insn);
if (reload_spill_index[j] < 0
&& set
&& SET_SRC (set) == rl->reg_rtx)
{
int src = REGNO (SET_SRC (set));
mode = GET_MODE (old);
if (mode == VOIDmode)
{
/* VOIDmode should never happen for an output. */
if (asm_noperands (PATTERN (insn)) < 0)
/* It's the compiler's fault. */
fatal_insn ("VOIDmode on an output", insn);
error_for_asm (insn, "output operand is constant in `asm'");
/* Prevent crash--use something we know is valid. */
mode = word_mode;
old = gen_rtx_REG (mode, REGNO (reloadreg));
}
reload_spill_index[j] = src;
SET_HARD_REG_BIT (reg_is_output_reload, src);
if (find_regno_note (insn, REG_DEAD, src))
SET_HARD_REG_BIT (reg_reloaded_died, src);
}
if (REGNO (rl->reg_rtx) < FIRST_PSEUDO_REGISTER)
{
int s = rl->secondary_out_reload;
set = single_set (p);
/* If this reload copies only to the secondary reload
register, the secondary reload does the actual
store. */
if (s >= 0 && set == NULL_RTX)
; /* We can't tell what function the secondary reload
has and where the actual store to the pseudo is
made; leave new_spill_reg_store alone. */
else if (s >= 0
&& SET_SRC (set) == rl->reg_rtx
&& SET_DEST (set) == rld[s].reg_rtx)
{
/* Usually the next instruction will be the
secondary reload insn; if we can confirm
that it is, setting new_spill_reg_store to
that insn will allow an extra optimization. */
rtx s_reg = rld[s].reg_rtx;
rtx next = NEXT_INSN (p);
rld[s].out = rl->out;
rld[s].out_reg = rl->out_reg;
set = single_set (next);
if (set && SET_SRC (set) == s_reg
&& ! new_spill_reg_store[REGNO (s_reg)])
{
SET_HARD_REG_BIT (reg_is_output_reload,
REGNO (s_reg));
new_spill_reg_store[REGNO (s_reg)] = next;
}
}
else
new_spill_reg_store[REGNO (rl->reg_rtx)] = p;
}
}
}
if (GET_MODE (reloadreg) != mode)
reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
if (rl->when_needed == RELOAD_OTHER)
{
emit_insns (other_output_reload_insns[rl->opnum]);
other_output_reload_insns[rl->opnum] = get_insns ();
}
else
output_reload_insns[rl->opnum] = get_insns ();
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
end_sequence ();
}
/* If we need two reload regs, set RELOADREG to the intermediate
one, since it will be stored into OLD. We might need a secondary
register only for an input reload, so check again here. */
/* Do input reloading for reload RL, which is for the insn described by CHAIN
and has the number J. */
static void
do_input_reload (chain, rl, j)
struct insn_chain *chain;
struct reload *rl;
int j;
{
int expect_occurrences = 1;
rtx insn = chain->insn;
rtx old = (rl->in && GET_CODE (rl->in) == MEM
? rl->in_reg : rl->in);
if (old != 0
/* AUTO_INC reloads need to be handled even if inherited. We got an
AUTO_INC reload if reload_out is set but reload_out_reg isn't. */
&& (! reload_inherited[j] || (rl->out && ! rl->out_reg))
&& ! rtx_equal_p (rl->reg_rtx, old)
&& rl->reg_rtx != 0)
{
emit_input_reload_insns (chain, rld + j, old, j);
}
if (rld[j].secondary_out_reload >= 0)
{
rtx real_old = old;
/* When inheriting a wider reload, we have a MEM in rl->in,
e.g. inheriting a SImode output reload for
(mem:HI (plus:SI (reg:SI 14 fp) (const_int 10))) */
if (optimize && reload_inherited[j] && rl->in
&& GET_CODE (rl->in) == MEM
&& GET_CODE (rl->in_reg) == MEM
&& reload_spill_index[j] >= 0
&& TEST_HARD_REG_BIT (reg_reloaded_valid, reload_spill_index[j]))
{
expect_occurrences
= count_occurrences (PATTERN (insn), rl->in) == 1 ? 0 : -1;
rl->in
= regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]];
}
if (GET_CODE (old) == REG && REGNO (old) >= FIRST_PSEUDO_REGISTER
&& reg_equiv_mem[REGNO (old)] != 0)
real_old = reg_equiv_mem[REGNO (old)];
/* If we are reloading a register that was recently stored in with an
output-reload, see if we can prove there was
actually no need to store the old value in it. */
if((SECONDARY_OUTPUT_RELOAD_CLASS (rld[j].class,
mode, real_old)
!= NO_REGS))
{
second_reloadreg = reloadreg;
reloadreg = rld[rld[j].secondary_out_reload].reg_rtx;
if (optimize
&& (reload_inherited[j] || reload_override_in[j])
&& rl->reg_rtx
&& GET_CODE (rl->reg_rtx) == REG
&& spill_reg_store[REGNO (rl->reg_rtx)] != 0
#if 0
/* There doesn't seem to be any reason to restrict this to pseudos
and doing so loses in the case where we are copying from a
register of the wrong class. */
&& (REGNO (spill_reg_stored_to[REGNO (rl->reg_rtx)])
>= FIRST_PSEUDO_REGISTER)
#endif
/* The insn might have already some references to stackslots
replaced by MEMs, while reload_out_reg still names the
original pseudo. */
&& (dead_or_set_p (insn,
spill_reg_stored_to[REGNO (rl->reg_rtx)])
|| rtx_equal_p (spill_reg_stored_to[REGNO (rl->reg_rtx)],
rl->out_reg)))
delete_output_reload (insn, j, REGNO (rl->reg_rtx));
}
/* See if RELOADREG is to be used as a scratch register
or as an intermediate register. */
if (rld[j].secondary_out_icode != CODE_FOR_nothing)
{
emit_insn ((GEN_FCN (rld[j].secondary_out_icode)
(real_old, second_reloadreg, reloadreg)));
special = 1;
}
else
{
/* See if we need both a scratch and intermediate reload
register. */
/* Do output reloading for reload RL, which is for the insn described by
CHAIN and has the number J.
??? At some point we need to support handling output reloads of
JUMP_INSNs or insns that set cc0. */
static void
do_output_reload (chain, rl, j)
struct insn_chain *chain;
struct reload *rl;
int j;
{
rtx note, old;
rtx insn = chain->insn;
/* If this is an output reload that stores something that is
not loaded in this same reload, see if we can eliminate a previous
store. */
rtx pseudo = rl->out_reg;
if (pseudo
&& GET_CODE (pseudo) == REG
&& ! rtx_equal_p (rl->in_reg, pseudo)
&& REGNO (pseudo) >= FIRST_PSEUDO_REGISTER
&& reg_last_reload_reg[REGNO (pseudo)])
{
int pseudo_no = REGNO (pseudo);
int last_regno = REGNO (reg_last_reload_reg[pseudo_no]);
/* We don't need to test full validity of last_regno for
inherit here; we only want to know if the store actually
matches the pseudo. */
if (reg_reloaded_contents[last_regno] == pseudo_no
&& spill_reg_store[last_regno]
&& rtx_equal_p (pseudo, spill_reg_stored_to[last_regno]))
delete_output_reload (insn, j, last_regno);
}
int secondary_reload = rld[j].secondary_out_reload;
enum insn_code tertiary_icode
= rld[secondary_reload].secondary_out_icode;
old = rl->out_reg;
if (old == 0
|| rl->reg_rtx == old
|| rl->reg_rtx == 0)
return;
if (GET_MODE (reloadreg) != mode)
reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
/* An output operand that dies right away does need a reload,
but need not be copied from it. Show the new location in the
REG_UNUSED note. */
if ((GET_CODE (old) == REG || GET_CODE (old) == SCRATCH)
&& (note = find_reg_note (insn, REG_UNUSED, old)) != 0)
{
XEXP (note, 0) = rl->reg_rtx;
return;
}
/* Likewise for a SUBREG of an operand that dies. */
else if (GET_CODE (old) == SUBREG
&& GET_CODE (SUBREG_REG (old)) == REG
&& 0 != (note = find_reg_note (insn, REG_UNUSED,
SUBREG_REG (old))))
{
XEXP (note, 0) = gen_lowpart_common (GET_MODE (old),
rl->reg_rtx);
return;
}
else if (GET_CODE (old) == SCRATCH)
/* If we aren't optimizing, there won't be a REG_UNUSED note,
but we don't want to make an output reload. */
return;
if (tertiary_icode != CODE_FOR_nothing)
{
rtx third_reloadreg
= rld[rld[secondary_reload].secondary_out_reload].reg_rtx;
rtx tem;
/* Copy primary reload reg to secondary reload reg.
(Note that these have been swapped above, then
secondary reload reg to OLD using our insn. */
/* If REAL_OLD is a paradoxical SUBREG, remove it
and try to put the opposite SUBREG on
RELOADREG. */
if (GET_CODE (real_old) == SUBREG
&& (GET_MODE_SIZE (GET_MODE (real_old))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (real_old))))
&& 0 != (tem = gen_lowpart_common
(GET_MODE (SUBREG_REG (real_old)),
reloadreg)))
real_old = SUBREG_REG (real_old), reloadreg = tem;
gen_reload (reloadreg, second_reloadreg,
rld[j].opnum, rld[j].when_needed);
emit_insn ((GEN_FCN (tertiary_icode)
(real_old, reloadreg, third_reloadreg)));
special = 1;
}
/* If is a JUMP_INSN, we can't support output reloads yet. */
if (GET_CODE (insn) == JUMP_INSN)
abort ();
else
/* Copy between the reload regs here and then to
OUT later. */
emit_output_reload_insns (chain, rld + j, j);
}
gen_reload (reloadreg, second_reloadreg,
rld[j].opnum, rld[j].when_needed);
}
}
}
#endif
/* Output insns to reload values in and out of the chosen reload regs. */
/* Output the last reload insn. */
if (! special)
{
rtx set;
/* Don't output the last reload if OLD is not the dest of
INSN and is in the src and is clobbered by INSN. */
if (! flag_expensive_optimizations
|| GET_CODE (old) != REG
|| !(set = single_set (insn))
|| rtx_equal_p (old, SET_DEST (set))
|| !reg_mentioned_p (old, SET_SRC (set))
|| !regno_clobbered_p (REGNO (old), insn))
gen_reload (old, reloadreg, rld[j].opnum,
rld[j].when_needed);
}
static void
emit_reload_insns (chain)
struct insn_chain *chain;
{
rtx insn = chain->insn;
/* 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')
{
rtx pat = PATTERN (p);
register int j;
rtx following_insn = NEXT_INSN (insn);
rtx before_insn = PREV_INSN (insn);
/* If this output reload doesn't come from a spill reg,
clear any memory of reloaded copies of the pseudo reg.
If this output reload comes from a spill reg,
reg_has_output_reload will make this do nothing. */
note_stores (pat, forget_old_reloads_1, NULL);
CLEAR_HARD_REG_SET (reg_reloaded_died);
if (reg_mentioned_p (rld[j].reg_rtx, pat))
{
rtx set = single_set (insn);
if (reload_spill_index[j] < 0
&& set
&& SET_SRC (set) == rld[j].reg_rtx)
{
int src = REGNO (SET_SRC (set));
for (j = 0; j < reload_n_operands; j++)
input_reload_insns[j] = input_address_reload_insns[j]
= inpaddr_address_reload_insns[j]
= output_reload_insns[j] = output_address_reload_insns[j]
= outaddr_address_reload_insns[j]
= other_output_reload_insns[j] = 0;
other_input_address_reload_insns = 0;
other_input_reload_insns = 0;
operand_reload_insns = 0;
other_operand_reload_insns = 0;
reload_spill_index[j] = src;
SET_HARD_REG_BIT (reg_is_output_reload, src);
if (find_regno_note (insn, REG_DEAD, src))
SET_HARD_REG_BIT (reg_reloaded_died, src);
}
if (REGNO (rld[j].reg_rtx) < FIRST_PSEUDO_REGISTER)
{
int s = rld[j].secondary_out_reload;
set = single_set (p);
/* If this reload copies only to the secondary reload
register, the secondary reload does the actual
store. */
if (s >= 0 && set == NULL_RTX)
; /* We can't tell what function the secondary reload
has and where the actual store to the pseudo is
made; leave new_spill_reg_store alone. */
else if (s >= 0
&& SET_SRC (set) == rld[j].reg_rtx
&& SET_DEST (set) == rld[s].reg_rtx)
{
/* Usually the next instruction will be the
secondary reload insn; if we can confirm
that it is, setting new_spill_reg_store to
that insn will allow an extra optimization. */
rtx s_reg = rld[s].reg_rtx;
rtx next = NEXT_INSN (p);
rld[s].out = rld[j].out;
rld[s].out_reg = rld[j].out_reg;
set = single_set (next);
if (set && SET_SRC (set) == s_reg
&& ! new_spill_reg_store[REGNO (s_reg)])
{
SET_HARD_REG_BIT (reg_is_output_reload,
REGNO (s_reg));
new_spill_reg_store[REGNO (s_reg)] = next;
}
}
else
new_spill_reg_store[REGNO (rld[j].reg_rtx)] = p;
}
}
}
/* Now output the instructions to copy the data into and out of the
reload registers. Do these in the order that the reloads were reported,
since reloads of base and index registers precede reloads of operands
and the operands may need the base and index registers reloaded. */
if (rld[j].when_needed == RELOAD_OTHER)
{
emit_insns (other_output_reload_insns[rld[j].opnum]);
other_output_reload_insns[rld[j].opnum] = get_insns ();
}
else
output_reload_insns[rld[j].opnum] = get_insns ();
for (j = 0; j < n_reloads; j++)
{
if (rld[j].reg_rtx
&& REGNO (rld[j].reg_rtx) < FIRST_PSEUDO_REGISTER)
new_spill_reg_store[REGNO (rld[j].reg_rtx)] = 0;
end_sequence ();
}
do_input_reload (chain, rld + j, j);
do_output_reload (chain, rld + j, j);
}
/* Now write all the insns we made for reloads in the order expected by
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment