/* 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, 93, 94, 1995 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];
+/* 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.
\f
static int possible_group_p PROTO((int, int *));
static void count_possible_groups PROTO((int *, enum machine_mode *,
- int *));
+ int *, int));
static int modes_equiv_for_class_p PROTO((enum machine_mode,
enum machine_mode,
enum reg_class));
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
/* If any single spilled regs happen to form groups,
count them now. Maybe we don't really need
to spill another group. */
- count_possible_groups (group_size, group_mode, max_groups);
+ count_possible_groups (group_size, group_mode, max_groups,
+ class);
if (max_groups[class] <= 0)
break;
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;
}
}
return 0;
}
\f
-/* Count any groups that can be formed from the registers recently spilled.
- This is done class by class, in order of ascending class number. */
+/* Count any groups of CLASS that can be formed from the registers recently
+ spilled. */
static void
-count_possible_groups (group_size, group_mode, max_groups)
+count_possible_groups (group_size, group_mode, max_groups, class)
int *group_size;
enum machine_mode *group_mode;
int *max_groups;
+ int class;
{
- int i;
+ HARD_REG_SET new;
+ int i, j;
+
/* Now find all consecutive groups of spilled registers
and mark each group off against the need for such groups.
But don't count them against ordinary need, yet. */
- for (i = 0; i < N_REG_CLASSES; i++)
- if (group_size[i] > 1)
+ if (group_size[class] == 0)
+ return;
+
+ CLEAR_HARD_REG_SET (new);
+
+ /* Make a mask of all the regs that are spill regs in class I. */
+ for (i = 0; i < n_spills; i++)
+ if (TEST_HARD_REG_BIT (reg_class_contents[class], spill_regs[i])
+ && ! TEST_HARD_REG_BIT (counted_for_groups, spill_regs[i])
+ && ! TEST_HARD_REG_BIT (counted_for_nongroups, spill_regs[i]))
+ SET_HARD_REG_BIT (new, spill_regs[i]);
+
+ /* Find each consecutive group of them. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER && max_groups[class] > 0; i++)
+ if (TEST_HARD_REG_BIT (new, i)
+ && i + group_size[class] <= FIRST_PSEUDO_REGISTER
+ && HARD_REGNO_MODE_OK (i, group_mode[class]))
{
- HARD_REG_SET new;
- int j;
-
- CLEAR_HARD_REG_SET (new);
-
- /* Make a mask of all the regs that are spill regs in class I. */
- for (j = 0; j < n_spills; j++)
- if (TEST_HARD_REG_BIT (reg_class_contents[i], spill_regs[j])
- && ! TEST_HARD_REG_BIT (counted_for_groups, spill_regs[j])
- && ! TEST_HARD_REG_BIT (counted_for_nongroups,
- spill_regs[j]))
- SET_HARD_REG_BIT (new, spill_regs[j]);
-
- /* Find each consecutive group of them. */
- for (j = 0; j < FIRST_PSEUDO_REGISTER && max_groups[i] > 0; j++)
- if (TEST_HARD_REG_BIT (new, j)
- && j + group_size[i] <= FIRST_PSEUDO_REGISTER
- /* Next line in case group-mode for this class
- demands an even-odd pair. */
- && HARD_REGNO_MODE_OK (j, group_mode[i]))
- {
- int k;
- for (k = 1; k < group_size[i]; k++)
- if (! TEST_HARD_REG_BIT (new, j + k))
- break;
- if (k == group_size[i])
- {
- /* We found a group. Mark it off against this class's
- need for groups, and against each superclass too. */
- register enum reg_class *p;
- max_groups[i]--;
- p = reg_class_superclasses[i];
- while (*p != LIM_REG_CLASSES)
- max_groups[(int) *p++]--;
- /* Don't count these registers again. */
- for (k = 0; k < group_size[i]; k++)
- SET_HARD_REG_BIT (counted_for_groups, j + k);
- }
- /* Skip to the last reg in this group. When j is incremented
- above, it will then point to the first reg of the next
- possible group. */
- j += k - 1;
- }
- }
+ for (j = 1; j < group_size[class]; j++)
+ if (! TEST_HARD_REG_BIT (new, i + j))
+ break;
+
+ if (j == group_size[class])
+ {
+ /* We found a group. Mark it off against this class's need for
+ groups, and against each superclass too. */
+ register enum reg_class *p;
+
+ max_groups[class]--;
+ p = reg_class_superclasses[class];
+ while (*p != LIM_REG_CLASSES)
+ {
+ 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[class]; j++)
+ SET_HARD_REG_BIT (counted_for_groups, i + j);
+ }
+ /* Skip to the last reg in this group. When i is incremented above,
+ it will then point to the first reg of the next possible group. */
+ i += j - 1;
+ }
}
\f
/* ALLOCATE_MODE is a register mode that needs to be reloaded. OTHER_MODE is
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
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);
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
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;
{
register rtx old;
rtx oldequiv_reg = 0;
- rtx store_insn = 0;
+
+ if (reload_spill_index[j] >= 0)
+ new_spill_reg_store[reload_spill_index[j]] = 0;
old = reload_in[j];
if (old != 0 && ! reload_inherited[j]
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)
+ push_to_sequence (other_output_reload_insns);
+ 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,
reg_has_output_reload will make this do nothing. */
note_stores (PATTERN (p), forget_old_reloads_1);
- if (reg_mentioned_p (reload_reg_rtx[j], PATTERN (p)))
- store_insn = p;
+ if (reg_mentioned_p (reload_reg_rtx[j], PATTERN (p))
+ && reload_spill_index[j] >= 0)
+ new_spill_reg_store[reload_spill_index[j]] = p;
}
- output_reload_insns[reload_opnum[j]] = get_insns ();
- end_sequence ();
+ if (reload_when_needed[j] == RELOAD_OTHER)
+ other_output_reload_insns = get_insns ();
+ else
+ output_reload_insns[reload_opnum[j]] = get_insns ();
+ end_sequence ();
}
-
- if (reload_spill_index[j] >= 0)
- new_spill_reg_store[reload_spill_index[j]] = store_insn;
}
/* Now write all the insns we made for reloads in the order expected by
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. */
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
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,