/* Reload pseudo regs into hard regs for insns that require hard regs.
- Copyright (C) 1987, 88, 89, 92, 93, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-5, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
#include <stdio.h>
#include "recog.h"
#include "basic-block.h"
#include "output.h"
+#include "real.h"
/* This file contains the reload pass of the compiler, which is
run after register allocation has been done. It checks that
elements that are actually valid; new ones are added at the end. */
static short spill_regs[FIRST_PSEUDO_REGISTER];
+/* This reg set indicates those registers that have been used a spill
+ registers. This information is used in reorg.c, to help figure out
+ what registers are live at any point. It is assumed that all spill_regs
+ are dead at every CODE_LABEL. */
+
+HARD_REG_SET used_spill_regs;
+
+/* Index of last register assigned as a spill register. We allocate in
+ a round-robin fashion. */
+
+static int last_spill_reg;
+
/* Describes order of preference for putting regs into spill_regs.
Contains the numbers of all the hard regs, in order most preferred first.
This order is different for each function.
/* List of labels that must never be deleted. */
extern rtx forced_labels;
+
+/* Allocation number table from global register allocation. */
+extern int *reg_allocno;
\f
/* This structure is used to record information about register eliminations.
Each array entry describes one possible way of eliminating a register
static void scan_paradoxical_subregs PROTO((rtx));
static int hard_reg_use_compare PROTO((struct hard_reg_n_uses *,
struct hard_reg_n_uses *));
-static void order_regs_for_reload PROTO((void));
+static void order_regs_for_reload PROTO((int));
static int compare_spill_regs PROTO((short *, short *));
static void reload_as_needed PROTO((rtx, int));
static void forget_old_reloads_1 PROTO((rtx, rtx));
/* Look for REG_EQUIV notes; record what each pseudo is equivalent to.
Also find all paradoxical subregs and find largest such for each pseudo.
On machines with small register classes, record hard registers that
- are used for user variables. These can never be used for spills. */
+ are used for user variables. These can never be used for spills.
+ Also look for a "constant" NOTE_INSN_SETJMP. This means that all
+ caller-saved registers must be marked live. */
for (insn = first; insn; insn = NEXT_INSN (insn))
{
rtx set = single_set (insn);
+ if (GET_CODE (insn) == NOTE && CONST_CALL_P (insn)
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (! call_used_regs[i])
+ regs_ever_live[i] = 1;
+
if (set != 0 && GET_CODE (SET_DEST (set)) == REG)
{
rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
/* Compute the order of preference for hard registers to spill.
Store them by decreasing preference in potential_reload_regs. */
- order_regs_for_reload ();
+ order_regs_for_reload (global);
/* So far, no hard regs have been spilled. */
n_spills = 0;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
spill_reg_order[i] = -1;
+ /* Initialize to -1, which means take the first spill register. */
+ last_spill_reg = -1;
+
/* On most machines, we can't use any register explicitly used in the
rtl as a spill register. But on some, we have to. Those will have
taken care to keep the life of hard regs as short as possible. */
int did_elimination = 0;
/* To compute the number of reload registers of each class
- needed for an insn, we must similate what choose_reload_regs
+ needed for an insn, we must simulate what choose_reload_regs
can do. We do this by splitting an insn into an "input" and
an "output" part. RELOAD_OTHER reloads are used in both.
The input part uses those reloads, RELOAD_FOR_INPUT reloads,
if (other_mode != VOIDmode && other_mode != allocate_mode
&& ! modes_equiv_for_class_p (allocate_mode,
other_mode, class))
- abort ();
+ fatal_insn ("Two dissimilar machine modes both need groups of consecutive regs of the same class",
+ insn);
}
else if (size == 1)
{
need only in the smallest class in which it
is required. */
- bcopy (insn_needs.other.regs[0], basic_needs,
- sizeof basic_needs);
- bcopy (insn_needs.other.groups, basic_groups,
- sizeof basic_groups);
+ bcopy ((char *) insn_needs.other.regs[0],
+ (char *) basic_needs, sizeof basic_needs);
+ bcopy ((char *) insn_needs.other.groups,
+ (char *) basic_groups, sizeof basic_groups);
for (i = 0; i < N_REG_CLASSES; i++)
{
}
/* Now count extra regs if there might be a conflict with
- the return value register.
+ the return value register. */
- ??? This is not quite correct because we don't properly
- handle the case of groups, but if we end up doing
- something wrong, it either will end up not mattering or
- we will abort elsewhere. */
-
for (r = regno; r < regno + nregs; r++)
if (spill_reg_order[r] >= 0)
for (i = 0; i < N_REG_CLASSES; i++)
if (TEST_HARD_REG_BIT (reg_class_contents[i], r))
{
- if (basic_needs[i] > 0 || basic_groups[i] > 0)
+ if (basic_needs[i] > 0)
{
enum reg_class *p;
while (*p != LIM_REG_CLASSES)
insn_needs.other.regs[0][(int) *p++]++;
}
+ if (basic_groups[i] > 0)
+ {
+ enum reg_class *p;
+
+ insn_needs.other.groups[i]++;
+ p = reg_class_superclasses[i];
+ while (*p != LIM_REG_CLASSES)
+ insn_needs.other.groups[(int) *p++]++;
+ }
}
}
#endif /* SMALL_REGISTER_CLASSES */
/* Put all registers spilled so far back in potential_reload_regs, but
put them at the front, since we've already spilled most of the
- psuedos in them (we might have left some pseudos unspilled if they
+ pseudos in them (we might have left some pseudos unspilled if they
were in a block that didn't need any spill registers of a conflicting
class. We used to try to mark off the need for those registers,
but doing so properly is very complex and reallocating them is the
max_groups[class]--;
p = reg_class_superclasses[class];
while (*p != LIM_REG_CLASSES)
- max_groups[(int) *p++]--;
+ {
+ if (group_size [(int) *p] <= group_size [class])
+ max_groups[(int) *p]--;
+ p++;
+ }
/* Indicate both these regs are part of a group. */
SET_HARD_REG_BIT (counted_for_groups, j);
max_groups[class]--;
p = reg_class_superclasses[class];
while (*p != LIM_REG_CLASSES)
- max_groups[(int) *p++]--;
-
+ {
+ if (group_size [(int) *p]
+ <= group_size [class])
+ max_groups[(int) *p]--;
+ p++;
+ }
break;
}
}
while (max_needs[class] > 0 || max_nongroups[class] > 0)
{
-#ifdef SMALL_REGISTER_CLASSES
- /* This should be right for all machines, but only the 386
- is known to need it, so this conditional plays safe.
- ??? For 2.5, try making this unconditional. */
/* If we spilled enough regs, but they weren't counted
against the non-group need, see if we can count them now.
If so, we can avoid some actual spilling. */
}
if (max_needs[class] <= 0 && max_nongroups[class] <= 0)
break;
-#endif
/* Consider the potential reload regs that aren't
yet in use as reload regs, in order of preference.
free (scratch_block);
scratch_block = 0;
+ CLEAR_HARD_REG_SET (used_spill_regs);
+ for (i = 0; i < n_spills; i++)
+ SET_HARD_REG_BIT (used_spill_regs, spill_regs[i]);
+
return failure;
}
\f
max_groups[class]--;
p = reg_class_superclasses[class];
while (*p != LIM_REG_CLASSES)
- max_groups[(int) *p++]--;
+ {
+ if (group_size [(int) *p] <= group_size [class])
+ max_groups[(int) *p]--;
+ p++;
+ }
/* Don't count these registers again. */
- for (j = 0; j < group_size[j]; j++)
+ for (j = 0; j < group_size[class]; j++)
SET_HARD_REG_BIT (counted_for_groups, i + j);
}
if (asm_noperands (PATTERN (insn)) >= 0)
error_for_asm (insn, "`asm' needs too many reloads");
else
- abort ();
+ fatal_insn ("Unable to find a register to spill.", insn);
}
/* Add a new register to the tables of available spill-registers
{
/* No known place to spill from => no slot to reuse. */
x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size, -1);
-#if BYTES_BIG_ENDIAN
- /* Cancel the big-endian correction done in assign_stack_local.
- Get the address of the beginning of the slot.
- This is so we can do a big-endian correction unconditionally
- below. */
- adjust = inherent_size - total_size;
-#endif
+ if (BYTES_BIG_ENDIAN)
+ /* Cancel the big-endian correction done in assign_stack_local.
+ Get the address of the beginning of the slot.
+ This is so we can do a big-endian correction unconditionally
+ below. */
+ adjust = inherent_size - total_size;
+
+ RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[i]);
}
/* Reuse a stack slot if possible. */
else if (spill_stack_slot[from_reg] != 0
/* Compute maximum size needed, both for inherent size
and for total size. */
enum machine_mode mode = GET_MODE (regno_reg_rtx[i]);
+ rtx stack_slot;
if (spill_stack_slot[from_reg])
{
if (GET_MODE_SIZE (GET_MODE (spill_stack_slot[from_reg]))
}
/* Make a slot with that size. */
x = assign_stack_local (mode, total_size, -1);
-#if BYTES_BIG_ENDIAN
- /* Cancel the big-endian correction done in assign_stack_local.
- Get the address of the beginning of the slot.
- This is so we can do a big-endian correction unconditionally
- below. */
- adjust = GET_MODE_SIZE (mode) - total_size;
-#endif
- spill_stack_slot[from_reg] = x;
+ stack_slot = x;
+ if (BYTES_BIG_ENDIAN)
+ {
+ /* Cancel the big-endian correction done in assign_stack_local.
+ Get the address of the beginning of the slot.
+ This is so we can do a big-endian correction unconditionally
+ below. */
+ adjust = GET_MODE_SIZE (mode) - total_size;
+ if (adjust)
+ stack_slot = gen_rtx (MEM, mode_for_size (total_size
+ * BITS_PER_UNIT,
+ MODE_INT, 1),
+ plus_constant (XEXP (x, 0), adjust));
+ }
+ spill_stack_slot[from_reg] = stack_slot;
spill_stack_slot_width[from_reg] = total_size;
}
-#if BYTES_BIG_ENDIAN
/* On a big endian machine, the "address" of the slot
is the address of the low part that fits its inherent mode. */
- if (inherent_size < total_size)
+ if (BYTES_BIG_ENDIAN && inherent_size < total_size)
adjust += (total_size - inherent_size);
-#endif /* BYTES_BIG_ENDIAN */
/* If we have any adjustment to make, or if the stack slot is the
wrong mode, make a new stack slot. */
/* If this is the product of an eliminable register and a
constant, apply the distribute law and move the constant out
so that we have (plus (mult ..) ..). This is needed in order
- to keep load-address insns valid. This case is pathalogical.
+ to keep load-address insns valid. This case is pathological.
We ignore the possibility of overflow here. */
if (GET_CODE (XEXP (x, 0)) == REG
&& REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
}
/* Fall through to generic unary operation case. */
- case USE:
case STRICT_LOW_PART:
case NEG: case NOT:
case SIGN_EXTEND: case ZERO_EXTEND:
smaller. So leave the SUBREG then. */
&& ! (GET_CODE (SUBREG_REG (x)) == REG
&& GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
- && GET_MODE_SIZE (GET_MODE (new)) <= UNITS_PER_WORD)
+ && GET_MODE_SIZE (GET_MODE (new)) <= UNITS_PER_WORD
+ && (GET_MODE_SIZE (GET_MODE (x))
+ > GET_MODE_SIZE (GET_MODE (new)))
+ && INTEGRAL_MODE_P (GET_MODE (new))
+ && LOAD_EXTEND_OP (GET_MODE (new)) != NIL)
#endif
)
{
int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
enum machine_mode mode = GET_MODE (x);
-#if BYTES_BIG_ENDIAN
- offset += (MIN (UNITS_PER_WORD,
- GET_MODE_SIZE (GET_MODE (new)))
- - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
-#endif
+ if (BYTES_BIG_ENDIAN)
+ offset += (MIN (UNITS_PER_WORD,
+ GET_MODE_SIZE (GET_MODE (new)))
+ - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
PUT_MODE (new, mode);
XEXP (new, 0) = plus_constant (XEXP (new, 0), offset);
return x;
+ case USE:
+ /* If using a register that is the source of an eliminate we still
+ think can be performed, note it cannot be performed since we don't
+ know how this register is used. */
+ for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
+ if (ep->from_rtx == XEXP (x, 0))
+ ep->can_eliminate = 0;
+
+ new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
+ if (new != XEXP (x, 0))
+ return gen_rtx (code, GET_MODE (x), new);
+ return x;
+
case CLOBBER:
/* If clobbering a register that is the replacement register for an
elimination we still think can be performed, note that it cannot
will delete it in reload_as_needed once we know that this
elimination is, in fact, being done.
- If REPLACE isn't set, we can't delete this insn, but neededn't
+ If REPLACE isn't set, we can't delete this insn, but needn't
process it since it won't be used unless something changes. */
if (replace)
delete_dead_insn (insn);
}
done:
- /* If we changed something, perform elmination in REG_NOTES. This is
+ /* If we changed something, perform elimination in REG_NOTES. This is
needed even when REPLACE is zero because a REG_DEAD note might refer
to a register that we eliminate and could cause a different number
of spill registers to be needed in the final reload pass than in
/* We will need to scan everything again. */
something_changed = 1;
if (global)
- retry_global_alloc (i, forbidden_regs);
+ retry_global_alloc (i, forbidden_regs);
alter_reg (i, regno);
if (dumpfile)
Store them in order of decreasing preference in potential_reload_regs. */
static void
-order_regs_for_reload ()
+order_regs_for_reload (global)
+ int global;
{
register int i;
register int o = 0;
{
int lim = regno + HARD_REGNO_NREGS (regno, PSEUDO_REGNO_MODE (i));
while (regno < lim)
- hard_reg_n_uses[regno++].uses += reg_n_refs[i];
+ {
+ /* If allocated by local-alloc, show more uses since
+ we're not going to be able to reallocate it, but
+ we might if allocated by global alloc. */
+ if (global && reg_allocno[i] < 0)
+ hard_reg_n_uses[regno].uses += (reg_n_refs[i] + 1) / 2;
+
+ hard_reg_n_uses[regno++].uses += reg_n_refs[i];
+ }
}
large += reg_n_refs[i];
}
else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
rtx avoid_return_reg = 0;
+ rtx oldpat = PATTERN (insn);
#ifdef SMALL_REGISTER_CLASSES
/* Set avoid_return_reg if this is an insn
&& ! reload_optional[i]
&& (reload_in[i] != 0 || reload_out[i] != 0
|| reload_secondary_p[i] != 0))
- abort ();
+ fatal_insn ("Non-optional registers need a spill register", insn);
/* Now compute which reload regs to reload them into. Perhaps
reusing reload regs from previous insns, or else output
for this insn in order to be stored in
(obeying register constraints). That is correct; such reload
registers ARE still valid. */
- note_stores (PATTERN (insn), forget_old_reloads_1);
+ note_stores (oldpat, forget_old_reloads_1);
/* There may have been CLOBBER insns placed after INSN. So scan
between INSN and NEXT and use them to forget old reloads. */
or -1 if we did not need one of the spill registers for this reload. */
int reload_spill_index[MAX_RELOADS];
-/* Index of last register assigned as a spill register. We allocate in
- a round-robin fashio. */
-
-static int last_spill_reg = 0;
-
/* Find a spill register to use as a reload register for reload R.
LAST_RELOAD is non-zero if this is the last reload for the insn being
processed.
failure:
if (asm_noperands (PATTERN (insn)) < 0)
/* It's the compiler's fault. */
- abort ();
+ fatal_insn ("Could not find a spill register", insn);
/* It's the user's fault; the operand's mode and constraint
don't match. Disable this reload so we don't crash in final. */
rtx output_address_reload_insns[MAX_RECOG_OPERANDS];
rtx operand_reload_insns = 0;
rtx other_operand_reload_insns = 0;
+ rtx other_output_reload_insns = 0;
rtx following_insn = NEXT_INSN (insn);
rtx before_insn = insn;
int special;
{
if (icode != CODE_FOR_nothing)
{
- rtx pat;
-#ifdef SECONDARY_MEMORY_NEEDED
- /* If we need a memory location to do the move, do
- it that way. */
- if (GET_CODE (real_oldequiv) == REG
- && REGNO (real_oldequiv) < FIRST_PSEUDO_REGISTER
- && SECONDARY_MEMORY_NEEDED
- (REGNO_REG_CLASS (REGNO (real_oldequiv)),
- REGNO_REG_CLASS (REGNO (second_reload_reg)),
- GET_MODE (second_reload_reg)))
- {
- /* Get the memory to use and rewrite both
- registers to its mode. */
- rtx loc
- = get_secondary_mem (real_oldequiv,
- GET_MODE (second_reload_reg),
- reload_opnum[j],
- reload_when_needed[j]);
- rtx tmp_reloadreg;
-
- if (GET_MODE (loc)
- != GET_MODE (second_reload_reg))
- second_reload_reg
- = gen_rtx (REG,
- GET_MODE (loc),
- REGNO (second_reload_reg));
-
- if (GET_MODE (loc) != GET_MODE (real_oldequiv))
- tmp_reloadreg = gen_rtx (REG, GET_MODE (loc),
- REGNO (real_oldequiv));
- else
- tmp_reloadreg = real_oldequiv;
-
- emit_move_insn (loc, tmp_reloadreg);
- emit_move_insn (second_reload_reg, loc);
- pat = gen_move_insn (reloadreg, second_reload_reg);
-
- }
- else
-#endif
- pat = GEN_FCN (icode) (reloadreg,
- real_oldequiv,
- second_reload_reg);
- emit_insn (pat);
+ emit_insn (GEN_FCN (icode) (reloadreg, real_oldequiv,
+ second_reload_reg));
special = 1;
}
else
third_reload_reg)));
}
else
- gen_input_reload (second_reload_reg, oldequiv,
- reload_opnum[j],
- reload_when_needed[j]);
+ gen_reload (second_reload_reg, oldequiv,
+ reload_opnum[j],
+ reload_when_needed[j]);
oldequiv = second_reload_reg;
}
#endif
if (! special && ! rtx_equal_p (reloadreg, oldequiv))
- gen_input_reload (reloadreg, oldequiv, reload_opnum[j],
- reload_when_needed[j]);
+ gen_reload (reloadreg, oldequiv, reload_opnum[j],
+ reload_when_needed[j]);
#if defined(SECONDARY_INPUT_RELOAD_CLASS) && defined(PRESERVE_DEATH_INFO_REGNO_P)
/* We may have to make a REG_DEAD note for the secondary reload
XEXP (note, 0) = reload_reg_rtx[j];
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),
+ reload_reg_rtx[j]);
+ 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. */
if (GET_CODE (insn) == JUMP_INSN)
abort ();
- push_to_sequence (output_reload_insns[reload_opnum[j]]);
+ if (reload_when_needed[j] == RELOAD_OTHER)
+ start_sequence ();
+ else
+ push_to_sequence (output_reload_insns[reload_opnum[j]]);
/* Determine the mode to reload in.
See comments above (for input reloading). */
/* VOIDmode should never happen for an output. */
if (asm_noperands (PATTERN (insn)) < 0)
/* It's the compiler's fault. */
- abort ();
+ 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;
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
/* If we need two reload regs, set RELOADREG to the intermediate
- one, since it will be stored into OUT. We might need a secondary
+ one, since it will be stored into OLD. We might need a secondary
register only for an input reload, so check again here. */
if (reload_secondary_out_reload[j] >= 0)
{
/* See if we need both a scratch and intermediate reload
register. */
+
int secondary_reload = reload_secondary_out_reload[j];
enum insn_code tertiary_icode
= reload_secondary_out_icode[secondary_reload];
- rtx pat;
if (GET_MODE (reloadreg) != mode)
reloadreg = gen_rtx (REG, mode, REGNO (reloadreg));
{
rtx third_reloadreg
= reload_reg_rtx[reload_secondary_out_reload[secondary_reload]];
- pat = (GEN_FCN (tertiary_icode)
- (reloadreg, second_reloadreg, third_reloadreg));
- }
-#ifdef SECONDARY_MEMORY_NEEDED
- /* If we need a memory location to do the move, do it that way. */
- else if (GET_CODE (reloadreg) == REG
- && REGNO (reloadreg) < FIRST_PSEUDO_REGISTER
- && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (reloadreg)),
- REGNO_REG_CLASS (REGNO (second_reloadreg)),
- GET_MODE (second_reloadreg)))
- {
- /* Get the memory to use and rewrite both registers
- to its mode. */
- rtx loc
- = get_secondary_mem (reloadreg,
- GET_MODE (second_reloadreg),
- reload_opnum[j],
- reload_when_needed[j]);
- rtx tmp_reloadreg;
-
- if (GET_MODE (loc) != GET_MODE (second_reloadreg))
- second_reloadreg = gen_rtx (REG, GET_MODE (loc),
- REGNO (second_reloadreg));
-
- if (GET_MODE (loc) != GET_MODE (reloadreg))
- tmp_reloadreg = gen_rtx (REG, GET_MODE (loc),
- REGNO (reloadreg));
- else
- tmp_reloadreg = reloadreg;
-
- emit_move_insn (loc, second_reloadreg);
- pat = gen_move_insn (tmp_reloadreg, loc);
+ 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,
+ reload_opnum[j], reload_when_needed[j]);
+ emit_insn ((GEN_FCN (tertiary_icode)
+ (real_old, reloadreg, third_reloadreg)));
+ special = 1;
}
-#endif
+
else
- pat = gen_move_insn (reloadreg, second_reloadreg);
+ /* Copy between the reload regs here and then to
+ OUT later. */
- emit_insn (pat);
+ gen_reload (reloadreg, second_reloadreg,
+ reload_opnum[j], reload_when_needed[j]);
}
}
}
/* Output the last reload insn. */
if (! special)
- {
-#ifdef SECONDARY_MEMORY_NEEDED
- /* If we need a memory location to do the move, do it that way. */
- if (GET_CODE (old) == REG && REGNO (old) < FIRST_PSEUDO_REGISTER
- && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (old)),
- REGNO_REG_CLASS (REGNO (reloadreg)),
- GET_MODE (reloadreg)))
- {
- /* Get the memory to use and rewrite both registers to
- its mode. */
- rtx loc = get_secondary_mem (old, GET_MODE (reloadreg),
- reload_opnum[j],
- reload_when_needed[j]);
-
- if (GET_MODE (loc) != GET_MODE (reloadreg))
- reloadreg = gen_rtx (REG, GET_MODE (loc),
- REGNO (reloadreg));
-
- if (GET_MODE (loc) != GET_MODE (old))
- old = gen_rtx (REG, GET_MODE (loc), REGNO (old));
-
- emit_insn (gen_move_insn (loc, reloadreg));
- emit_insn (gen_move_insn (old, loc));
- }
- else
-#endif
- emit_insn (gen_move_insn (old, reloadreg));
- }
+ gen_reload (old, reloadreg, reload_opnum[j],
+ reload_when_needed[j]);
#ifdef PRESERVE_DEATH_INFO_REGNO_P
/* If final will look at death notes for this reg,
new_spill_reg_store[reload_spill_index[j]] = p;
}
- output_reload_insns[reload_opnum[j]] = get_insns ();
+ if (reload_when_needed[j] == RELOAD_OTHER)
+ {
+ if (other_output_reload_insns)
+ emit_insns (other_output_reload_insns);
+ other_output_reload_insns = get_insns ();
+ }
+ else
+ output_reload_insns[reload_opnum[j]] = get_insns ();
+
end_sequence ();
}
}
RELOAD_FOR_OTHER_ADDRESS reloads for input addresses.
- RELOAD_OTHER reloads.
+ RELOAD_OTHER reloads, output in ascending order by reload number.
For each operand, any RELOAD_FOR_INPUT_ADDRESS reloads followed by
the RELOAD_FOR_INPUT reload for the operand.
After the insn being reloaded, we write the following:
For each operand, any RELOAD_FOR_OUTPUT_ADDRESS reload followed by
- the RELOAD_FOR_OUTPUT reload for that operand. */
+ the RELOAD_FOR_OUTPUT reload for that operand.
+
+ Any RELOAD_OTHER output reloads, output in descending order by
+ reload number. */
emit_insns_before (other_input_address_reload_insns, before_insn);
emit_insns_before (other_input_reload_insns, before_insn);
emit_insns_before (output_reload_insns[j], following_insn);
}
+ emit_insns_before (other_output_reload_insns, following_insn);
+
/* Move death notes from INSN
to output-operand-address and output reload insns. */
#ifdef PRESERVE_DEATH_INFO_REGNO_P
/* I is nonneg if this reload used one of the spill regs.
If reload_reg_rtx[r] is 0, this is an optional reload
- that we opted to ignore.
-
- Also ignore reloads that don't reach the end of the insn,
- since we will eventually see the one that does. */
+ that we opted to ignore. */
- if (i >= 0 && reload_reg_rtx[r] != 0
- && reload_reg_reaches_end_p (spill_regs[i], reload_opnum[r],
- reload_when_needed[r]))
+ if (i >= 0 && reload_reg_rtx[r] != 0)
{
- /* First, clear out memory of what used to be in this spill reg.
- If consecutive registers are used, clear them all. */
int nr
= HARD_REGNO_NREGS (spill_regs[i], GET_MODE (reload_reg_rtx[r]));
int k;
+ int part_reaches_end = 0;
+ int all_reaches_end = 1;
+ /* For a multi register reload, we need to check if all or part
+ of the value lives to the end. */
for (k = 0; k < nr; k++)
{
- reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]] = -1;
- reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = 0;
+ if (reload_reg_reaches_end_p (spill_regs[i] + k, reload_opnum[r],
+ reload_when_needed[r]))
+ part_reaches_end = 1;
+ else
+ all_reaches_end = 0;
}
- /* Maybe the spill reg contains a copy of reload_out. */
- if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
+ /* Ignore reloads that don't reach the end of the insn in
+ entirety. */
+ if (all_reaches_end)
{
- register int nregno = REGNO (reload_out[r]);
- int nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
- : HARD_REGNO_NREGS (nregno,
- GET_MODE (reload_reg_rtx[r])));
-
- spill_reg_store[i] = new_spill_reg_store[i];
- reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+ /* First, clear out memory of what used to be in this spill reg.
+ If consecutive registers are used, clear them all. */
- /* If NREGNO is a hard register, it may occupy more than
- one register. If it does, say what is in the
- rest of the registers assuming that both registers
- agree on how many words the object takes. If not,
- invalidate the subsequent registers. */
-
- if (nregno < FIRST_PSEUDO_REGISTER)
- for (k = 1; k < nnr; k++)
- reg_last_reload_reg[nregno + k]
- = (nr == nnr ? gen_rtx (REG,
- reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
- REGNO (reload_reg_rtx[r]) + k)
- : 0);
-
- /* Now do the inverse operation. */
for (k = 0; k < nr; k++)
{
- reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
- = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr ? nregno
- : nregno + k);
- reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = insn;
+ reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]] = -1;
+ reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = 0;
}
- }
-
- /* Maybe the spill reg contains a copy of reload_in. Only do
- something if there will not be an output reload for
- the register being reloaded. */
- else if (reload_out[r] == 0
- && reload_in[r] != 0
- && ((GET_CODE (reload_in[r]) == REG
- && ! reg_has_output_reload[REGNO (reload_in[r])]
- || (GET_CODE (reload_in_reg[r]) == REG
- && ! reg_has_output_reload[REGNO (reload_in_reg[r])]))))
- {
- register int nregno;
- int nnr;
-
- if (GET_CODE (reload_in[r]) == REG)
- nregno = REGNO (reload_in[r]);
- else
- nregno = REGNO (reload_in_reg[r]);
- nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
- : HARD_REGNO_NREGS (nregno,
- GET_MODE (reload_reg_rtx[r])));
+ /* Maybe the spill reg contains a copy of reload_out. */
+ if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
+ {
+ register int nregno = REGNO (reload_out[r]);
+ int nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
+ : HARD_REGNO_NREGS (nregno,
+ GET_MODE (reload_reg_rtx[r])));
+
+ spill_reg_store[i] = new_spill_reg_store[i];
+ reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+
+ /* If NREGNO is a hard register, it may occupy more than
+ one register. If it does, say what is in the
+ rest of the registers assuming that both registers
+ agree on how many words the object takes. If not,
+ invalidate the subsequent registers. */
+
+ if (nregno < FIRST_PSEUDO_REGISTER)
+ for (k = 1; k < nnr; k++)
+ reg_last_reload_reg[nregno + k]
+ = (nr == nnr
+ ? gen_rtx (REG,
+ reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
+ REGNO (reload_reg_rtx[r]) + k)
+ : 0);
+
+ /* Now do the inverse operation. */
+ for (k = 0; k < nr; k++)
+ {
+ reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
+ = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
+ ? nregno
+ : nregno + k);
+ reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = insn;
+ }
+ }
- reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+ /* Maybe the spill reg contains a copy of reload_in. Only do
+ something if there will not be an output reload for
+ the register being reloaded. */
+ else if (reload_out[r] == 0
+ && reload_in[r] != 0
+ && ((GET_CODE (reload_in[r]) == REG
+ && ! reg_has_output_reload[REGNO (reload_in[r])])
+ || (GET_CODE (reload_in_reg[r]) == REG
+ && ! reg_has_output_reload[REGNO (reload_in_reg[r])])))
+ {
+ register int nregno;
+ int nnr;
- if (nregno < FIRST_PSEUDO_REGISTER)
- for (k = 1; k < nnr; k++)
- reg_last_reload_reg[nregno + k]
- = (nr == nnr ? gen_rtx (REG,
- reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
- REGNO (reload_reg_rtx[r]) + k)
- : 0);
+ if (GET_CODE (reload_in[r]) == REG)
+ nregno = REGNO (reload_in[r]);
+ else
+ nregno = REGNO (reload_in_reg[r]);
- /* Unless we inherited this reload, show we haven't
- recently done a store. */
- if (! reload_inherited[r])
- spill_reg_store[i] = 0;
+ nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
+ : HARD_REGNO_NREGS (nregno,
+ GET_MODE (reload_reg_rtx[r])));
+
+ reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+
+ if (nregno < FIRST_PSEUDO_REGISTER)
+ for (k = 1; k < nnr; k++)
+ reg_last_reload_reg[nregno + k]
+ = (nr == nnr
+ ? gen_rtx (REG,
+ reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
+ REGNO (reload_reg_rtx[r]) + k)
+ : 0);
+
+ /* Unless we inherited this reload, show we haven't
+ recently done a store. */
+ if (! reload_inherited[r])
+ spill_reg_store[i] = 0;
+
+ for (k = 0; k < nr; k++)
+ {
+ reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
+ = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
+ ? nregno
+ : nregno + k);
+ reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]]
+ = insn;
+ }
+ }
+ }
+ /* However, if part of the reload reaches the end, then we must
+ invalidate the old info for the part that survives to the end. */
+ else if (part_reaches_end)
+ {
for (k = 0; k < nr; k++)
- {
- reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
- = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr ? nregno
- : nregno + k);
- reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]]
- = insn;
- }
+ if (reload_reg_reaches_end_p (spill_regs[i] + k,
+ reload_opnum[r],
+ reload_when_needed[r]))
+ {
+ reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]] = -1;
+ reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = 0;
+ }
}
}
if (i < 0 && reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
{
register int nregno = REGNO (reload_out[r]);
- int num_regs = HARD_REGNO_NREGS (nregno, GET_MODE (reload_out[r]));
+ if (nregno >= FIRST_PSEUDO_REGISTER)
+ reg_last_reload_reg[nregno] = 0;
+ else
+ {
+ int num_regs = HARD_REGNO_NREGS (nregno,GET_MODE (reload_out[r]));
- while (num_regs-- > 0)
- reg_last_reload_reg[nregno + num_regs] = 0;
+ while (num_regs-- > 0)
+ reg_last_reload_reg[nregno + num_regs] = 0;
+ }
}
}
}
\f
-/* Emit code to perform an input reload of IN to RELOADREG. IN is from
- operand OPNUM with reload type TYPE.
+/* Emit code to perform a reload from IN (which may be a reload register) to
+ OUT (which may also be a reload register). IN or OUT is from operand
+ OPNUM with reload type TYPE.
Returns first insn emitted. */
rtx
-gen_input_reload (reloadreg, in, opnum, type)
- rtx reloadreg;
+gen_reload (out, in, opnum, type)
+ rtx out;
rtx in;
int opnum;
enum reload_type type;
{
rtx last = get_last_insn ();
+ rtx tem;
+
+ /* If IN is a paradoxical SUBREG, remove it and try to put the
+ opposite SUBREG on OUT. Likewise for a paradoxical SUBREG on OUT. */
+ if (GET_CODE (in) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (in))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
+ && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (in)), out)) != 0)
+ in = SUBREG_REG (in), out = tem;
+ else if (GET_CODE (out) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (out))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
+ && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (out)), in)) != 0)
+ out = SUBREG_REG (out), in = tem;
/* How to do this reload can get quite tricky. Normally, we are being
asked to reload a simple operand, such as a MEM, a constant, or a pseudo
it will be A = A + B as constrain_operands expects. */
if (GET_CODE (XEXP (in, 1)) == REG
- && REGNO (reloadreg) == REGNO (XEXP (in, 1)))
+ && REGNO (out) == REGNO (XEXP (in, 1)))
tem = op0, op0 = op1, op1 = tem;
if (op0 != XEXP (in, 0) || op1 != XEXP (in, 1))
in = gen_rtx (PLUS, GET_MODE (in), op0, op1);
- insn = emit_insn (gen_rtx (SET, VOIDmode, reloadreg, in));
+ insn = emit_insn (gen_rtx (SET, VOIDmode, out, in));
code = recog_memoized (insn);
if (code >= 0)
&& REGNO (op1) >= FIRST_PSEUDO_REGISTER))
tem = op0, op0 = op1, op1 = tem;
- emit_insn (gen_move_insn (reloadreg, op0));
+ emit_insn (gen_move_insn (out, op0));
- /* If OP0 and OP1 are the same, we can use RELOADREG for OP1.
+ /* If OP0 and OP1 are the same, we can use OUT for OP1.
This fixes a problem on the 32K where the stack pointer cannot
be used as an operand of an add insn. */
if (rtx_equal_p (op0, op1))
- op1 = reloadreg;
+ op1 = out;
- insn = emit_insn (gen_add2_insn (reloadreg, op1));
+ insn = emit_insn (gen_add2_insn (out, op1));
/* If that failed, copy the address register to the reload register.
Then add the constant to the reload register. */
delete_insns_since (last);
- emit_insn (gen_move_insn (reloadreg, op1));
- emit_insn (gen_add2_insn (reloadreg, op0));
+ emit_insn (gen_move_insn (out, op1));
+ emit_insn (gen_add2_insn (out, op0));
}
#ifdef SECONDARY_MEMORY_NEEDED
/* If we need a memory location to do the move, do it that way. */
else if (GET_CODE (in) == REG && REGNO (in) < FIRST_PSEUDO_REGISTER
+ && GET_CODE (out) == REG && REGNO (out) < FIRST_PSEUDO_REGISTER
&& SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)),
- REGNO_REG_CLASS (REGNO (reloadreg)),
- GET_MODE (reloadreg)))
+ REGNO_REG_CLASS (REGNO (out)),
+ GET_MODE (out)))
{
/* Get the memory to use and rewrite both registers to its mode. */
- rtx loc = get_secondary_mem (in, GET_MODE (reloadreg), opnum, type);
+ rtx loc = get_secondary_mem (in, GET_MODE (out), opnum, type);
- if (GET_MODE (loc) != GET_MODE (reloadreg))
- reloadreg = gen_rtx (REG, GET_MODE (loc), REGNO (reloadreg));
+ if (GET_MODE (loc) != GET_MODE (out))
+ out = gen_rtx (REG, GET_MODE (loc), REGNO (out));
if (GET_MODE (loc) != GET_MODE (in))
in = gen_rtx (REG, GET_MODE (loc), REGNO (in));
emit_insn (gen_move_insn (loc, in));
- emit_insn (gen_move_insn (reloadreg, loc));
+ emit_insn (gen_move_insn (out, loc));
}
#endif
/* If IN is a simple operand, use gen_move_insn. */
else if (GET_RTX_CLASS (GET_CODE (in)) == 'o' || GET_CODE (in) == SUBREG)
- emit_insn (gen_move_insn (reloadreg, in));
+ emit_insn (gen_move_insn (out, in));
#ifdef HAVE_reload_load_address
else if (HAVE_reload_load_address)
- emit_insn (gen_reload_load_address (reloadreg, in));
+ emit_insn (gen_reload_load_address (out, in));
#endif
- /* Otherwise, just write (set REGLOADREG IN) and hope for the best. */
+ /* Otherwise, just write (set OUT IN) and hope for the best. */
else
- emit_insn (gen_rtx (SET, VOIDmode, reloadreg, in));
+ emit_insn (gen_rtx (SET, VOIDmode, out, in));
/* Return the first insn emitted.
We can not just return get_last_insn, because there may have
emit_insn (gen_move_insn (reloadreg, incloc));
/* See if we can directly increment INCLOC. Use a method similar to that
- in gen_input_reload. */
+ in gen_reload. */
last = get_last_insn ();
add_insn = emit_insn (gen_rtx (SET, VOIDmode, incloc,