aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/reload1.c1592
2 files changed, 824 insertions, 780 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f009143..1dc34b0 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+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.
diff --git a/gcc/reload1.c b/gcc/reload1.c
index 366a9a1..8df32e6 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -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