/* Search an insn for pseudo regs that must be in hard regs and are not.
- Copyright (C) 1987, 88, 89, 92-98, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
: (type)))
#ifdef HAVE_SECONDARY_RELOADS
-static int push_secondary_reload PROTO((int, rtx, int, int, enum reg_class,
+static int push_secondary_reload PARAMS ((int, rtx, int, int, enum reg_class,
enum machine_mode, enum reload_type,
enum insn_code *));
#endif
-static enum reg_class find_valid_class PROTO((enum machine_mode, int));
-static int push_reload PROTO((rtx, rtx, rtx *, rtx *, enum reg_class,
+static enum reg_class find_valid_class PARAMS ((enum machine_mode, int));
+static int push_reload PARAMS ((rtx, rtx, rtx *, rtx *, enum reg_class,
enum machine_mode, enum machine_mode,
int, int, int, enum reload_type));
-static void push_replacement PROTO((rtx *, int, enum machine_mode));
-static void combine_reloads PROTO((void));
-static int find_reusable_reload PROTO((rtx *, rtx, enum reg_class,
+static void push_replacement PARAMS ((rtx *, int, enum machine_mode));
+static void combine_reloads PARAMS ((void));
+static int find_reusable_reload PARAMS ((rtx *, rtx, enum reg_class,
enum reload_type, int, int));
-static rtx find_dummy_reload PROTO((rtx, rtx, rtx *, rtx *,
+static rtx find_dummy_reload PARAMS ((rtx, rtx, rtx *, rtx *,
enum machine_mode, enum machine_mode,
enum reg_class, int, int));
-static int earlyclobber_operand_p PROTO((rtx));
-static int hard_reg_set_here_p PROTO((int, int, rtx));
-static struct decomposition decompose PROTO((rtx));
-static int immune_p PROTO((rtx, rtx, struct decomposition));
-static int alternative_allows_memconst PROTO((const char *, int));
-static rtx find_reloads_toplev PROTO((rtx, int, enum reload_type, int, int, rtx));
-static rtx make_memloc PROTO((rtx, int));
-static int find_reloads_address PROTO((enum machine_mode, rtx *, rtx, rtx *,
+static int hard_reg_set_here_p PARAMS ((unsigned int, unsigned int, rtx));
+static struct decomposition decompose PARAMS ((rtx));
+static int immune_p PARAMS ((rtx, rtx, struct decomposition));
+static int alternative_allows_memconst PARAMS ((const char *, int));
+static rtx find_reloads_toplev PARAMS ((rtx, int, enum reload_type, int,
+ int, rtx));
+static rtx make_memloc PARAMS ((rtx, int));
+static int find_reloads_address PARAMS ((enum machine_mode, rtx *, rtx, rtx *,
int, enum reload_type, int, rtx));
-static rtx subst_reg_equivs PROTO((rtx, rtx));
-static rtx subst_indexed_address PROTO((rtx));
-static int find_reloads_address_1 PROTO((enum machine_mode, rtx, int, rtx *,
+static rtx subst_reg_equivs PARAMS ((rtx, rtx));
+static rtx subst_indexed_address PARAMS ((rtx));
+static int find_reloads_address_1 PARAMS ((enum machine_mode, rtx, int, rtx *,
int, enum reload_type,int, rtx));
-static void find_reloads_address_part PROTO((rtx, rtx *, enum reg_class,
+static void find_reloads_address_part PARAMS ((rtx, rtx *, enum reg_class,
enum machine_mode, int,
enum reload_type, int));
-static rtx find_reloads_subreg_address PROTO((rtx, int, int, enum reload_type,
+static rtx find_reloads_subreg_address PARAMS ((rtx, int, int, enum reload_type,
int, rtx));
-static int find_inc_amount PROTO((rtx, rtx));
-static int loc_mentioned_in_p PROTO((rtx *, rtx));
-extern void debug_reload_to_stream PROTO((FILE *));
-extern void debug_reload PROTO((void));
+static int find_inc_amount PARAMS ((rtx, rtx));
+static int loc_mentioned_in_p PARAMS ((rtx *, rtx));
+extern void debug_reload_to_stream PARAMS ((FILE *));
+extern void debug_reload PARAMS ((void));
\f
#ifdef HAVE_SECONDARY_RELOADS
rld[t_reload].outmode = ! in_p ? t_mode : VOIDmode;
rld[t_reload].reg_rtx = 0;
rld[t_reload].optional = optional;
- rld[t_reload].nongroup = 0;
rld[t_reload].inc = 0;
/* Maybe we could combine these, but it seems too tricky. */
rld[t_reload].nocombine = 1;
rld[s_reload].outmode = ! in_p ? mode : VOIDmode;
rld[s_reload].reg_rtx = 0;
rld[s_reload].optional = optional;
- rld[s_reload].nongroup = 0;
rld[s_reload].inc = 0;
/* Maybe we could combine these, but it seems too tricky. */
rld[s_reload].nocombine = 1;
static enum reg_class
find_valid_class (m1, n)
- enum machine_mode m1;
+ enum machine_mode m1 ATTRIBUTE_UNUSED;
int n;
{
int class;
int regno;
enum reg_class best_class = NO_REGS;
- int best_size = 0;
+ unsigned int best_size = 0;
for (class = 1; class < N_REG_CLASSES; class++)
{
rld[i].outmode = outmode;
rld[i].reg_rtx = 0;
rld[i].optional = optional;
- rld[i].nongroup = 0;
rld[i].inc = 0;
rld[i].nocombine = 0;
rld[i].in_reg = inloc ? *inloc : 0;
&& GET_MODE_SIZE (inmode) <= GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
&& HARD_REGNO_MODE_OK (regno, inmode)
&& GET_MODE_SIZE (outmode) <= GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
- && HARD_REGNO_MODE_OK (regno, outmode)
- && TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno)
- && !fixed_regs[regno])
+ && HARD_REGNO_MODE_OK (regno, outmode))
{
- rld[i].reg_rtx = gen_rtx_REG (inmode, regno);
- break;
+ int offs;
+ int nregs = HARD_REGNO_NREGS (regno, inmode);
+ for (offs = 0; offs < nregs; offs++)
+ if (fixed_regs[regno + offs]
+ || ! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
+ regno + offs))
+ break;
+
+ if (offs == nregs)
+ {
+ rld[i].reg_rtx = gen_rtx_REG (inmode, regno);
+ break;
+ }
}
}
if (GET_CODE (out) == REG
&& REGNO (out) < FIRST_PSEUDO_REGISTER)
{
- register int regno = REGNO (out) + out_offset;
- int nwords = HARD_REGNO_NREGS (regno, outmode);
+ unsigned int regno = REGNO (out) + out_offset;
+ unsigned int nwords = HARD_REGNO_NREGS (regno, outmode);
rtx saved_rtx;
/* When we consider whether the insn uses OUT,
*inloc = const0_rtx;
if (regno < FIRST_PSEUDO_REGISTER
- /* A fixed reg that can overlap other regs better not be used
- for reloading in any way. */
-#ifdef OVERLAPPING_REGNO_P
- && ! (fixed_regs[regno] && OVERLAPPING_REGNO_P (regno))
-#endif
&& ! refers_to_regno_for_reload_p (regno, regno + nwords,
PATTERN (this_insn), outloc))
{
- int i;
+ unsigned int i;
+
for (i = 0; i < nwords; i++)
if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
regno + i))
(GET_MODE (out) != VOIDmode
? GET_MODE (out) : outmode)))
{
- register int regno = REGNO (in) + in_offset;
- int nwords = HARD_REGNO_NREGS (regno, inmode);
+ unsigned int regno = REGNO (in) + in_offset;
+ unsigned int nwords = HARD_REGNO_NREGS (regno, inmode);
if (! refers_to_regno_for_reload_p (regno, regno + nwords, out, NULL_PTR)
&& ! hard_reg_set_here_p (regno, regno + nwords,
|| ! refers_to_regno_for_reload_p (regno, regno + nwords,
PATTERN (this_insn), inloc)))
{
- int i;
+ unsigned int i;
+
for (i = 0; i < nwords; i++)
if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
regno + i))
/* Return 1 if X is an operand of an insn that is being earlyclobbered. */
-static int
+int
earlyclobber_operand_p (x)
rtx x;
{
static int
hard_reg_set_here_p (beg_regno, end_regno, x)
- register int beg_regno, end_regno;
+ unsigned int beg_regno, end_regno;
rtx x;
{
if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
{
register rtx op0 = SET_DEST (x);
+
while (GET_CODE (op0) == SUBREG)
op0 = SUBREG_REG (op0);
if (GET_CODE (op0) == REG)
{
- register int r = REGNO (op0);
+ unsigned int r = REGNO (op0);
+
/* See if this reg overlaps range under consideration. */
if (r < end_regno
&& r + HARD_REGNO_NREGS (r, GET_MODE (op0)) > beg_regno)
else if (GET_CODE (x) == PARALLEL)
{
register int i = XVECLEN (x, 0) - 1;
+
for (; i >= 0; i--)
if (hard_reg_set_here_p (beg_regno, end_regno, XVECEXP (x, 0, i)))
return 1;
int
strict_memory_address_p (mode, addr)
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
register rtx addr;
{
GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
int swapped;
int goal_alternative[MAX_RECOG_OPERANDS];
int this_alternative_number;
- int goal_alternative_number;
+ int goal_alternative_number = 0;
int operand_reloadnum[MAX_RECOG_OPERANDS];
int goal_alternative_matches[MAX_RECOG_OPERANDS];
int goal_alternative_matched[MAX_RECOG_OPERANDS];
int goal_alternative_swapped;
int best;
int commutative;
- int changed;
char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
rtx substed_operand[MAX_RECOG_OPERANDS];
rtx body = PATTERN (insn);
rtx set = single_set (insn);
- int goal_earlyclobber, this_earlyclobber;
+ int goal_earlyclobber = 0, this_earlyclobber;
enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
int retval = 0;
&& reg_alternate_class (REGNO (recog_data.operand[i])) == NO_REGS);
}
-#ifdef HAVE_cc0
- /* If we made any reloads for addresses, see if they violate a
- "no input reloads" requirement for this insn. */
- if (no_input_reloads)
- for (i = 0; i < n_reloads; i++)
- if (rld[i].in != 0)
- abort ();
-#endif
-
/* If this is simply a copy from operand 1 to operand 0, merge the
preferred classes for the operands. */
if (set != 0 && noperands >= 2 && recog_data.operand[0] == SET_DEST (set)
{
for (i = 0; i < n_reloads; i++)
{
- int first_num, type;
+ int first_num;
+ enum reload_type type;
switch (rld[i].when_needed)
{
rld[j].in = 0;
}
- /* Set which reloads must use registers not used in any group. Start
- with those that conflict with a group and then include ones that
- conflict with ones that are already known to conflict with a group. */
+#ifdef HAVE_cc0
+ /* If we made any reloads for addresses, see if they violate a
+ "no input reloads" requirement for this insn. But loads that we
+ do after the insn (such as for output addresses) are fine. */
+ if (no_input_reloads)
+ for (i = 0; i < n_reloads; i++)
+ if (rld[i].in != 0
+ && rld[i].when_needed != RELOAD_FOR_OUTADDR_ADDRESS
+ && rld[i].when_needed != RELOAD_FOR_OUTPUT_ADDRESS)
+ abort ();
+#endif
- changed = 0;
+ /* Compute reload_mode and reload_nregs. */
for (i = 0; i < n_reloads; i++)
{
- enum machine_mode mode = rld[i].inmode;
- enum reg_class class = rld[i].class;
- int size;
-
- if (GET_MODE_SIZE (rld[i].outmode) > GET_MODE_SIZE (mode))
- mode = rld[i].outmode;
- size = CLASS_MAX_NREGS (class, mode);
-
- if (size == 1)
- for (j = 0; j < n_reloads; j++)
- if ((CLASS_MAX_NREGS (rld[j].class,
- (GET_MODE_SIZE (rld[j].outmode)
- > GET_MODE_SIZE (rld[j].inmode))
- ? rld[j].outmode : rld[j].inmode)
- > 1)
- && !rld[j].optional
- && (rld[j].in != 0 || rld[j].out != 0
- || rld[j].secondary_p)
- && reloads_conflict (i, j)
- && reg_classes_intersect_p (class, rld[j].class))
- {
- rld[i].nongroup = 1;
- changed = 1;
- break;
- }
- }
-
- while (changed)
- {
- changed = 0;
+ rld[i].mode
+ = (rld[i].inmode == VOIDmode
+ || (GET_MODE_SIZE (rld[i].outmode)
+ > GET_MODE_SIZE (rld[i].inmode)))
+ ? rld[i].outmode : rld[i].inmode;
- for (i = 0; i < n_reloads; i++)
- {
- enum machine_mode mode = rld[i].inmode;
- enum reg_class class = rld[i].class;
- int size;
-
- if (GET_MODE_SIZE (rld[i].outmode) > GET_MODE_SIZE (mode))
- mode = rld[i].outmode;
- size = CLASS_MAX_NREGS (class, mode);
-
- if (! rld[i].nongroup && size == 1)
- for (j = 0; j < n_reloads; j++)
- if (rld[j].nongroup
- && reloads_conflict (i, j)
- && reg_classes_intersect_p (class, rld[j].class))
- {
- rld[i].nongroup = 1;
- changed = 1;
- break;
- }
- }
+ rld[i].nregs = CLASS_MAX_NREGS (rld[i].class, rld[i].mode);
}
return retval;
that the index needs a reload and find_reloads_address_1 will take care
of it.
- There is still a case when we might generate an extra reload,
- however. In certain cases eliminate_regs will return a MEM for a REG
- (see the code there for details). In those cases, memory_address_p
- applied to our address will return 0 so we will think that our offset
- must be too large. But it might indeed be valid and the only problem
- is that a MEM is present where a REG should be. This case should be
- very rare and there doesn't seem to be any way to avoid it.
-
If we decide to do something here, it must be that
`double_reg_address_ok' is true and that this address rtl was made by
eliminate_regs. We generate a reload of the fp/sp/ap + constant and
int
refers_to_regno_for_reload_p (regno, endregno, x, loc)
- int regno, endregno;
+ unsigned int regno, endregno;
rtx x;
rtx *loc;
{
- register int i;
- register RTX_CODE code;
- register const char *fmt;
+ int i;
+ unsigned int r;
+ RTX_CODE code;
+ const char *fmt;
if (x == 0)
return 0;
switch (code)
{
case REG:
- i = REGNO (x);
+ r = REGNO (x);
/* If this is a pseudo, a hard register must not have been allocated.
X must therefore either be a constant or be in memory. */
- if (i >= FIRST_PSEUDO_REGISTER)
+ if (r >= FIRST_PSEUDO_REGISTER)
{
- if (reg_equiv_memory_loc[i])
+ if (reg_equiv_memory_loc[r])
return refers_to_regno_for_reload_p (regno, endregno,
- reg_equiv_memory_loc[i],
+ reg_equiv_memory_loc[r],
NULL_PTR);
- if (reg_equiv_constant[i])
+ if (reg_equiv_constant[r])
return 0;
abort ();
}
- return (endregno > i
- && regno < i + (i < FIRST_PSEUDO_REGISTER
- ? HARD_REGNO_NREGS (i, GET_MODE (x))
+ return (endregno > r
+ && regno < r + (r < FIRST_PSEUDO_REGISTER
+ ? HARD_REGNO_NREGS (r, GET_MODE (x))
: 1));
case SUBREG:
if (GET_CODE (SUBREG_REG (x)) == REG
&& REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
{
- int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
- int inner_endregno
+ unsigned int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
+ unsigned int inner_endregno
= inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
else
return 0;
- /* On some machines, certain regs must always be rejected
- because they don't behave the way ordinary registers do. */
-
-#ifdef OVERLAPPING_REGNO_P
- if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER
- && OVERLAPPING_REGNO_P (regno))
- return 0;
-#endif
-
/* Scan insns back from INSN, looking for one that copies
a value into or out of GOAL.
Stop and give up if we reach a label. */
p = PREV_INSN (p);
if (p == 0 || GET_CODE (p) == CODE_LABEL)
return 0;
+
if (GET_CODE (p) == INSN
/* If we don't want spill regs ... */
&& (! (reload_reg_p != 0
&& reload_reg_p != (short *) (HOST_WIDE_INT) 1)
- /* ... then ignore insns introduced by reload; they aren't useful
- and can cause results in reload_as_needed to be different
- from what they were when calculating the need for spills.
- If we notice an input-reload insn here, we will reject it below,
- but it might hide a usable equivalent. That makes bad code.
- It may even abort: perhaps no reg was spilled for this insn
- because it was assumed we would find that equivalent. */
+ /* ... then ignore insns introduced by reload; they aren't
+ useful and can cause results in reload_as_needed to be
+ different from what they were when calculating the need for
+ spills. If we notice an input-reload insn here, we will
+ reject it below, but it might hide a usable equivalent.
+ That makes bad code. It may even abort: perhaps no reg was
+ spilled for this insn because it was assumed we would find
+ that equivalent. */
|| INSN_UID (p) < reload_first_uid))
{
rtx tem;
pat = single_set (p);
+
/* First check for something that sets some reg equal to GOAL. */
if (pat != 0
&& ((regno >= 0
/* Reject registers that overlap GOAL. */
if (!goal_mem && !goal_const
- && regno + HARD_REGNO_NREGS (regno, mode) > valueno
- && regno < valueno + HARD_REGNO_NREGS (valueno, mode))
+ && regno + (int) HARD_REGNO_NREGS (regno, mode) > valueno
+ && regno < valueno + (int) HARD_REGNO_NREGS (valueno, mode))
return 0;
/* Reject VALUE if it is one of the regs reserved for reloads.
&& reload_reg_p[valueno] >= 0)
return 0;
- /* On some machines, certain regs must always be rejected
- because they don't behave the way ordinary registers do. */
-
-#ifdef OVERLAPPING_REGNO_P
- if (OVERLAPPING_REGNO_P (valueno))
- return 0;
-#endif
-
nregs = HARD_REGNO_NREGS (regno, mode);
valuenregs = HARD_REGNO_NREGS (valueno, mode);
return 0;
#endif
-#ifdef INSN_CLOBBERS_REGNO_P
- if ((valueno >= 0 && valueno < FIRST_PSEUDO_REGISTER
- && INSN_CLOBBERS_REGNO_P (p, valueno))
- || (regno >= 0 && regno < FIRST_PSEUDO_REGISTER
- && INSN_CLOBBERS_REGNO_P (p, regno)))
- return 0;
-#endif
-
if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
{
pat = PATTERN (p);
int
regno_clobbered_p (regno, insn)
- int regno;
+ unsigned int regno;
rtx insn;
{
if (GET_CODE (PATTERN (insn)) == CLOBBER