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> Tue Dec 21 07:06:36 1999 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* pa.h (FUNCTION_ARG_BOUNDARY): Never return 0. * pa.h (FUNCTION_ARG_BOUNDARY): Never return 0.
......
...@@ -414,6 +414,14 @@ static int set_reload_reg PROTO((int, int)); ...@@ -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_init PROTO((struct insn_chain *, rtx *));
static void choose_reload_regs PROTO((struct insn_chain *)); static void choose_reload_regs PROTO((struct insn_chain *));
static void merge_assigned_reloads PROTO((rtx)); 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 emit_reload_insns PROTO((struct insn_chain *));
static void delete_output_reload PROTO((rtx, int, int)); static void delete_output_reload PROTO((rtx, int, int));
static void delete_address_reloads PROTO((rtx, rtx)); static void delete_address_reloads PROTO((rtx, rtx));
...@@ -5834,867 +5842,891 @@ merge_assigned_reloads (insn) ...@@ -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 static void
emit_reload_insns (chain) emit_input_reload_insns (chain, rl, old, j)
struct insn_chain *chain; struct insn_chain *chain;
struct reload *rl;
rtx old;
int j;
{ {
rtx insn = chain->insn; 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; #ifdef SECONDARY_INPUT_RELOAD_CLASS
rtx input_reload_insns[MAX_RECOG_OPERANDS]; /* If we need a secondary register for this operation, see if
rtx other_input_address_reload_insns = 0; the value is already in a register in that class. Don't
rtx other_input_reload_insns = 0; do this if the secondary register will be used as a scratch
rtx input_address_reload_insns[MAX_RECOG_OPERANDS]; register. */
rtx inpaddr_address_reload_insns[MAX_RECOG_OPERANDS];
rtx output_reload_insns[MAX_RECOG_OPERANDS]; if (rl->secondary_in_reload >= 0
rtx output_address_reload_insns[MAX_RECOG_OPERANDS]; && rl->secondary_in_icode == CODE_FOR_nothing
rtx outaddr_address_reload_insns[MAX_RECOG_OPERANDS]; && optimize)
rtx operand_reload_insns = 0; oldequiv
rtx other_operand_reload_insns = 0; = find_equiv_reg (old, insn,
rtx other_output_reload_insns[MAX_RECOG_OPERANDS]; rld[rl->secondary_in_reload].class,
rtx following_insn = NEXT_INSN (insn); -1, NULL_PTR, 0, mode);
rtx before_insn = PREV_INSN (insn); #endif
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;
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++) /* delete_output_reload is only invoked properly if old contains
input_reload_insns[j] = input_address_reload_insns[j] the original pseudo register. Since this is replaced with a
= inpaddr_address_reload_insns[j] hard reg when RELOAD_OVERRIDE_IN is set, see if we can
= output_reload_insns[j] = output_address_reload_insns[j] find the pseudo in RELOAD_IN_REG. */
= outaddr_address_reload_insns[j] if (oldequiv == 0
= other_output_reload_insns[j] = 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 push_to_sequence (*where);
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. */
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; /* We are not going to bother supporting the case where a
rtx oldequiv_reg = 0; incremented register can't be copied directly from
rtx this_reload_insn = 0; OLDEQUIV since this seems highly unlikely. */
int expect_occurrences = 1; if (rl->secondary_in_reload >= 0)
abort ();
if (rld[j].reg_rtx
&& REGNO (rld[j].reg_rtx) < FIRST_PSEUDO_REGISTER)
new_spill_reg_store[REGNO (rld[j].reg_rtx)] = 0;
old = (rld[j].in && GET_CODE (rld[j].in) == MEM if (reload_inherited[j])
? rld[j].in_reg : rld[j].in); oldequiv = reloadreg;
if (old != 0 old = XEXP (rl->in_reg, 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;
#ifdef SECONDARY_INPUT_RELOAD_CLASS if (optimize && GET_CODE (oldequiv) == REG
/* If we need a secondary register for this operation, see if && REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
the value is already in a register in that class. Don't && spill_reg_store[REGNO (oldequiv)]
do this if the secondary register will be used as a scratch && GET_CODE (old) == REG
register. */ && (dead_or_set_p (insn,
spill_reg_stored_to[REGNO (oldequiv)])
if (rld[j].secondary_in_reload >= 0 || rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
&& rld[j].secondary_in_icode == CODE_FOR_nothing old)))
&& optimize) delete_output_reload (insn, j, REGNO (oldequiv));
oldequiv
= find_equiv_reg (old, insn, /* Prevent normal processing of this reload. */
rld[rld[j].secondary_in_reload].class, special = 1;
-1, NULL_PTR, 0, mode); /* Output a special code sequence for this case. */
#endif 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 /* If we are reloading a pseudo-register that was set by the previous
that already holds the same value. If so, reload from there. insn, see if we can get rid of that pseudo-register entirely
We can pass 0 as the reload_reg_p argument because by redirecting the previous insn into our reload register. */
any other reload has either already been emitted,
in which case find_equiv_reg will see the reload-insn, else if (optimize && GET_CODE (old) == REG
or has yet to be emitted, in which case it doesn't matter && REGNO (old) >= FIRST_PSEUDO_REGISTER
because we will use this equiv reg right away. */ && dead_or_set_p (insn, old)
/* This is unsafe if some other reload
if (oldequiv == 0 && optimize uses the same reg first. */
&& (GET_CODE (old) == MEM && reload_reg_free_for_value_p (REGNO (reloadreg),
|| (GET_CODE (old) == REG rl->opnum,
&& REGNO (old) >= FIRST_PSEUDO_REGISTER rl->when_needed,
&& reg_renumber[REGNO (old)] < 0))) old, rl->out,
oldequiv = find_equiv_reg (old, insn, ALL_REGS, j, 0))
-1, NULL_PTR, 0, mode); {
rtx temp = PREV_INSN (insn);
if (oldequiv) 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); spill_reg_store[REGNO (SET_SRC (PATTERN (temp)))] = 0;
spill_reg_stored_to[REGNO (SET_SRC (PATTERN (temp)))] = 0;
/* 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;
} }
/* delete_output_reload is only invoked properly if old contains /* If these are the only uses of the pseudo reg,
the original pseudo register. Since this is replaced with a pretend for GDB it lives in the reload reg we used. */
hard reg when RELOAD_OVERRIDE_IN is set, see if we can if (REG_N_DEATHS (REGNO (old)) == 1
find the pseudo in RELOAD_IN_REG. */ && REG_N_SETS (REGNO (old)) == 1)
if (oldequiv == 0
&& reload_override_in[j]
&& GET_CODE (rld[j].in_reg) == REG)
{ {
oldequiv = old; reg_renumber[REGNO (old)] = REGNO (rl->reg_rtx);
old = rld[j].in_reg; alter_reg (REGNO (old), -1);
}
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 ();
} }
return;
}
}
push_to_sequence (*where); /* We can't do that, so output an insn to load RELOADREG. */
special = 0;
/* Auto-increment addresses must be reloaded in a special way. */ #ifdef SECONDARY_INPUT_RELOAD_CLASS
if (rld[j].out && ! rld[j].out_reg) /* If we have a secondary reload, pick up the secondary register
{ and icode, if any. If OLDEQUIV and OLD are different or
/* We are not going to bother supporting the case where a if this is an in-out reload, recompute whether or not we
incremented register can't be copied directly from still need a secondary register and what the icode should
OLDEQUIV since this seems highly unlikely. */ be. If we still need a secondary register and the class or
if (rld[j].secondary_in_reload >= 0) icode is different, go back to reloading from OLD if using
abort (); OLDEQUIV means that we got the wrong type of register. We
cannot have different class or icode due to an in-out reload
if (reload_inherited[j]) because we don't make such reloads when both the input and
oldequiv = reloadreg; output need secondary reload registers. */
old = XEXP (rld[j].in_reg, 0); if (rl->secondary_in_reload >= 0)
{
if (optimize && GET_CODE (oldequiv) == REG rtx second_reload_reg = 0;
&& REGNO (oldequiv) < FIRST_PSEUDO_REGISTER int secondary_reload = rl->secondary_in_reload;
&& spill_reg_store[REGNO (oldequiv)] rtx real_oldequiv = oldequiv;
&& GET_CODE (old) == REG rtx real_old = old;
&& (dead_or_set_p (insn, rtx tmp;
spill_reg_stored_to[REGNO (oldequiv)]) enum insn_code icode;
|| rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
old))) /* If OLDEQUIV is a pseudo with a MEM, get the real MEM
delete_output_reload (insn, j, REGNO (oldequiv)); and similarly for OLD.
See comments in get_secondary_reload in reload.c. */
/* Prevent normal processing of this reload. */ /* If it is a pseudo that cannot be replaced with its
special = 1; equivalent MEM, we must fall back to reload_in, which
/* Output a special code sequence for this case. */ will have all the necessary substitutions registered.
new_spill_reg_store[REGNO (reloadreg)] Likewise for a pseudo that can't be replaced with its
= inc_for_reload (reloadreg, oldequiv, rld[j].out, equivalent constant.
rld[j].inc);
} 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 if (new_class == NO_REGS)
insn, see if we can get rid of that pseudo-register entirely second_reload_reg = 0;
by redirecting the previous insn into our reload register. */ else
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))
{ {
rtx temp = PREV_INSN (insn); enum insn_code new_icode;
while (temp && GET_CODE (temp) == NOTE) enum machine_mode new_mode;
temp = PREV_INSN (temp);
if (temp if (! TEST_HARD_REG_BIT (reg_class_contents[(int) new_class],
&& GET_CODE (temp) == INSN REGNO (second_reload_reg)))
&& GET_CODE (PATTERN (temp)) == SET oldequiv = old, real_oldequiv = real_old;
&& SET_DEST (PATTERN (temp)) == old else
/* 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. */ new_icode = reload_in_optab[(int) mode];
SET_DEST (PATTERN (temp)) = reloadreg; if (new_icode != CODE_FOR_nothing
&& ((insn_data[(int) new_icode].operand[0].predicate
/* If the previous insn is an output reload, the source is && ! ((*insn_data[(int) new_icode].operand[0].predicate)
a reload register, and its spill_reg_store entry will (reloadreg, mode)))
contain the previous destination. This is now || (insn_data[(int) new_icode].operand[1].predicate
invalid. */ && ! ((*insn_data[(int) new_icode].operand[1].predicate)
if (GET_CODE (SET_SRC (PATTERN (temp))) == REG (real_oldequiv, mode)))))
&& REGNO (SET_SRC (PATTERN (temp))) < FIRST_PSEUDO_REGISTER) new_icode = CODE_FOR_nothing;
{
spill_reg_store[REGNO (SET_SRC (PATTERN (temp)))] = 0; if (new_icode == CODE_FOR_nothing)
spill_reg_stored_to[REGNO (SET_SRC (PATTERN (temp)))] = 0; new_mode = mode;
} else
new_mode = insn_data[(int) new_icode].operand[2].mode;
/* If these are the only uses of the pseudo reg, if (GET_MODE (second_reload_reg) != new_mode)
pretend for GDB it lives in the reload reg we used. */
if (REG_N_DEATHS (REGNO (old)) == 1
&& REG_N_SETS (REGNO (old)) == 1)
{ {
reg_renumber[REGNO (old)] = REGNO (rld[j].reg_rtx); if (!HARD_REGNO_MODE_OK (REGNO (second_reload_reg),
alter_reg (REGNO (old), -1); 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 emit_insn (GEN_FCN (icode) (reloadreg, real_oldequiv,
rtx second_reload_reg = 0; second_reload_reg));
enum insn_code icode; return;
}
/* If we have a secondary reload, pick up the secondary register else
and icode, if any. If OLDEQUIV and OLD are different or {
if this is an in-out reload, recompute whether or not we /* See if we need a scratch register to load the
still need a secondary register and what the icode should intermediate register (a tertiary reload). */
be. If we still need a secondary register and the class or enum insn_code tertiary_icode
icode is different, go back to reloading from OLD if using = rld[secondary_reload].secondary_in_icode;
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)];
}
tmp = old; if (tertiary_icode != CODE_FOR_nothing)
if (GET_CODE (tmp) == SUBREG) {
tmp = SUBREG_REG (tmp); rtx third_reload_reg
if (GET_CODE (tmp) == REG = rld[rld[secondary_reload].secondary_in_reload].reg_rtx;
&& 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)];
}
second_reload_reg = rld[secondary_reload].reg_rtx; emit_insn ((GEN_FCN (tertiary_icode)
icode = rld[j].secondary_in_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)) oldequiv = second_reload_reg;
|| (rld[j].in != 0 && rld[j].out != 0)) }
{ }
enum reg_class new_class }
= SECONDARY_INPUT_RELOAD_CLASS (rld[j].class, #endif
mode, real_oldequiv);
if (new_class == NO_REGS) if (! rtx_equal_p (reloadreg, oldequiv))
second_reload_reg = 0; {
else rtx real_oldequiv = oldequiv;
{
enum insn_code new_icode; if ((GET_CODE (oldequiv) == REG
enum machine_mode new_mode; && 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], /* End this sequence. */
REGNO (second_reload_reg))) *where = get_insns ();
oldequiv = old, real_oldequiv = real_old; end_sequence ();
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;
if (GET_MODE (second_reload_reg) != new_mode) /* Update reload_override_in so that delete_address_reloads_1
{ can see the actual register usage. */
if (!HARD_REGNO_MODE_OK (REGNO (second_reload_reg), if (oldequiv_reg)
new_mode)) reload_override_in[j] = oldequiv;
oldequiv = old, real_oldequiv = real_old; }
else
second_reload_reg
= gen_rtx_REG (new_mode,
REGNO (second_reload_reg));
}
}
}
}
/* If we still need a secondary reload register, check /* Generate insns to for the output reload RL, which is for the insn described
to see if it is being used as a scratch or intermediate by CHAIN and has the number J. */
register and generate code appropriately. If we need static void
a scratch register, use REAL_OLDEQUIV since the form of emit_output_reload_insns (chain, rl, j)
the insn may depend on the actual address if it is struct insn_chain *chain;
a MEM. */ 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 (rl->when_needed == RELOAD_OTHER)
{ start_sequence ();
if (icode != CODE_FOR_nothing) else
{ push_to_sequence (output_reload_insns[rl->opnum]);
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 (tertiary_icode != CODE_FOR_nothing) /* Determine the mode to reload in.
{ See comments above (for input reloading). */
rtx third_reload_reg
= rld[rld[secondary_reload].secondary_in_reload].reg_rtx;
emit_insn ((GEN_FCN (tertiary_icode) if (mode == VOIDmode)
(second_reload_reg, real_oldequiv, {
third_reload_reg))); /* VOIDmode should never happen for an output. */
} if (asm_noperands (PATTERN (insn)) < 0)
else /* It's the compiler's fault. */
gen_reload (second_reload_reg, real_oldequiv, fatal_insn ("VOIDmode on an output", insn);
rld[j].opnum, error_for_asm (insn, "output operand is constant in `asm'");
rld[j].when_needed); /* Prevent crash--use something we know is valid. */
mode = word_mode;
old = gen_rtx_REG (mode, REGNO (reloadreg));
}
oldequiv = second_reload_reg; if (GET_MODE (reloadreg) != mode)
} reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
}
}
#endif
if (! special && ! rtx_equal_p (reloadreg, oldequiv)) #ifdef SECONDARY_OUTPUT_RELOAD_CLASS
{
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);
}
} /* 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 (); if (rl->secondary_out_reload >= 0)
/* End this sequence. */ {
*where = get_insns (); rtx real_old = old;
end_sequence ();
/* Update reload_override_in so that delete_address_reloads_1 if (GET_CODE (old) == REG && REGNO (old) >= FIRST_PSEUDO_REGISTER
can see the actual register usage. */ && reg_equiv_mem[REGNO (old)] != 0)
if (oldequiv_reg) real_old = reg_equiv_mem[REGNO (old)];
reload_override_in[j] = oldequiv;
}
/* When inheriting a wider reload, we have a MEM in rld[j].in, if ((SECONDARY_OUTPUT_RELOAD_CLASS (rl->class,
e.g. inheriting a SImode output reload for mode, real_old)
(mem:HI (plus:SI (reg:SI 14 fp) (const_int 10))) */ != NO_REGS))
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]))
{ {
expect_occurrences rtx second_reloadreg = reloadreg;
= count_occurrences (PATTERN (insn), rld[j].in) == 1 ? 0 : -1; reloadreg = rld[rl->secondary_out_reload].reg_rtx;
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. */
if (optimize /* See if RELOADREG is to be used as a scratch register
&& (reload_inherited[j] || reload_override_in[j]) or as an intermediate register. */
&& rld[j].reg_rtx if (rl->secondary_out_icode != CODE_FOR_nothing)
&& GET_CODE (rld[j].reg_rtx) == REG {
&& spill_reg_store[REGNO (rld[j].reg_rtx)] != 0 emit_insn ((GEN_FCN (rl->secondary_out_icode)
#if 0 (real_old, second_reloadreg, reloadreg)));
/* There doesn't seem to be any reason to restrict this to pseudos special = 1;
and doing so loses in the case where we are copying from a }
register of the wrong class. */ else
&& (REGNO (spill_reg_stored_to[REGNO (rld[j].reg_rtx)]) {
>= FIRST_PSEUDO_REGISTER) /* See if we need both a scratch and intermediate reload
#endif register. */
/* 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));
/* Input-reloading is done. Now do output-reloading, int secondary_reload = rl->secondary_out_reload;
storing the value from the reload-register after the main insn enum insn_code tertiary_icode
if rld[j].out is nonzero. = rld[secondary_reload].secondary_out_icode;
??? At some point we need to support handling output reloads of if (GET_MODE (reloadreg) != mode)
JUMP_INSNs or insns that set cc0. */ reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
/* If this is an output reload that stores something that is if (tertiary_icode != CODE_FOR_nothing)
not loaded in this same reload, see if we can eliminate a previous {
store. */ rtx third_reloadreg
{ = rld[rld[secondary_reload].secondary_out_reload].reg_rtx;
rtx pseudo = rld[j].out_reg; 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 else
&& GET_CODE (pseudo) == REG /* Copy between the reload regs here and then to
&& ! rtx_equal_p (rld[j].in_reg, pseudo) OUT later. */
&& 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);
}
}
old = rld[j].out_reg; gen_reload (reloadreg, second_reloadreg,
if (old != 0 rl->opnum, rl->when_needed);
&& 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;
} }
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 #endif
/* If is a JUMP_INSN, we can't support output reloads yet. */ /* Output the last reload insn. */
if (GET_CODE (insn) == JUMP_INSN) if (! special)
abort (); {
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) /* Look at all insns we emitted, just to be safe. */
start_sequence (); for (p = get_insns (); p; p = NEXT_INSN (p))
else if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
push_to_sequence (output_reload_insns[rld[j].opnum]); {
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. if (reg_mentioned_p (rl->reg_rtx, pat))
See comments above (for input reloading). */ {
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); reload_spill_index[j] = src;
if (mode == VOIDmode) SET_HARD_REG_BIT (reg_is_output_reload, src);
{ if (find_regno_note (insn, REG_DEAD, src))
/* VOIDmode should never happen for an output. */ SET_HARD_REG_BIT (reg_reloaded_died, src);
if (asm_noperands (PATTERN (insn)) < 0) }
/* It's the compiler's fault. */ if (REGNO (rl->reg_rtx) < FIRST_PSEUDO_REGISTER)
fatal_insn ("VOIDmode on an output", insn); {
error_for_asm (insn, "output operand is constant in `asm'"); int s = rl->secondary_out_reload;
/* Prevent crash--use something we know is valid. */ set = single_set (p);
mode = word_mode; /* If this reload copies only to the secondary reload
old = gen_rtx_REG (mode, REGNO (reloadreg)); 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) if (rl->when_needed == RELOAD_OTHER)
reloadreg = gen_rtx_REG (mode, REGNO (reloadreg)); {
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 /* Do input reloading for reload RL, which is for the insn described by CHAIN
one, since it will be stored into OLD. We might need a secondary and has the number J. */
register only for an input reload, so check again here. */ 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) /* When inheriting a wider reload, we have a MEM in rl->in,
{ e.g. inheriting a SImode output reload for
rtx real_old = old; (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 /* If we are reloading a register that was recently stored in with an
&& reg_equiv_mem[REGNO (old)] != 0) output-reload, see if we can prove there was
real_old = reg_equiv_mem[REGNO (old)]; actually no need to store the old value in it. */
if((SECONDARY_OUTPUT_RELOAD_CLASS (rld[j].class, if (optimize
mode, real_old) && (reload_inherited[j] || reload_override_in[j])
!= NO_REGS)) && rl->reg_rtx
{ && GET_CODE (rl->reg_rtx) == REG
second_reloadreg = reloadreg; && spill_reg_store[REGNO (rl->reg_rtx)] != 0
reloadreg = rld[rld[j].secondary_out_reload].reg_rtx; #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 /* Do output reloading for reload RL, which is for the insn described by
or as an intermediate register. */ CHAIN and has the number J.
if (rld[j].secondary_out_icode != CODE_FOR_nothing) ??? At some point we need to support handling output reloads of
{ JUMP_INSNs or insns that set cc0. */
emit_insn ((GEN_FCN (rld[j].secondary_out_icode) static void
(real_old, second_reloadreg, reloadreg))); do_output_reload (chain, rl, j)
special = 1; struct insn_chain *chain;
} struct reload *rl;
else int j;
{ {
/* See if we need both a scratch and intermediate reload rtx note, old;
register. */ 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; old = rl->out_reg;
enum insn_code tertiary_icode if (old == 0
= rld[secondary_reload].secondary_out_icode; || rl->reg_rtx == old
|| rl->reg_rtx == 0)
return;
if (GET_MODE (reloadreg) != mode) /* An output operand that dies right away does need a reload,
reloadreg = gen_rtx_REG (mode, REGNO (reloadreg)); 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) /* If is a JUMP_INSN, we can't support output reloads yet. */
{ if (GET_CODE (insn) == JUMP_INSN)
rtx third_reloadreg abort ();
= 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;
}
else emit_output_reload_insns (chain, rld + j, j);
/* Copy between the reload regs here and then to }
OUT later. */
gen_reload (reloadreg, second_reloadreg, /* Output insns to reload values in and out of the chosen reload regs. */
rld[j].opnum, rld[j].when_needed);
}
}
}
#endif
/* Output the last reload insn. */ static void
if (! special) emit_reload_insns (chain)
{ struct insn_chain *chain;
rtx set; {
rtx insn = chain->insn;
/* 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);
}
/* Look at all insns we emitted, just to be safe. */ register int j;
for (p = get_insns (); p; p = NEXT_INSN (p)) rtx following_insn = NEXT_INSN (insn);
if (GET_RTX_CLASS (GET_CODE (p)) == 'i') rtx before_insn = PREV_INSN (insn);
{
rtx pat = PATTERN (p);
/* If this output reload doesn't come from a spill reg, CLEAR_HARD_REG_SET (reg_reloaded_died);
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);
if (reg_mentioned_p (rld[j].reg_rtx, pat)) for (j = 0; j < reload_n_operands; j++)
{ input_reload_insns[j] = input_address_reload_insns[j]
rtx set = single_set (insn); = inpaddr_address_reload_insns[j]
if (reload_spill_index[j] < 0 = output_reload_insns[j] = output_address_reload_insns[j]
&& set = outaddr_address_reload_insns[j]
&& SET_SRC (set) == rld[j].reg_rtx) = other_output_reload_insns[j] = 0;
{ other_input_address_reload_insns = 0;
int src = REGNO (SET_SRC (set)); other_input_reload_insns = 0;
operand_reload_insns = 0;
other_operand_reload_insns = 0;
reload_spill_index[j] = src; /* Now output the instructions to copy the data into and out of the
SET_HARD_REG_BIT (reg_is_output_reload, src); reload registers. Do these in the order that the reloads were reported,
if (find_regno_note (insn, REG_DEAD, src)) since reloads of base and index registers precede reloads of operands
SET_HARD_REG_BIT (reg_reloaded_died, src); and the operands may need the base and index registers reloaded. */
}
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;
}
}
}
if (rld[j].when_needed == RELOAD_OTHER) for (j = 0; j < n_reloads; j++)
{ {
emit_insns (other_output_reload_insns[rld[j].opnum]); if (rld[j].reg_rtx
other_output_reload_insns[rld[j].opnum] = get_insns (); && REGNO (rld[j].reg_rtx) < FIRST_PSEUDO_REGISTER)
} new_spill_reg_store[REGNO (rld[j].reg_rtx)] = 0;
else
output_reload_insns[rld[j].opnum] = get_insns ();
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 /* 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