/* Search an insn for pseudo regs that must be in hard regs and are not.
- Copyright (C) 1987, 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92, 93, 1994 Free Software Foundation, Inc.
This file is part of GNU CC.
for addressing a non-reloaded mem ref,
or for unspecified purposes (i.e., more than one
of the above).
- reload_secondary_reload int, gives the reload number of a secondary
- reload, when needed; otherwise -1
reload_secondary_p int, 1 if this is a secondary register for one
- or more reloads.
- reload_secondary_icode enum insn_code, if a secondary reload is required,
+ or more reloads.
+ reload_secondary_in_reload
+ reload_secondary_out_reload
+ int, gives the reload number of a secondary
+ reload, when needed; otherwise -1
+ reload_secondary_in_icode
+ reload_secondary_out_icode
+ enum insn_code, if a secondary reload is required,
gives the INSN_CODE that uses the secondary
reload as a scratch register, or CODE_FOR_nothing
if the secondary reload register is to be an
char reload_nocombine[MAX_RELOADS];
int reload_opnum[MAX_RELOADS];
enum reload_type reload_when_needed[MAX_RELOADS];
-int reload_secondary_reload[MAX_RELOADS];
int reload_secondary_p[MAX_RELOADS];
-enum insn_code reload_secondary_icode[MAX_RELOADS];
+int reload_secondary_in_reload[MAX_RELOADS];
+int reload_secondary_out_reload[MAX_RELOADS];
+enum insn_code reload_secondary_in_icode[MAX_RELOADS];
+enum insn_code reload_secondary_out_icode[MAX_RELOADS];
/* All the "earlyclobber" operands of the current insn
are recorded here. */
operand, which can be different for that from the input operand. */
static int output_reloadnum;
-static enum reg_class find_secondary_reload PROTO((rtx, enum reg_class,
- enum machine_mode, int,
- enum insn_code *,
- enum machine_mode *,
- enum reg_class *,
- enum insn_code *,
- enum machine_mode *));
+ /* Compare two RTX's. */
+#define MATCHES(x, y) \
+ (x == y || (x != 0 && (GET_CODE (x) == REG \
+ ? GET_CODE (y) == REG && REGNO (x) == REGNO (y) \
+ : rtx_equal_p (x, y) && ! side_effects_p (x))))
+
+ /* Indicates if two reloads purposes are for similar enough things that we
+ can merge their reloads. */
+#define MERGABLE_RELOADS(when1, when2, op1, op2) \
+ ((when1) == RELOAD_OTHER || (when2) == RELOAD_OTHER \
+ || ((when1) == (when2) && (op1) == (op2)) \
+ || ((when1) == RELOAD_FOR_INPUT && (when2) == RELOAD_FOR_INPUT) \
+ || ((when1) == RELOAD_FOR_OPERAND_ADDRESS \
+ && (when2) == RELOAD_FOR_OPERAND_ADDRESS) \
+ || ((when1) == RELOAD_FOR_OTHER_ADDRESS \
+ && (when2) == RELOAD_FOR_OTHER_ADDRESS))
+
+ /* Nonzero if these two reload purposes produce RELOAD_OTHER when merged. */
+#define MERGE_TO_OTHER(when1, when2, op1, op2) \
+ ((when1) != (when2) \
+ || ! ((op1) == (op2) \
+ || (when1) == RELOAD_FOR_INPUT \
+ || (when1) == RELOAD_FOR_OPERAND_ADDRESS \
+ || (when1) == RELOAD_FOR_OTHER_ADDRESS))
+
+static int push_secondary_reload PROTO((int, rtx, int, int, enum reg_class,
+ enum machine_mode, enum reload_type,
+ enum insn_code *));
static int push_reload PROTO((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 rtx find_dummy_reload PROTO((rtx, rtx, rtx *, rtx *,
+ enum machine_mode, enum machine_mode,
enum reg_class, 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));
/* Determine if any secondary reloads are needed for loading (if IN_P is
non-zero) or storing (if IN_P is zero) X to or from a reload register of
- register class RELOAD_CLASS in mode RELOAD_MODE.
-
- Return the register class of a secondary reload register, or NO_REGS if
- none. *PMODE is set to the mode that the register is required in.
- If the reload register is needed as a scratch register instead of an
- intermediate register, *PICODE is set to the insn_code of the insn to be
- used to load or store the primary reload register; otherwise *PICODE
- is set to CODE_FOR_nothing.
-
- In some cases (such as storing MQ into an external memory location on
- the RT), both an intermediate register and a scratch register. In that
- case, *PICODE is set to CODE_FOR_nothing, the class for the intermediate
- register is returned, and the *PTERTIARY_... variables are set to describe
- the scratch register. */
-
-static enum reg_class
-find_secondary_reload (x, reload_class, reload_mode, in_p, picode, pmode,
- ptertiary_class, ptertiary_icode, ptertiary_mode)
+ register class RELOAD_CLASS in mode RELOAD_MODE. If secondary reloads
+ are needed, push them.
+
+ Return the reload number of the secondary reload we made, or -1 if
+ we didn't need one. *PICODE is set to the insn_code to use if we do
+ need a secondary reload. */
+
+static int
+push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
+ type, picode)
+ int in_p;
rtx x;
+ int opnum;
+ int optional;
enum reg_class reload_class;
enum machine_mode reload_mode;
- int in_p;
+ enum reload_type type;
enum insn_code *picode;
- enum machine_mode *pmode;
- enum reg_class *ptertiary_class;
- enum insn_code *ptertiary_icode;
- enum machine_mode *ptertiary_mode;
{
enum reg_class class = NO_REGS;
enum machine_mode mode = reload_mode;
enum reg_class t_class = NO_REGS;
enum machine_mode t_mode = VOIDmode;
enum insn_code t_icode = CODE_FOR_nothing;
+ enum reload_type secondary_type;
+ int i;
+ int s_reload, t_reload = -1;
+
+ if (type == RELOAD_FOR_INPUT_ADDRESS || type == RELOAD_FOR_OUTPUT_ADDRESS)
+ secondary_type = type;
+ else
+ secondary_type = in_p ? RELOAD_FOR_INPUT_ADDRESS : RELOAD_FOR_OUTPUT_ADDRESS;
+
+ *picode = CODE_FOR_nothing;
/* If X is a pseudo-register that has an equivalent MEM (actually, if it
is still a pseudo-register by now, it *must* have an equivalent MEM
class = SECONDARY_OUTPUT_RELOAD_CLASS (reload_class, reload_mode, x);
#endif
- /* If we don't need any secondary registers, go away; the rest of the
- values won't be used. */
+ /* If we don't need any secondary registers, done. */
if (class == NO_REGS)
- return NO_REGS;
+ return -1;
/* Get a possible insn to use. If the predicate doesn't accept X, don't
use the insn. */
}
}
- *pmode = mode;
- *picode = icode;
- *ptertiary_class = t_class;
- *ptertiary_mode = t_mode;
- *ptertiary_icode = t_icode;
+ /* This case isn't valid, so fail. Reload is allowed to use the same
+ register for RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_INPUT reloads, but
+ in the case of a secondary register, we actually need two different
+ registers for correct code. We fail here to prevent the possibility of
+ silently generating incorrect code later.
+
+ The convention is that secondary input reloads are valid only if the
+ secondary_class is different from class. If you have such a case, you
+ can not use secondary reloads, you must work around the problem some
+ other way.
- return class;
+ Allow this when MODE is not reload_mode and assume that the generated
+ code handles this case (it does on the Alpha, which is the only place
+ this currently happens). */
+
+ if (in_p && class == reload_class && mode == reload_mode)
+ abort ();
+
+ /* If we need a tertiary reload, see if we have one we can reuse or else
+ make a new one. */
+
+ if (t_class != NO_REGS)
+ {
+ for (t_reload = 0; t_reload < n_reloads; t_reload++)
+ if (reload_secondary_p[t_reload]
+ && (reg_class_subset_p (t_class, reload_reg_class[t_reload])
+ || reg_class_subset_p (reload_reg_class[t_reload], t_class))
+ && ((in_p && reload_inmode[t_reload] == t_mode)
+ || (! in_p && reload_outmode[t_reload] == t_mode))
+ && ((in_p && (reload_secondary_in_icode[t_reload]
+ == CODE_FOR_nothing))
+ || (! in_p &&(reload_secondary_out_icode[t_reload]
+ == CODE_FOR_nothing)))
+ && (reg_class_size[(int) t_class] == 1
+#ifdef SMALL_REGISTER_CLASSES
+ || 1
+#endif
+ )
+ && MERGABLE_RELOADS (secondary_type,
+ reload_when_needed[t_reload],
+ opnum, reload_opnum[t_reload]))
+ {
+ if (in_p)
+ reload_inmode[t_reload] = t_mode;
+ if (! in_p)
+ reload_outmode[t_reload] = t_mode;
+
+ if (reg_class_subset_p (t_class, reload_reg_class[t_reload]))
+ reload_reg_class[t_reload] = t_class;
+
+ reload_opnum[t_reload] = MIN (reload_opnum[t_reload], opnum);
+ reload_optional[t_reload] &= optional;
+ reload_secondary_p[t_reload] = 1;
+ if (MERGE_TO_OTHER (secondary_type, reload_when_needed[t_reload],
+ opnum, reload_opnum[t_reload]))
+ reload_when_needed[t_reload] = RELOAD_OTHER;
+ }
+
+ if (t_reload == n_reloads)
+ {
+ /* We need to make a new tertiary reload for this register class. */
+ reload_in[t_reload] = reload_out[t_reload] = 0;
+ reload_reg_class[t_reload] = t_class;
+ reload_inmode[t_reload] = in_p ? t_mode : VOIDmode;
+ reload_outmode[t_reload] = ! in_p ? t_mode : VOIDmode;
+ reload_reg_rtx[t_reload] = 0;
+ reload_optional[t_reload] = optional;
+ reload_inc[t_reload] = 0;
+ /* Maybe we could combine these, but it seems too tricky. */
+ reload_nocombine[t_reload] = 1;
+ reload_in_reg[t_reload] = 0;
+ reload_opnum[t_reload] = opnum;
+ reload_when_needed[t_reload] = secondary_type;
+ reload_secondary_in_reload[t_reload] = -1;
+ reload_secondary_out_reload[t_reload] = -1;
+ reload_secondary_in_icode[t_reload] = CODE_FOR_nothing;
+ reload_secondary_out_icode[t_reload] = CODE_FOR_nothing;
+ reload_secondary_p[t_reload] = 1;
+
+ n_reloads++;
+ }
+ }
+
+ /* See if we can reuse an existing secondary reload. */
+ for (s_reload = 0; s_reload < n_reloads; s_reload++)
+ if (reload_secondary_p[s_reload]
+ && (reg_class_subset_p (class, reload_reg_class[s_reload])
+ || reg_class_subset_p (reload_reg_class[s_reload], class))
+ && ((in_p && reload_inmode[s_reload] == mode)
+ || (! in_p && reload_outmode[s_reload] == mode))
+ && ((in_p && reload_secondary_in_reload[s_reload] == t_reload)
+ || (! in_p && reload_secondary_out_reload[s_reload] == t_reload))
+ && ((in_p && reload_secondary_in_icode[s_reload] == t_icode)
+ || (! in_p && reload_secondary_out_icode[s_reload] == t_icode))
+ && (reg_class_size[(int) class] == 1
+#ifdef SMALL_REGISTER_CLASSES
+ || 1
+#endif
+ )
+ && MERGABLE_RELOADS (secondary_type, reload_when_needed[s_reload],
+ opnum, reload_opnum[s_reload]))
+ {
+ if (in_p)
+ reload_inmode[s_reload] = mode;
+ if (! in_p)
+ reload_outmode[s_reload] = mode;
+
+ if (reg_class_subset_p (class, reload_reg_class[s_reload]))
+ reload_reg_class[s_reload] = class;
+
+ reload_opnum[s_reload] = MIN (reload_opnum[s_reload], opnum);
+ reload_optional[s_reload] &= optional;
+ reload_secondary_p[s_reload] = 1;
+ if (MERGE_TO_OTHER (secondary_type, reload_when_needed[s_reload],
+ opnum, reload_opnum[s_reload]))
+ reload_when_needed[s_reload] = RELOAD_OTHER;
+ }
+
+ if (s_reload == n_reloads)
+ {
+ /* We need to make a new secondary reload for this register class. */
+ reload_in[s_reload] = reload_out[s_reload] = 0;
+ reload_reg_class[s_reload] = class;
+
+ reload_inmode[s_reload] = in_p ? mode : VOIDmode;
+ reload_outmode[s_reload] = ! in_p ? mode : VOIDmode;
+ reload_reg_rtx[s_reload] = 0;
+ reload_optional[s_reload] = optional;
+ reload_inc[s_reload] = 0;
+ /* Maybe we could combine these, but it seems too tricky. */
+ reload_nocombine[s_reload] = 1;
+ reload_in_reg[s_reload] = 0;
+ reload_opnum[s_reload] = opnum;
+ reload_when_needed[s_reload] = secondary_type;
+ reload_secondary_in_reload[s_reload] = in_p ? t_reload : -1;
+ reload_secondary_out_reload[s_reload] = ! in_p ? t_reload : -1;
+ reload_secondary_in_icode[s_reload] = in_p ? t_icode : CODE_FOR_nothing;
+ reload_secondary_out_icode[s_reload]
+ = ! in_p ? t_icode : CODE_FOR_nothing;
+ reload_secondary_p[s_reload] = 1;
+
+ n_reloads++;
+
+#ifdef SECONDARY_MEMORY_NEEDED
+ /* If we need a memory location to copy between the two reload regs,
+ set it up now. */
+
+ if (in_p && icode == CODE_FOR_nothing
+ && SECONDARY_MEMORY_NEEDED (class, reload_class, reload_mode))
+ get_secondary_mem (x, reload_mode, opnum, type);
+
+ if (! in_p && icode == CODE_FOR_nothing
+ && SECONDARY_MEMORY_NEEDED (reload_class, class, reload_mode))
+ get_secondary_mem (x, reload_mode, opnum, type);
+#endif
+ }
+
+ *picode = icode;
+ return s_reload;
}
#endif /* HAVE_SECONDARY_RELOADS */
\f
rtx loc;
int mem_valid;
- /* If MODE is narrower than a word, widen it. This is required because
- most machines that require these memory locations do not support
- short load and stores from all registers (e.g., FP registers). We could
- possibly conditionalize this, but we lose nothing by doing the wider
- mode. */
+ /* By default, if MODE is narrower than a word, widen it to a word.
+ This is required because most machines that require these memory
+ locations do not support short load and stores from all registers
+ (e.g., FP registers). */
+#ifdef SECONDARY_MEMORY_NEEDED_MODE
+ mode = SECONDARY_MEMORY_NEEDED_MODE (mode);
+#else
if (GET_MODE_BITSIZE (mode) < BITS_PER_WORD)
mode = mode_for_size (BITS_PER_WORD, GET_MODE_CLASS (mode), 0);
+#endif
/* If we already have made a MEM for this operand in MODE, return it. */
if (secondary_memlocs_elim[(int) mode][opnum] != 0)
void
clear_secondary_mem ()
{
- bzero (secondary_memlocs, sizeof secondary_memlocs);
+ bzero ((char *) secondary_memlocs, sizeof secondary_memlocs);
}
#endif /* SECONDARY_MEMORY_NEEDED */
\f
register int i;
int dont_share = 0;
rtx *in_subreg_loc = 0, *out_subreg_loc = 0;
- int secondary_reload = -1;
- enum insn_code secondary_icode = CODE_FOR_nothing;
-
- /* Compare two RTX's. */
-#define MATCHES(x, y) \
- (x == y || (x != 0 && (GET_CODE (x) == REG \
- ? GET_CODE (y) == REG && REGNO (x) == REGNO (y) \
- : rtx_equal_p (x, y) && ! side_effects_p (x))))
-
- /* Indicates if two reloads purposes are for similar enough things that we
- can merge their reloads. */
-#define MERGABLE_RELOADS(when1, when2, op1, op2) \
- ((when1) == RELOAD_OTHER || (when2) == RELOAD_OTHER \
- || ((when1) == (when2) && (op1) == (op2)) \
- || ((when1) == RELOAD_FOR_INPUT && (when2) == RELOAD_FOR_INPUT) \
- || ((when1) == RELOAD_FOR_OPERAND_ADDRESS \
- && (when2) == RELOAD_FOR_OPERAND_ADDRESS) \
- || ((when1) == RELOAD_FOR_OTHER_ADDRESS \
- && (when2) == RELOAD_FOR_OTHER_ADDRESS))
-
- /* Nonzero if these two reload purposes produce RELOAD_OTHER when merged. */
-#define MERGE_TO_OTHER(when1, when2, op1, op2) \
- ((when1) != (when2) \
- || ! ((op1) == (op2) \
- || (when1) == RELOAD_FOR_INPUT \
- || (when1) == RELOAD_FOR_OPERAND_ADDRESS \
- || (when1) == RELOAD_FOR_OTHER_ADDRESS))
+ int secondary_in_reload = -1, secondary_out_reload = -1;
+ enum insn_code secondary_in_icode, secondary_out_icode;
/* INMODE and/or OUTMODE could be VOIDmode if no mode
has been specified for the operand. In that case,
}
/* If we are reloading a (SUBREG constant ...), really reload just the
- inside expression in its own mode.
+ inside expression in its own mode. Similarly for (SUBREG (PLUS ...)).
If we have (SUBREG:M1 (MEM:M2 ...) ...) (or an inner REG that is still
a pseudo and hence will become a MEM) with M1 wider than M2 and the
register is a pseudo, also reload the inside expression.
For machines that extend byte loads, do this for any SUBREG of a pseudo
- where both M1 and M2 are a word or smaller unless they are the same
- size.
+ where both M1 and M2 are a word or smaller, M1 is wider than M2, and
+ M2 is an integral mode that gets extended when loaded.
Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where
either M1 is not valid for R or M2 is wider than a word but we only
need one word to store an M2-sized quantity in R.
STRICT_LOW_PART (presumably, in == out in the cas).
Also reload the inner expression if it does not require a secondary
- reload but the SUBREG does. */
+ reload but the SUBREG does.
+
+ Finally, reload the inner expression if it is a register that is in
+ the class whose registers cannot be referenced in a different size
+ and M1 is not the same size as M2. */
if (in != 0 && GET_CODE (in) == SUBREG
&& (CONSTANT_P (SUBREG_REG (in))
+ || GET_CODE (SUBREG_REG (in)) == PLUS
|| strict_low
|| (((GET_CODE (SUBREG_REG (in)) == REG
&& REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER)
|| GET_CODE (SUBREG_REG (in)) == MEM)
-#if defined(BYTE_LOADS_ZERO_EXTEND) || defined(BYTE_LOADS_SIGN_EXTEND)
- && GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
- && GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) <= UNITS_PER_WORD
- && (GET_MODE_SIZE (inmode)
- != GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
-#else
- && (GET_MODE_SIZE (inmode)
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
+ && ((GET_MODE_SIZE (inmode)
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
+#ifdef LOAD_EXTEND_OP
+ || (GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
+ && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+ <= UNITS_PER_WORD)
+ && (GET_MODE_SIZE (inmode)
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
+ && INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (in)))
+ && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (in))) != NIL)
#endif
- )
+ ))
|| (GET_CODE (SUBREG_REG (in)) == REG
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
/* The case where out is nonzero
SUBREG_REG (in))
== NO_REGS))
#endif
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+ || (GET_CODE (SUBREG_REG (in)) == REG
+ && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
+ && (TEST_HARD_REG_BIT
+ (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
+ REGNO (SUBREG_REG (in))))
+ && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+ != GET_MODE_SIZE (inmode)))
+#endif
))
{
in_subreg_loc = inloc;
inloc = &SUBREG_REG (in);
in = *inloc;
-#if ! defined(BYTE_LOADS_ZERO_EXTEND) && ! defined(BYTE_LOADS_SIGN_EXTEND)
+#ifndef LOAD_EXTEND_OP
if (GET_CODE (in) == MEM)
/* This is supposed to happen only for paradoxical subregs made by
combine.c. (SUBREG (MEM)) isn't supposed to occur other ways. */
|| (((GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) >= FIRST_PSEUDO_REGISTER)
|| GET_CODE (SUBREG_REG (out)) == MEM)
-#if defined(BYTE_LOADS_ZERO_EXTEND) || defined(BYTE_LOADS_SIGN_EXTEND)
- && GET_MODE_SIZE (outmode) <= UNITS_PER_WORD
- && GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) <= UNITS_PER_WORD
- && (GET_MODE_SIZE (outmode)
- != GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
-#else
- && (GET_MODE_SIZE (outmode)
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
-#endif
- )
+ && ((GET_MODE_SIZE (outmode)
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))))
|| (GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
&& ((GET_MODE_SIZE (outmode) <= UNITS_PER_WORD
SUBREG_REG (out))
== NO_REGS))
#endif
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+ || (GET_CODE (SUBREG_REG (out)) == REG
+ && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
+ && (TEST_HARD_REG_BIT
+ (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
+ REGNO (SUBREG_REG (out))))
+ && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))
+ != GET_MODE_SIZE (outmode)))
+#endif
))
{
out_subreg_loc = outloc;
outloc = &SUBREG_REG (out);
out = *outloc;
-#if ! defined(BYTE_LOADS_ZERO_EXTEND) && ! defined(BYTE_LOADS_SIGN_EXTEND)
+#ifndef LOAD_EXTEND_OP
if (GET_CODE (out) == MEM
&& GET_MODE_SIZE (GET_MODE (out)) > GET_MODE_SIZE (outmode))
abort ();
if (i == n_reloads)
{
-#ifdef HAVE_SECONDARY_RELOADS
- enum reg_class secondary_class = NO_REGS;
- enum reg_class secondary_out_class = NO_REGS;
- enum machine_mode secondary_mode = inmode;
- enum machine_mode secondary_out_mode = outmode;
- enum insn_code secondary_icode;
- enum insn_code secondary_out_icode = CODE_FOR_nothing;
- enum reg_class tertiary_class = NO_REGS;
- enum reg_class tertiary_out_class = NO_REGS;
- enum machine_mode tertiary_mode;
- enum machine_mode tertiary_out_mode;
- enum insn_code tertiary_icode;
- enum insn_code tertiary_out_icode = CODE_FOR_nothing;
- int tertiary_reload = -1;
-
- /* See if we need a secondary reload register to move between
- CLASS and IN or CLASS and OUT. Get the modes and icodes to
- use for each of them if so. */
+ /* See if we need a secondary reload register to move between CLASS
+ and IN or CLASS and OUT. Get the icode and push any required reloads
+ needed for each of them if so. */
#ifdef SECONDARY_INPUT_RELOAD_CLASS
if (in != 0)
- secondary_class
- = find_secondary_reload (in, class, inmode, 1, &secondary_icode,
- &secondary_mode, &tertiary_class,
- &tertiary_icode, &tertiary_mode);
+ secondary_in_reload
+ = push_secondary_reload (1, in, opnum, optional, class, inmode, type,
+ &secondary_in_icode);
#endif
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
if (out != 0 && GET_CODE (out) != SCRATCH)
- secondary_out_class
- = find_secondary_reload (out, class, outmode, 0,
- &secondary_out_icode, &secondary_out_mode,
- &tertiary_out_class, &tertiary_out_icode,
- &tertiary_out_mode);
-#endif
-
- /* We can only record one secondary and one tertiary reload. If both
- IN and OUT need secondary reloads, we can only make an in-out
- reload if neither need an insn and if the classes are compatible.
- If they aren't, all we can do is abort since making two separate
- reloads is invalid. */
-
- if (secondary_class != NO_REGS && secondary_out_class != NO_REGS
- && reg_class_subset_p (secondary_out_class, secondary_class))
- secondary_class = secondary_out_class;
-
- if (secondary_class != NO_REGS && secondary_out_class != NO_REGS
- && (! reg_class_subset_p (secondary_class, secondary_out_class)
- || secondary_icode != CODE_FOR_nothing
- || secondary_out_icode != CODE_FOR_nothing))
- abort ();
-
- /* If we need a secondary reload for OUT but not IN, copy the
- information. */
- if (secondary_class == NO_REGS && secondary_out_class != NO_REGS)
- {
- secondary_class = secondary_out_class;
- secondary_icode = secondary_out_icode;
- tertiary_class = tertiary_out_class;
- tertiary_icode = tertiary_out_icode;
- tertiary_mode = tertiary_out_mode;
- }
-
- if (secondary_class != NO_REGS)
- {
- /* Secondary reloads don't conflict as badly as the primary object
- being reload. Specifically, we can always treat them as
- being for an input or output address and hence allowed to be
- reused in the same manner such address components could be
- reused. This is used as the reload_type for our secondary
- reloads. */
-
- enum reload_type secondary_type
- = (type == RELOAD_FOR_INPUT ? RELOAD_FOR_INPUT_ADDRESS
- : type == RELOAD_FOR_OUTPUT ? RELOAD_FOR_OUTPUT_ADDRESS
- : type);
-
- /* If we need a tertiary reload, see if we have one we can reuse
- or else make one. */
-
- if (tertiary_class != NO_REGS)
- {
- for (tertiary_reload = 0; tertiary_reload < n_reloads;
- tertiary_reload++)
- if (reload_secondary_p[tertiary_reload]
- && (reg_class_subset_p (tertiary_class,
- reload_reg_class[tertiary_reload])
- || reg_class_subset_p (reload_reg_class[tertiary_reload],
- tertiary_class))
- && ((reload_inmode[tertiary_reload] == tertiary_mode)
- || reload_inmode[tertiary_reload] == VOIDmode)
- && ((reload_outmode[tertiary_reload] == tertiary_mode)
- || reload_outmode[tertiary_reload] == VOIDmode)
- && (reload_secondary_icode[tertiary_reload]
- == CODE_FOR_nothing)
- && (reg_class_size[(int) tertiary_class] == 1
-#ifdef SMALL_REGISTER_CLASSES
- || 1
-#endif
- )
- && MERGABLE_RELOADS (secondary_type,
- reload_when_needed[tertiary_reload],
- opnum, reload_opnum[tertiary_reload]))
- {
- if (tertiary_mode != VOIDmode)
- reload_inmode[tertiary_reload] = tertiary_mode;
- if (tertiary_out_mode != VOIDmode)
- reload_outmode[tertiary_reload] = tertiary_mode;
- if (reg_class_subset_p (tertiary_class,
- reload_reg_class[tertiary_reload]))
- reload_reg_class[tertiary_reload] = tertiary_class;
- if (MERGE_TO_OTHER (secondary_type,
- reload_when_needed[tertiary_reload],
- opnum,
- reload_opnum[tertiary_reload]))
- reload_when_needed[tertiary_reload] = RELOAD_OTHER;
- reload_opnum[tertiary_reload]
- = MIN (reload_opnum[tertiary_reload], opnum);
- reload_optional[tertiary_reload] &= optional;
- reload_secondary_p[tertiary_reload] = 1;
- }
-
- if (tertiary_reload == n_reloads)
- {
- /* We need to make a new tertiary reload for this register
- class. */
- reload_in[tertiary_reload] = reload_out[tertiary_reload] = 0;
- reload_reg_class[tertiary_reload] = tertiary_class;
- reload_inmode[tertiary_reload] = tertiary_mode;
- reload_outmode[tertiary_reload] = tertiary_mode;
- reload_reg_rtx[tertiary_reload] = 0;
- reload_optional[tertiary_reload] = optional;
- reload_inc[tertiary_reload] = 0;
- /* Maybe we could combine these, but it seems too tricky. */
- reload_nocombine[tertiary_reload] = 1;
- reload_in_reg[tertiary_reload] = 0;
- reload_opnum[tertiary_reload] = opnum;
- reload_when_needed[tertiary_reload] = secondary_type;
- reload_secondary_reload[tertiary_reload] = -1;
- reload_secondary_icode[tertiary_reload] = CODE_FOR_nothing;
- reload_secondary_p[tertiary_reload] = 1;
-
- n_reloads++;
- i = n_reloads;
- }
- }
-
- /* See if we can reuse an existing secondary reload. */
- for (secondary_reload = 0; secondary_reload < n_reloads;
- secondary_reload++)
- if (reload_secondary_p[secondary_reload]
- && (reg_class_subset_p (secondary_class,
- reload_reg_class[secondary_reload])
- || reg_class_subset_p (reload_reg_class[secondary_reload],
- secondary_class))
- && ((reload_inmode[secondary_reload] == secondary_mode)
- || reload_inmode[secondary_reload] == VOIDmode)
- && ((reload_outmode[secondary_reload] == secondary_out_mode)
- || reload_outmode[secondary_reload] == VOIDmode)
- && reload_secondary_reload[secondary_reload] == tertiary_reload
- && reload_secondary_icode[secondary_reload] == tertiary_icode
- && (reg_class_size[(int) secondary_class] == 1
-#ifdef SMALL_REGISTER_CLASSES
- || 1
-#endif
- )
- && MERGABLE_RELOADS (secondary_type,
- reload_when_needed[secondary_reload],
- opnum, reload_opnum[secondary_reload]))
- {
- if (secondary_mode != VOIDmode)
- reload_inmode[secondary_reload] = secondary_mode;
- if (secondary_out_mode != VOIDmode)
- reload_outmode[secondary_reload] = secondary_out_mode;
- if (reg_class_subset_p (secondary_class,
- reload_reg_class[secondary_reload]))
- reload_reg_class[secondary_reload] = secondary_class;
- if (MERGE_TO_OTHER (secondary_type,
- reload_when_needed[secondary_reload],
- opnum, reload_opnum[secondary_reload]))
- reload_when_needed[secondary_reload] = RELOAD_OTHER;
- reload_opnum[secondary_reload]
- = MIN (reload_opnum[secondary_reload], opnum);
- reload_optional[secondary_reload] &= optional;
- reload_secondary_p[secondary_reload] = 1;
- }
-
- if (secondary_reload == n_reloads)
- {
- /* We need to make a new secondary reload for this register
- class. */
- reload_in[secondary_reload] = reload_out[secondary_reload] = 0;
- reload_reg_class[secondary_reload] = secondary_class;
- reload_inmode[secondary_reload] = secondary_mode;
- reload_outmode[secondary_reload] = secondary_out_mode;
- reload_reg_rtx[secondary_reload] = 0;
- reload_optional[secondary_reload] = optional;
- reload_inc[secondary_reload] = 0;
- /* Maybe we could combine these, but it seems too tricky. */
- reload_nocombine[secondary_reload] = 1;
- reload_in_reg[secondary_reload] = 0;
- reload_opnum[secondary_reload] = opnum;
- reload_when_needed[secondary_reload] = secondary_type;
- reload_secondary_reload[secondary_reload] = tertiary_reload;
- reload_secondary_icode[secondary_reload] = tertiary_icode;
- reload_secondary_p[secondary_reload] = 1;
-
- n_reloads++;
- i = n_reloads;
-
-#ifdef SECONDARY_MEMORY_NEEDED
- /* If we need a memory location to copy between the two
- reload regs, set it up now. */
-
- if (in != 0 && secondary_icode == CODE_FOR_nothing
- && SECONDARY_MEMORY_NEEDED (secondary_class, class, inmode))
- get_secondary_mem (in, inmode, opnum, type);
-
- if (out != 0 && secondary_icode == CODE_FOR_nothing
- && SECONDARY_MEMORY_NEEDED (class, secondary_class, outmode))
- get_secondary_mem (out, outmode, opnum, type);
-#endif
- }
- }
+ secondary_out_reload
+ = push_secondary_reload (0, out, opnum, optional, class, outmode,
+ type, &secondary_out_icode);
#endif
/* We found no existing reload suitable for re-use.
So add an additional reload. */
+ i = n_reloads;
reload_in[i] = in;
reload_out[i] = out;
reload_reg_class[i] = class;
reload_in_reg[i] = inloc ? *inloc : 0;
reload_opnum[i] = opnum;
reload_when_needed[i] = type;
- reload_secondary_reload[i] = secondary_reload;
- reload_secondary_icode[i] = secondary_icode;
+ reload_secondary_in_reload[i] = secondary_in_reload;
+ reload_secondary_out_reload[i] = secondary_out_reload;
+ reload_secondary_in_icode[i] = secondary_in_icode;
+ reload_secondary_out_icode[i] = secondary_out_icode;
reload_secondary_p[i] = 0;
n_reloads++;
if (in != 0 && out != 0 && in != out && reload_reg_rtx[i] == 0)
{
reload_reg_rtx[i] = find_dummy_reload (in, out, inloc, outloc,
+ inmode, outmode,
reload_reg_class[i], i);
/* If the outgoing register already contains the same value
return;
/* If this reload is for an earlyclobber operand, we can't do anything. */
-
- for (i = 0; i < n_earlyclobbers; i++)
- if (reload_out[output_reload] == reload_earlyclobbers[i])
- return;
+ if (earlyclobber_operand_p (reload_out[output_reload]))
+ return;
/* Check each input reload; can we combine it? */
reload_outmode[output_reload]))
&& reload_inc[i] == 0
&& reload_reg_rtx[i] == 0
- /* Don't combine two reloads with different secondary reloads. */
- && (reload_secondary_reload[i] == reload_secondary_reload[output_reload]
- || reload_secondary_reload[i] == -1
- || reload_secondary_reload[output_reload] == -1)
#ifdef SECONDARY_MEMORY_NEEDED
- /* Likewise for different secondary memory locations. */
+ /* Don't combine two reloads with different secondary
+ memory locations. */
&& (secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[i]] == 0
|| secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]] == 0
|| rtx_equal_p (secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[i]],
/* The combined reload is needed for the entire insn. */
reload_when_needed[i] = RELOAD_OTHER;
/* If the output reload had a secondary reload, copy it. */
- if (reload_secondary_reload[output_reload] != -1)
- reload_secondary_reload[i] = reload_secondary_reload[output_reload];
+ if (reload_secondary_out_reload[output_reload] != -1)
+ {
+ reload_secondary_out_reload[i]
+ = reload_secondary_out_reload[output_reload];
+ reload_secondary_out_icode[i]
+ = reload_secondary_out_icode[output_reload];
+ }
+
#ifdef SECONDARY_MEMORY_NEEDED
/* Copy any secondary MEM. */
if (secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]] != 0)
is just to see if a register can be found, not to find and install it. */
static rtx
-find_dummy_reload (real_in, real_out, inloc, outloc, class, for_real)
+find_dummy_reload (real_in, real_out, inloc, outloc,
+ inmode, outmode, class, for_real)
rtx real_in, real_out;
rtx *inloc, *outloc;
+ enum machine_mode inmode, outmode;
enum reg_class class;
int for_real;
{
/* If operands exceed a word, we can't use either of them
unless they have the same size. */
- if (GET_MODE_SIZE (GET_MODE (real_out)) != GET_MODE_SIZE (GET_MODE (real_in))
- && (GET_MODE_SIZE (GET_MODE (real_out)) > UNITS_PER_WORD
- || GET_MODE_SIZE (GET_MODE (real_in)) > UNITS_PER_WORD))
+ if (GET_MODE_SIZE (outmode) != GET_MODE_SIZE (inmode)
+ && (GET_MODE_SIZE (outmode) > UNITS_PER_WORD
+ || GET_MODE_SIZE (inmode) > UNITS_PER_WORD))
return 0;
/* Find the inside of any subregs. */
&& REGNO (out) < FIRST_PSEUDO_REGISTER)
{
register int regno = REGNO (out) + out_offset;
- int nwords = HARD_REGNO_NREGS (regno, GET_MODE (real_out));
+ int nwords = HARD_REGNO_NREGS (regno, outmode);
rtx saved_rtx;
/* When we consider whether the insn uses OUT,
if (GET_CODE (real_out) == REG)
value = real_out;
else
- value = gen_rtx (REG, GET_MODE (real_out), regno);
+ value = gen_rtx (REG, outmode, regno);
}
}
|| find_reg_note (this_insn, REG_UNUSED, real_out))
&& find_reg_note (this_insn, REG_DEAD, real_in)
&& !fixed_regs[REGNO (in)]
- && HARD_REGNO_MODE_OK (REGNO (in), GET_MODE (out)))
+ && HARD_REGNO_MODE_OK (REGNO (in),
+ /* The only case where out and real_out might
+ have different modes is where real_out
+ is a subreg, and in that case, out
+ has a real mode. */
+ (GET_MODE (out) != VOIDmode
+ ? GET_MODE (out) : outmode)))
{
register int regno = REGNO (in) + in_offset;
- int nwords = HARD_REGNO_NREGS (regno, GET_MODE (real_in));
+ 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,
if (GET_CODE (real_in) == REG)
value = real_in;
else
- value = gen_rtx (REG, GET_MODE (real_in), regno);
+ value = gen_rtx (REG, inmode, regno);
}
}
}
whether the IN or an OUT of a reload can serve as the
reload register. */
+/* Return 1 if X is an operand of an insn that is being earlyclobbered. */
+
+static int
+earlyclobber_operand_p (x)
+ rtx x;
+{
+ int i;
+
+ for (i = 0; i < n_earlyclobbers; i++)
+ if (reload_earlyclobbers[i] == x)
+ return 1;
+
+ return 0;
+}
+
/* Return 1 if expression X alters a hard reg in the range
from BEG_REGNO (inclusive) to END_REGNO (exclusive),
either explicitly or in the guise of a pseudo-reg allocated to REGNO.
int
n_occurrences (c, s)
- char c;
+ int c;
char *s;
{
int n = 0;
/* Constants and stack slots never overlap. */
if (CONSTANT_P (xdata.base)
&& (ydata.base == frame_pointer_rtx
+ || ydata.base == hard_frame_pointer_rtx
|| ydata.base == stack_pointer_rtx))
return 1;
if (CONSTANT_P (ydata.base)
&& (xdata.base == frame_pointer_rtx
+ || xdata.base == hard_frame_pointer_rtx
|| xdata.base == stack_pointer_rtx))
return 1;
/* If either base is variable, we don't know anything. */
/* The eliminated forms of any secondary memory locations are per-insn, so
clear them out here. */
- bzero (secondary_memlocs_elim, sizeof secondary_memlocs_elim);
+ bzero ((char *) secondary_memlocs_elim, sizeof secondary_memlocs_elim);
#endif
/* Find what kind of insn this is. NOPERANDS gets number of operands.
constraints, operand_mode);
if (noperands > 0)
{
- bcopy (constraints, constraints1, noperands * sizeof (char *));
+ bcopy ((char *) constraints, (char *) constraints1,
+ noperands * sizeof (char *));
n_alternatives = n_occurrences (',', constraints[0]) + 1;
for (i = 1; i < noperands; i++)
if (n_alternatives != n_occurrences (',', constraints[i]) + 1)
: modified[i] == RELOAD_WRITE ? RELOAD_FOR_OUTPUT_ADDRESS
: RELOAD_OTHER);
- if (constraints[i][0] == 'p')
+ if (*constraints[i] == 0)
+ /* Ignore things like match_operator operands. */
+ ;
+ else if (constraints[i][0] == 'p')
{
find_reloads_address (VOIDmode, NULL_PTR,
recog_operand[i], recog_operand_loc[i],
ind_levels,
set != 0
&& &SET_DEST (set) == recog_operand_loc[i]);
+ else if (code == PLUS)
+ /* We can get a PLUS as an "operand" as a result of
+ register elimination. See eliminate_regs and gen_input_reload. */
+ substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]
+ = find_reloads_toplev (recog_operand[i], i, address_type[i],
+ ind_levels, 0);
else if (code == REG)
{
/* This is equivalent to calling find_reloads_toplev.
regardless of what the constraint says. */
int force_reload = 0;
int offmemok = 0;
+ /* Nonzero if a constant forced into memory would be OK for this
+ operand. */
+ int constmemok = 0;
int earlyclobber = 0;
/* If the operand is a SUBREG, extract
{
offset += SUBREG_WORD (operand);
operand = SUBREG_REG (operand);
- /* Force reload if this is a constant or if there may may
+ /* Force reload if this is a constant or PLUS or if there may may
be a problem accessing OPERAND in the outer mode. */
if (CONSTANT_P (operand)
-#if defined(BYTE_LOADS_ZERO_EXTEND) || defined(BYTE_LOADS_SIGN_EXTEND)
- /* If we have a SUBREG where both the inner and outer
- modes are different size but no wider than a word,
- combine.c has made assumptions about the behavior of
- the machine in such register access. If the data is,
- in fact, in memory we must always load using the size
- assumed to be in the register and let the insn do the
- different-sized accesses. */
+ || GET_CODE (operand) == PLUS
+ /* We must force a reload of paradoxical SUBREGs
+ of a MEM because the alignment of the inner value
+ may not be enough to do the outer reference. On
+ big-endian machines, it may also reference outside
+ the object.
+
+ On machines that extend byte operations and we have a
+ SUBREG where both the inner and outer modes are no wider
+ than a word and the inner mode is narrower, is integral,
+ and gets extended when loaded from memory, combine.c has
+ made assumptions about the behavior of the machine in such
+ register access. If the data is, in fact, in memory we
+ must always load using the size assumed to be in the
+ register and let the insn do the different-sized
+ accesses. */
|| ((GET_CODE (operand) == MEM
|| (GET_CODE (operand)== REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER))
- && GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
- && GET_MODE_SIZE (GET_MODE (operand)) <= UNITS_PER_WORD
- && (GET_MODE_SIZE (operand_mode[i])
- != GET_MODE_SIZE (GET_MODE (operand))))
+ && (((GET_MODE_BITSIZE (GET_MODE (operand))
+ < BIGGEST_ALIGNMENT)
+ && (GET_MODE_SIZE (operand_mode[i])
+ > GET_MODE_SIZE (GET_MODE (operand))))
+ || (GET_CODE (operand) == MEM && BYTES_BIG_ENDIAN)
+#ifdef LOAD_EXTEND_OP
+ || (GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
+ && (GET_MODE_SIZE (GET_MODE (operand))
+ <= UNITS_PER_WORD)
+ && (GET_MODE_SIZE (operand_mode[i])
+ > GET_MODE_SIZE (GET_MODE (operand)))
+ && INTEGRAL_MODE_P (GET_MODE (operand))
+ && LOAD_EXTEND_OP (GET_MODE (operand)) != NIL)
#endif
+ ))
/* Subreg of a hard reg which can't handle the subreg's mode
or which would handle that mode in the wrong number of
registers for subregging to work. */
value
= find_dummy_reload (recog_operand[i], recog_operand[c],
recog_operand_loc[i], recog_operand_loc[c],
+ operand_mode[i], operand_mode[c],
this_alternative[c], -1);
if (value != 0)
we are supposed to match can be fixed with reloads. */
badop = 0;
this_alternative[i] = this_alternative[c];
+
+ /* If we have to reload this operand and some previous
+ operand also had to match the same thing as this
+ operand, we don't know how to do that. So reject this
+ alternative. */
+ if (! win || force_reload)
+ for (j = 0; j < i; j++)
+ if (this_alternative_matches[j]
+ == this_alternative_matches[i])
+ badop = 1;
+
break;
case 'p':
/* All necessary reloads for an address_operand
were handled in find_reloads_address. */
- this_alternative[i] = (int) ALL_REGS;
+ this_alternative[i] = (int) BASE_REG_CLASS;
win = 1;
break;
win = 1;
if (CONSTANT_P (operand))
badop = 0;
+ constmemok = 1;
break;
case '<':
|| reg_equiv_address[REGNO (XEXP (operand, 0))] != 0))
|| (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER
- && reg_renumber[REGNO (operand)] < 0))
+ && reg_renumber[REGNO (operand)] < 0
+ /* If reg_equiv_address is nonzero, we will be
+ loading it into a register; hence it will be
+ offsettable, but we cannot say that reg_equiv_mem
+ is offsettable without checking. */
+ && ((reg_equiv_mem[REGNO (operand)] != 0
+ && offsettable_memref_p (reg_equiv_mem[REGNO (operand)]))
+ || (reg_equiv_address[REGNO (operand)] != 0))))
win = 1;
if (CONSTANT_P (operand) || GET_CODE (operand) == MEM)
badop = 0;
+ constmemok = 1;
offmemok = 1;
break;
this_alternative_win[i] = 1;
else
{
+ int const_to_mem = 0;
+
this_alternative_offmemok[i] = offmemok;
losers++;
if (badop)
else if (modified[i] != RELOAD_WRITE && no_input_reloads)
bad = 1;
+ /* If this is a constant that is reloaded into the desired
+ class by copying it to memory first, count that as another
+ reload. This is consistent with other code and is
+ required to avoid chosing another alternative when
+ the constant is moved into memory by this function on
+ an early reload pass. Note that the test here is
+ precisely the same as in the code below that calls
+ force_const_mem. */
+ if (CONSTANT_P (operand)
+ /* force_const_mem does not accept HIGH. */
+ && GET_CODE (operand) != HIGH
+ && (PREFERRED_RELOAD_CLASS (operand,
+ (enum reg_class) this_alternative[i])
+ == NO_REGS)
+ && operand_mode[i] != VOIDmode)
+ {
+ const_to_mem = 1;
+ if (this_alternative[i] != (int) NO_REGS)
+ losers++;
+ }
+
+ /* If we can't reload this value at all, reject this
+ alternative. Note that we could also lose due to
+ LIMIT_RELOAD_RELOAD_CLASS, but we don't check that
+ here. */
+
+ if (! CONSTANT_P (operand)
+ && (enum reg_class) this_alternative[i] != NO_REGS
+ && (PREFERRED_RELOAD_CLASS (operand,
+ (enum reg_class) this_alternative[i])
+ == NO_REGS))
+ bad = 1;
+
/* We prefer to reload pseudos over reloading other things,
since such reloads may be able to be eliminated later.
If we are reloading a SCRATCH, we won't be generating any
insns, just using a register, so it is also preferred.
- So bump REJECT in other cases. */
- if (GET_CODE (operand) != REG && GET_CODE (operand) != SCRATCH)
+ So bump REJECT in other cases. Don't do this in the
+ case where we are forcing a constant into memory and
+ it will then win since we don't want to have a different
+ alternative match then. */
+ if (! (GET_CODE (operand) == REG
+ && REGNO (operand) >= FIRST_PSEUDO_REGISTER)
+ && GET_CODE (operand) != SCRATCH
+ && ! (const_to_mem && constmemok))
reject++;
}
Don't bother with this if this alternative will accept this
operand.
- Don't do this for a multiword operand, if
- we have to worry about small classes, because making reg groups
- harder to allocate is asking for trouble.
+ Don't do this for a multiword operand, since it is only a
+ small win and has the risk of requiring more spill registers,
+ which could cause a large loss.
Don't do this if the preferred class has only one register
because we might otherwise exhaust the class. */
if (! win && this_alternative[i] != (int) NO_REGS
-#ifdef SMALL_REGISTER_CLASSES
&& GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
-#endif
&& reg_class_size[(int) preferred_class[i]] > 1)
{
if (! reg_class_subset_p (this_alternative[i],
pref_or_nothing[commutative] = pref_or_nothing[commutative + 1];
pref_or_nothing[commutative + 1] = t;
- bcopy (constraints1, constraints, noperands * sizeof (char *));
+ bcopy ((char *) constraints1, (char *) constraints,
+ noperands * sizeof (char *));
goto try_swapped;
}
else
for (i = 0; i < noperands; i++)
if (! goal_alternative_win[i]
&& CONSTANT_P (recog_operand[i])
+ /* force_const_mem does not accept HIGH. */
+ && GET_CODE (recog_operand[i]) != HIGH
&& (PREFERRED_RELOAD_CLASS (recog_operand[i],
(enum reg_class) goal_alternative[i])
== NO_REGS)
goal_alternative_win[i] = 1;
}
+ /* Record the values of the earlyclobber operands for the caller. */
+ if (goal_earlyclobber)
+ for (i = 0; i < noperands; i++)
+ if (goal_alternative_earlyclobber[i])
+ reload_earlyclobbers[n_earlyclobbers++] = recog_operand[i];
+
/* Now record reloads for all the operands that need them. */
for (i = 0; i < noperands; i++)
if (! goal_alternative_win[i])
;
/* Handle an operand with a nonoffsettable address
appearing where an offsettable address will do
- by reloading the address into a base register. */
+ by reloading the address into a base register.
+
+ ??? We can also do this when the operand is a register and
+ reg_equiv_mem is not offsettable, but this is a bit tricky,
+ so we don't bother with it. It may not be worth doing. */
else if (goal_alternative_matched[i] == -1
&& goal_alternative_offmemok[i]
&& GET_CODE (recog_operand[i]) == MEM)
now we are treating part of the operand as an input, so
we must change these to RELOAD_FOR_INPUT_ADDRESS. */
- if (operand_type[i] == RELOAD_FOR_OUTPUT)
+ if (modified[i] == RELOAD_WRITE)
for (j = 0; j < n_reloads; j++)
if (reload_opnum[j] == i
&& reload_when_needed[j] == RELOAD_FOR_OUTPUT_ADDRESS)
0, 1, goal_alternative_matches[i], RELOAD_OTHER);
}
- /* Record the values of the earlyclobber operands for the caller. */
- if (goal_earlyclobber)
- for (i = 0; i < noperands; i++)
- if (goal_alternative_earlyclobber[i])
- reload_earlyclobbers[n_earlyclobbers++] = recog_operand[i];
-
/* If this insn pattern contains any MATCH_DUP's, make sure that
they will be substituted if the operands they match are substituted.
Also do now any substitutions we already did on the operands.
|| reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS)
&& (operand_reloadnum[reload_opnum[i]] < 0
|| reload_optional[operand_reloadnum[reload_opnum[i]]]))
- reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
+ {
+ /* If we have a secondary reload to go along with this reload,
+ change its type to RELOAD_FOR_OPADDR_ADDR. */
+
+ if (reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
+ && reload_secondary_in_reload[i] != -1)
+ {
+ int secondary_in_reload = reload_secondary_in_reload[i];
+
+ reload_when_needed[secondary_in_reload] =
+ RELOAD_FOR_OPADDR_ADDR;
+
+ /* If there's a tertiary reload we have to change it also. */
+ if (secondary_in_reload > 0
+ && reload_secondary_in_reload[secondary_in_reload] != -1)
+ reload_when_needed[reload_secondary_in_reload[secondary_in_reload]]
+ = RELOAD_FOR_OPADDR_ADDR;
+ }
+
+ if (reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS
+ && reload_secondary_out_reload[i] != -1)
+ {
+ int secondary_out_reload = reload_secondary_out_reload[i];
+
+ reload_when_needed[secondary_out_reload] =
+ RELOAD_FOR_OPADDR_ADDR;
+
+ /* If there's a tertiary reload we have to change it also. */
+ if (secondary_out_reload
+ && reload_secondary_out_reload[secondary_out_reload] != -1)
+ reload_when_needed[reload_secondary_out_reload[secondary_out_reload]]
+ = RELOAD_FOR_OPADDR_ADDR;
+ }
+ reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
+ }
if (reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
&& operand_reloadnum[reload_opnum[i]] >= 0
&& reload_when_needed[j] == reload_when_needed[i]
&& MATCHES (reload_in[i], reload_in[j])
&& reload_reg_class[i] == reload_reg_class[j]
- && !reload_nocombine[i] && !reload_nocombine[j])
+ && !reload_nocombine[i] && !reload_nocombine[j]
+ && reload_reg_rtx[i] == reload_reg_rtx[j])
{
reload_opnum[i] = MIN (reload_opnum[i], reload_opnum[j]);
transfer_replacements (i, j);
force a reload in that case. So we should not do anything here. */
else if (regno >= FIRST_PSEUDO_REGISTER
-#if defined(BYTE_LOADS_ZERO_EXTEND) || defined(BYTE_LOADS_SIGN_EXTEND)
+#ifdef LOAD_EXTEND_OP
&& (GET_MODE_SIZE (GET_MODE (x))
<= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
#endif
(displacement is too large), compute the sum in a register. */
else if (GET_CODE (ad) == PLUS
&& (XEXP (ad, 0) == frame_pointer_rtx
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+ || XEXP (ad, 0) == hard_frame_pointer_rtx
+#endif
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
|| XEXP (ad, 0) == arg_pointer_rtx
#endif
/* Unshare the MEM rtx so we can safely alter it. */
if (memrefloc)
{
- rtx oldref = *memrefloc;
*memrefloc = copy_rtx (*memrefloc);
loc = &XEXP (*memrefloc, 0);
}
else if (GET_CODE (ad) == PLUS && GET_CODE (XEXP (ad, 1)) == CONST_INT
&& GET_CODE (XEXP (ad, 0)) == PLUS
&& (XEXP (XEXP (ad, 0), 0) == frame_pointer_rtx
+#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+ || XEXP (XEXP (ad, 0), 0) == hard_frame_pointer_rtx
+#endif
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
|| XEXP (XEXP (ad, 0), 0) == arg_pointer_rtx
#endif
else if (GET_CODE (ad) == PLUS && GET_CODE (XEXP (ad, 1)) == CONST_INT
&& GET_CODE (XEXP (ad, 0)) == PLUS
&& (XEXP (XEXP (ad, 0), 1) == frame_pointer_rtx
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+ || XEXP (XEXP (ad, 0), 1) == hard_frame_pointer_rtx
+#endif
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
|| XEXP (XEXP (ad, 0), 1) == arg_pointer_rtx
#endif
&& ! memory_address_p (mode, ad))
{
*loc = ad = gen_rtx (PLUS, GET_MODE (ad),
+ XEXP (XEXP (ad, 0), 0),
plus_constant (XEXP (XEXP (ad, 0), 1),
- INTVAL (XEXP (ad, 1))),
- XEXP (XEXP (ad, 0), 0));
- find_reloads_address_part (XEXP (ad, 0), &XEXP (ad, 0), BASE_REG_CLASS,
+ INTVAL (XEXP (ad, 1))));
+ find_reloads_address_part (XEXP (ad, 1), &XEXP (ad, 1), BASE_REG_CLASS,
GET_MODE (ad), opnum, type, ind_levels);
- find_reloads_address_1 (XEXP (ad, 1), 1, &XEXP (ad, 1), opnum, type, 0);
+ find_reloads_address_1 (XEXP (ad, 0), 1, &XEXP (ad, 0), opnum, type, 0);
return 1;
}
if (memrefloc && GET_CODE (ad) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (ad))
{
- rtx oldref = *memrefloc;
*memrefloc = copy_rtx (*memrefloc);
loc = &XEXP (*memrefloc, 0);
}
{
register RTX_CODE code = GET_CODE (x);
- if (code == PLUS)
+ switch (code)
{
- register rtx op0 = XEXP (x, 0);
- register rtx op1 = XEXP (x, 1);
- register RTX_CODE code0 = GET_CODE (op0);
- register RTX_CODE code1 = GET_CODE (op1);
- if (code0 == MULT || code0 == SIGN_EXTEND || code1 == MEM)
- {
- find_reloads_address_1 (op0, 1, &XEXP (x, 0), opnum, type,
- ind_levels);
- find_reloads_address_1 (op1, 0, &XEXP (x, 1), opnum, type,
- ind_levels);
- }
- else if (code1 == MULT || code1 == SIGN_EXTEND || code0 == MEM)
- {
- find_reloads_address_1 (op0, 0, &XEXP (x, 0), opnum, type,
- ind_levels);
- find_reloads_address_1 (op1, 1, &XEXP (x, 1), opnum, type,
- ind_levels);
- }
- else if (code0 == CONST_INT || code0 == CONST
- || code0 == SYMBOL_REF || code0 == LABEL_REF)
- find_reloads_address_1 (op1, 0, &XEXP (x, 1), opnum, type, ind_levels);
- else if (code1 == CONST_INT || code1 == CONST
- || code1 == SYMBOL_REF || code1 == LABEL_REF)
- find_reloads_address_1 (op0, 0, &XEXP (x, 0), opnum, type, ind_levels);
- else if (code0 == REG && code1 == REG)
- {
- if (REG_OK_FOR_INDEX_P (op0)
- && REG_OK_FOR_BASE_P (op1))
- return 0;
- else if (REG_OK_FOR_INDEX_P (op1)
- && REG_OK_FOR_BASE_P (op0))
- return 0;
- else if (REG_OK_FOR_BASE_P (op1))
- find_reloads_address_1 (op0, 1, &XEXP (x, 0), opnum, type,
+ case PLUS:
+ {
+ register rtx orig_op0 = XEXP (x, 0);
+ register rtx orig_op1 = XEXP (x, 1);
+ register RTX_CODE code0 = GET_CODE (orig_op0);
+ register RTX_CODE code1 = GET_CODE (orig_op1);
+ register rtx op0 = orig_op0;
+ register rtx op1 = orig_op1;
+
+ if (GET_CODE (op0) == SUBREG)
+ {
+ op0 = SUBREG_REG (op0);
+ code0 = GET_CODE (op0);
+ }
+
+ if (GET_CODE (op1) == SUBREG)
+ {
+ op1 = SUBREG_REG (op1);
+ code1 = GET_CODE (op1);
+ }
+
+ if (code0 == MULT || code0 == SIGN_EXTEND || code1 == MEM)
+ {
+ find_reloads_address_1 (orig_op0, 1, &XEXP (x, 0), opnum, type,
ind_levels);
- else if (REG_OK_FOR_BASE_P (op0))
- find_reloads_address_1 (op1, 1, &XEXP (x, 1), opnum, type,
+ find_reloads_address_1 (orig_op1, 0, &XEXP (x, 1), opnum, type,
ind_levels);
- else if (REG_OK_FOR_INDEX_P (op1))
- find_reloads_address_1 (op0, 0, &XEXP (x, 0), opnum, type,
+ }
+
+ else if (code1 == MULT || code1 == SIGN_EXTEND || code0 == MEM)
+ {
+ find_reloads_address_1 (orig_op0, 0, &XEXP (x, 0), opnum, type,
ind_levels);
- else if (REG_OK_FOR_INDEX_P (op0))
- find_reloads_address_1 (op1, 0, &XEXP (x, 1), opnum, type,
+ find_reloads_address_1 (orig_op1, 1, &XEXP (x, 1), opnum, type,
ind_levels);
- else
- {
- find_reloads_address_1 (op0, 1, &XEXP (x, 0), opnum, type,
- ind_levels);
- find_reloads_address_1 (op1, 0, &XEXP (x, 1), opnum, type,
- ind_levels);
- }
- }
- else if (code0 == REG)
- {
- find_reloads_address_1 (op0, 1, &XEXP (x, 0), opnum, type,
- ind_levels);
- find_reloads_address_1 (op1, 0, &XEXP (x, 1), opnum, type,
- ind_levels);
- }
- else if (code1 == REG)
- {
- find_reloads_address_1 (op1, 1, &XEXP (x, 1), opnum, type,
+ }
+
+ else if (code0 == CONST_INT || code0 == CONST
+ || code0 == SYMBOL_REF || code0 == LABEL_REF)
+ find_reloads_address_1 (orig_op1, 0, &XEXP (x, 1), opnum, type,
ind_levels);
- find_reloads_address_1 (op0, 0, &XEXP (x, 0), opnum, type,
+
+ else if (code1 == CONST_INT || code1 == CONST
+ || code1 == SYMBOL_REF || code1 == LABEL_REF)
+ find_reloads_address_1 (orig_op0, 0, &XEXP (x, 0), opnum, type,
ind_levels);
- }
- }
- else if (code == POST_INC || code == POST_DEC
- || code == PRE_INC || code == PRE_DEC)
- {
+
+ else if (code0 == REG && code1 == REG)
+ {
+ if (REG_OK_FOR_INDEX_P (op0)
+ && REG_OK_FOR_BASE_P (op1))
+ return 0;
+ else if (REG_OK_FOR_INDEX_P (op1)
+ && REG_OK_FOR_BASE_P (op0))
+ return 0;
+ else if (REG_OK_FOR_BASE_P (op1))
+ find_reloads_address_1 (orig_op0, 1, &XEXP (x, 0), opnum, type,
+ ind_levels);
+ else if (REG_OK_FOR_BASE_P (op0))
+ find_reloads_address_1 (orig_op1, 1, &XEXP (x, 1), opnum, type,
+ ind_levels);
+ else if (REG_OK_FOR_INDEX_P (op1))
+ find_reloads_address_1 (orig_op0, 0, &XEXP (x, 0), opnum, type,
+ ind_levels);
+ else if (REG_OK_FOR_INDEX_P (op0))
+ find_reloads_address_1 (orig_op1, 0, &XEXP (x, 1), opnum, type,
+ ind_levels);
+ else
+ {
+ find_reloads_address_1 (orig_op0, 1, &XEXP (x, 0), opnum, type,
+ ind_levels);
+ find_reloads_address_1 (orig_op1, 0, &XEXP (x, 1), opnum, type,
+ ind_levels);
+ }
+ }
+
+ else if (code0 == REG)
+ {
+ find_reloads_address_1 (orig_op0, 1, &XEXP (x, 0), opnum, type,
+ ind_levels);
+ find_reloads_address_1 (orig_op1, 0, &XEXP (x, 1), opnum, type,
+ ind_levels);
+ }
+
+ else if (code1 == REG)
+ {
+ find_reloads_address_1 (orig_op1, 1, &XEXP (x, 1), opnum, type,
+ ind_levels);
+ find_reloads_address_1 (orig_op0, 0, &XEXP (x, 0), opnum, type,
+ ind_levels);
+ }
+ }
+
+ return 0;
+
+ case POST_INC:
+ case POST_DEC:
+ case PRE_INC:
+ case PRE_DEC:
if (GET_CODE (XEXP (x, 0)) == REG)
{
register int regno = REGNO (XEXP (x, 0));
}
return value;
}
+
else if (GET_CODE (XEXP (x, 0)) == MEM)
{
/* This is probably the result of a substitution, by eliminate_regs,
return 1;
}
- }
- else if (code == MEM)
- {
- /* This is probably the result of a substitution, by eliminate_regs,
- of an equivalent address for a pseudo that was not allocated to a
- hard register. Verify that the specified address is valid and reload
- it into a register.
+ return 0;
- Since we know we are going to reload this item, don't decrement
- for the indirection level.
+ case MEM:
+ /* This is probably the result of a substitution, by eliminate_regs, of
+ an equivalent address for a pseudo that was not allocated to a hard
+ register. Verify that the specified address is valid and reload it
+ into a register.
+
+ Since we know we are going to reload this item, don't decrement for
+ the indirection level.
Note that this is actually conservative: it would be slightly more
efficient to use the value of SPILL_INDIRECT_LEVELS from
find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0),
opnum, type, ind_levels);
-
push_reload (*loc, NULL_RTX, loc, NULL_PTR,
context ? INDEX_REG_CLASS : BASE_REG_CLASS,
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
return 1;
- }
- else if (code == REG)
- {
- register int regno = REGNO (x);
- if (reg_equiv_constant[regno] != 0)
- {
- find_reloads_address_part (reg_equiv_constant[regno], loc,
- (context ? INDEX_REG_CLASS
- : BASE_REG_CLASS),
- GET_MODE (x), opnum, type, ind_levels);
- return 1;
- }
+ case REG:
+ {
+ register int regno = REGNO (x);
+
+ if (reg_equiv_constant[regno] != 0)
+ {
+ find_reloads_address_part (reg_equiv_constant[regno], loc,
+ (context ? INDEX_REG_CLASS
+ : BASE_REG_CLASS),
+ GET_MODE (x), opnum, type, ind_levels);
+ return 1;
+ }
#if 0 /* This might screw code in reload1.c to delete prior output-reload
that feeds this insn. */
- if (reg_equiv_mem[regno] != 0)
- {
- push_reload (reg_equiv_mem[regno], NULL_RTX, loc, NULL_PTR,
- context ? INDEX_REG_CLASS : BASE_REG_CLASS,
- GET_MODE (x), VOIDmode, 0, 0, opnum, type);
- return 1;
- }
+ if (reg_equiv_mem[regno] != 0)
+ {
+ push_reload (reg_equiv_mem[regno], NULL_RTX, loc, NULL_PTR,
+ context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+ GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+ return 1;
+ }
#endif
- if (reg_equiv_address[regno] != 0)
- {
- x = make_memloc (x, regno);
- find_reloads_address (GET_MODE (x), 0, XEXP (x, 0), &XEXP (x, 0),
- opnum, type, ind_levels);
- }
- if (reg_renumber[regno] >= 0)
- regno = reg_renumber[regno];
- if ((regno >= FIRST_PSEUDO_REGISTER
- || !(context ? REGNO_OK_FOR_INDEX_P (regno)
- : REGNO_OK_FOR_BASE_P (regno))))
- {
- push_reload (x, NULL_RTX, loc, NULL_PTR,
- context ? INDEX_REG_CLASS : BASE_REG_CLASS,
- GET_MODE (x), VOIDmode, 0, 0, opnum, type);
- return 1;
- }
+ if (reg_equiv_address[regno] != 0)
+ {
+ x = make_memloc (x, regno);
+ find_reloads_address (GET_MODE (x), 0, XEXP (x, 0), &XEXP (x, 0),
+ opnum, type, ind_levels);
+ }
- /* If a register appearing in an address is the subject of a CLOBBER
- in this insn, reload it into some other register to be safe.
- The CLOBBER is supposed to make the register unavailable
- from before this insn to after it. */
- if (regno_clobbered_p (regno, this_insn))
- {
- push_reload (x, NULL_RTX, loc, NULL_PTR,
- context ? INDEX_REG_CLASS : BASE_REG_CLASS,
- GET_MODE (x), VOIDmode, 0, 0, opnum, type);
- return 1;
- }
- }
- else
- {
- register char *fmt = GET_RTX_FORMAT (code);
- register int i;
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ if (reg_renumber[regno] >= 0)
+ regno = reg_renumber[regno];
+
+ if ((regno >= FIRST_PSEUDO_REGISTER
+ || !(context ? REGNO_OK_FOR_INDEX_P (regno)
+ : REGNO_OK_FOR_BASE_P (regno))))
+ {
+ push_reload (x, NULL_RTX, loc, NULL_PTR,
+ context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+ GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+ return 1;
+ }
+
+ /* If a register appearing in an address is the subject of a CLOBBER
+ in this insn, reload it into some other register to be safe.
+ The CLOBBER is supposed to make the register unavailable
+ from before this insn to after it. */
+ if (regno_clobbered_p (regno, this_insn))
+ {
+ push_reload (x, NULL_RTX, loc, NULL_PTR,
+ context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+ GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+ return 1;
+ }
+ }
+ return 0;
+
+ case SUBREG:
+ /* If this is a SUBREG of a hard register and the resulting register is
+ of the wrong class, reload the whole SUBREG. This avoids needless
+ copies if SUBREG_REG is multi-word. */
+ if (GET_CODE (SUBREG_REG (x)) == REG
+ && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
{
- if (fmt[i] == 'e')
- find_reloads_address_1 (XEXP (x, i), context, &XEXP (x, i),
- opnum, type, ind_levels);
+ int regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
+
+ if (! (context ? REGNO_OK_FOR_INDEX_P (regno)
+ : REGNO_OK_FOR_BASE_P (regno)))
+ {
+ push_reload (x, NULL_RTX, loc, NULL_PTR,
+ context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+ GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+ return 1;
+ }
}
+ break;
}
+ {
+ register char *fmt = GET_RTX_FORMAT (code);
+ register int i;
+
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ find_reloads_address_1 (XEXP (x, i), context, &XEXP (x, i),
+ opnum, type, ind_levels);
+ }
+ }
+
return 0;
}
\f
\f
/* Return nonzero if register in range [REGNO, ENDREGNO)
appears either explicitly or implicitly in X
- other than being stored into.
+ other than being stored into (except for earlyclobber operands).
References contained within the substructure at LOC do not count.
LOC may be zero, meaning don't ignore anything.
&& refers_to_regno_for_reload_p (regno, endregno,
SUBREG_REG (SET_DEST (x)),
loc))
- || (GET_CODE (SET_DEST (x)) != REG
+ /* If the ouput is an earlyclobber operand, this is
+ a conflict. */
+ || ((GET_CODE (SET_DEST (x)) != REG
+ || earlyclobber_operand_p (SET_DEST (x)))
&& refers_to_regno_for_reload_p (regno, endregno,
SET_DEST (x), loc))))
return 1;