/* Search an insn for pseudo regs that must be in hard regs and are not.
- Copyright (C) 1987, 88, 89, 92-6, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
#define REG_OK_STRICT
-#include <stdio.h>
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "insn-config.h"
#include "insn-codes.h"
#include "flags.h"
#include "real.h"
#include "output.h"
+#include "expr.h"
+#include "toplev.h"
#ifndef REGISTER_MOVE_COST
#define REGISTER_MOVE_COST(x, y) 2
reload_optional char, nonzero for an optional reload.
Optional reloads are ignored unless the
value is already sitting in a register.
+ reload_nongroup char, nonzero when a reload must use a register
+ not already allocated to a group.
reload_inc int, positive amount to increment or decrement by if
reload_in is a PRE_DEC, PRE_INC, POST_DEC, POST_INC.
Ignored otherwise (don't assume it is zero).
enum machine_mode reload_outmode[MAX_RELOADS];
rtx reload_reg_rtx[MAX_RELOADS];
char reload_optional[MAX_RELOADS];
+char reload_nongroup[MAX_RELOADS];
int reload_inc[MAX_RELOADS];
rtx reload_in_reg[MAX_RELOADS];
char reload_nocombine[MAX_RELOADS];
static int hard_regs_live_known;
/* Indexed by hard reg number,
- element is nonegative if hard reg has been spilled.
+ element is nonnegative if hard reg has been spilled.
This vector is passed to `find_reloads' as an argument
and is not changed here. */
static short *static_reload_reg_p;
? RELOAD_FOR_OUTADDR_ADDRESS \
: (type)))
+#ifdef HAVE_SECONDARY_RELOADS
static int push_secondary_reload PROTO((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,
enum machine_mode, 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));
+ 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 rtx find_reloads_toplev PROTO((rtx, int, enum reload_type, int, int));
static rtx make_memloc PROTO((rtx, int));
static int find_reloads_address PROTO((enum machine_mode, rtx *, rtx, rtx *,
- int, enum reload_type, int));
+ int, enum reload_type, int, rtx));
static rtx subst_reg_equivs PROTO((rtx));
static rtx subst_indexed_address PROTO((rtx));
static int find_reloads_address_1 PROTO((enum machine_mode, rtx, int, rtx *,
- int, enum reload_type,int));
+ int, enum reload_type,int, rtx));
static void find_reloads_address_part PROTO((rtx, rtx *, enum reg_class,
enum machine_mode, int,
enum reload_type, int));
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
== 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
- || SMALL_REGISTER_CLASSES
-#endif
- )
+ && (reg_class_size[(int) t_class] == 1 || SMALL_REGISTER_CLASSES)
&& MERGABLE_RELOADS (secondary_type,
reload_when_needed[t_reload],
opnum, reload_opnum[t_reload]))
reload_outmode[t_reload] = ! in_p ? t_mode : VOIDmode;
reload_reg_rtx[t_reload] = 0;
reload_optional[t_reload] = optional;
+ reload_nongroup[t_reload] = 0;
reload_inc[t_reload] = 0;
/* Maybe we could combine these, but it seems too tricky. */
reload_nocombine[t_reload] = 1;
|| (! 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
- || SMALL_REGISTER_CLASSES
-#endif
- )
+ && (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES)
&& MERGABLE_RELOADS (secondary_type, reload_when_needed[s_reload],
opnum, reload_opnum[s_reload]))
{
if (s_reload == n_reloads)
{
+#ifdef SECONDARY_MEMORY_NEEDED
+ /* If we need a memory location to copy between the two reload regs,
+ set it up now. Note that we do the input case before making
+ the reload and the output case after. This is due to the
+ way reloads are output. */
+
+ if (in_p && icode == CODE_FOR_nothing
+ && SECONDARY_MEMORY_NEEDED (class, reload_class, mode))
+ get_secondary_mem (x, reload_mode, opnum, type);
+#endif
+
/* 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_outmode[s_reload] = ! in_p ? mode : VOIDmode;
reload_reg_rtx[s_reload] = 0;
reload_optional[s_reload] = optional;
+ reload_nongroup[s_reload] = 0;
reload_inc[s_reload] = 0;
/* Maybe we could combine these, but it seems too tricky. */
reload_nocombine[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, mode))
- get_secondary_mem (x, mode, opnum, type);
-
if (! in_p && icode == CODE_FOR_nothing
&& SECONDARY_MEMORY_NEEDED (reload_class, class, mode))
get_secondary_mem (x, mode, opnum, type);
/* Get a version of the address doing any eliminations needed. If that
didn't give us a new MEM, make a new one if it isn't valid. */
- loc = eliminate_regs (secondary_memlocs[(int) mode], VOIDmode, NULL_RTX, 0);
+ loc = eliminate_regs (secondary_memlocs[(int) mode], VOIDmode, NULL_RTX);
mem_valid = strict_memory_address_p (mode, XEXP (loc, 0));
if (! mem_valid && loc == secondary_memlocs[(int) mode])
: RELOAD_OTHER);
find_reloads_address (mode, NULL_PTR, XEXP (loc, 0), &XEXP (loc, 0),
- opnum, type, 0);
+ opnum, type, 0, 0);
}
secondary_memlocs_elim[(int) mode][opnum] = loc;
{
if (GET_CODE (XEXP (in, 0)) == POST_INC
|| GET_CODE (XEXP (in, 0)) == POST_DEC)
- in = gen_rtx (MEM, GET_MODE (in), XEXP (XEXP (in, 0), 0));
+ in = gen_rtx_MEM (GET_MODE (in), XEXP (XEXP (in, 0), 0));
if (GET_CODE (XEXP (in, 0)) == PRE_INC
|| GET_CODE (XEXP (in, 0)) == PRE_DEC)
- out = gen_rtx (MEM, GET_MODE (out), XEXP (XEXP (out, 0), 0));
+ out = gen_rtx_MEM (GET_MODE (out), XEXP (XEXP (out, 0), 0));
}
/* If we are reloading a (SUBREG constant ...), really reload just the
&& INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (in)))
&& LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (in))) != NIL)
#endif
+#ifdef WORD_REGISTER_OPERATIONS
+ || ((GET_MODE_SIZE (inmode)
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
+ && ((GET_MODE_SIZE (inmode) - 1) / UNITS_PER_WORD ==
+ ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) - 1)
+ / UNITS_PER_WORD)))
+#endif
))
|| (GET_CODE (SUBREG_REG (in)) == REG
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
in_subreg_loc = inloc;
inloc = &SUBREG_REG (in);
in = *inloc;
-#ifndef LOAD_EXTEND_OP
+#if ! defined (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS)
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. */
&& REGNO (SUBREG_REG (out)) >= FIRST_PSEUDO_REGISTER)
|| GET_CODE (SUBREG_REG (out)) == MEM)
&& ((GET_MODE_SIZE (outmode)
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
+#ifdef WORD_REGISTER_OPERATIONS
+ || ((GET_MODE_SIZE (outmode)
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
+ && ((GET_MODE_SIZE (outmode) - 1) / UNITS_PER_WORD ==
+ ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) - 1)
+ / UNITS_PER_WORD)))
+#endif
+ ))
|| (GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
&& ((GET_MODE_SIZE (outmode) <= UNITS_PER_WORD
out_subreg_loc = outloc;
outloc = &SUBREG_REG (out);
out = *outloc;
-#ifndef LOAD_EXTEND_OP
+#if ! defined (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS)
if (GET_CODE (out) == MEM
&& GET_MODE_SIZE (GET_MODE (out)) > GET_MODE_SIZE (outmode))
abort ();
if (in != 0 && GET_CODE (in) == SUBREG && GET_CODE (SUBREG_REG (in)) == REG
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
&& ! dont_remove_subreg)
- in = gen_rtx (REG, GET_MODE (in),
- REGNO (SUBREG_REG (in)) + SUBREG_WORD (in));
+ in = gen_rtx_REG (GET_MODE (in),
+ REGNO (SUBREG_REG (in)) + SUBREG_WORD (in));
/* Similarly for OUT. */
if (out != 0 && GET_CODE (out) == SUBREG
&& GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
&& ! dont_remove_subreg)
- out = gen_rtx (REG, GET_MODE (out),
- REGNO (SUBREG_REG (out)) + SUBREG_WORD (out));
+ out = gen_rtx_REG (GET_MODE (out),
+ REGNO (SUBREG_REG (out)) + SUBREG_WORD (out));
/* Narrow down the class of register wanted if that is
desirable on this machine for efficiency. */
||
(out != 0 && MATCHES (reload_out[i], out)
&& (in == 0 || reload_in[i] == 0 || MATCHES (reload_in[i], in))))
- && (reg_class_size[(int) class] == 1
-#ifdef SMALL_REGISTER_CLASSES
- || SMALL_REGISTER_CLASSES
-#endif
- )
+ && (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES)
&& MERGABLE_RELOADS (type, reload_when_needed[i],
opnum, reload_opnum[i]))
break;
|| GET_CODE (in) == PRE_INC
|| GET_CODE (in) == PRE_DEC)
&& MATCHES (XEXP (in, 0), reload_in[i])))
- && (reg_class_size[(int) class] == 1
-#ifdef SMALL_REGISTER_CLASSES
- || SMALL_REGISTER_CLASSES
-#endif
- )
+ && (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES)
&& MERGABLE_RELOADS (type, reload_when_needed[i],
opnum, reload_opnum[i]))
{
/* We found no existing reload suitable for re-use.
So add an additional reload. */
+#ifdef SECONDARY_MEMORY_NEEDED
+ /* If a memory location is needed for the copy, make one. */
+ if (in != 0 && GET_CODE (in) == REG
+ && REGNO (in) < FIRST_PSEUDO_REGISTER
+ && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)),
+ class, inmode))
+ get_secondary_mem (in, inmode, opnum, type);
+#endif
+
i = n_reloads;
reload_in[i] = in;
reload_out[i] = out;
reload_outmode[i] = outmode;
reload_reg_rtx[i] = 0;
reload_optional[i] = optional;
+ reload_nongroup[i] = 0;
reload_inc[i] = 0;
reload_nocombine[i] = 0;
reload_in_reg[i] = inloc ? *inloc : 0;
n_reloads++;
#ifdef SECONDARY_MEMORY_NEEDED
- /* If a memory location is needed for the copy, make one. */
- if (in != 0 && GET_CODE (in) == REG
- && REGNO (in) < FIRST_PSEUDO_REGISTER
- && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)),
- class, inmode))
- get_secondary_mem (in, inmode, opnum, type);
-
if (out != 0 && GET_CODE (out) == REG
&& REGNO (out) < FIRST_PSEUDO_REGISTER
&& SECONDARY_MEMORY_NEEDED (class, REGNO_REG_CLASS (REGNO (out)),
{
reload_reg_rtx[i] = find_dummy_reload (in, out, inloc, outloc,
inmode, outmode,
- reload_reg_class[i], i);
+ reload_reg_class[i], i,
+ earlyclobber_operand_p (out));
/* If the outgoing register already contains the same value
as the incoming one, we can dispense with loading it.
&& TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno)
&& !fixed_regs[regno])
{
- reload_reg_rtx[i] = gen_rtx (REG, inmode, regno);
+ reload_reg_rtx[i] = gen_rtx_REG (inmode, regno);
break;
}
}
replacements[i].what = to;
}
\f
+/* Remove all replacements in reload FROM. */
+void
+remove_replacements (from)
+ int from;
+{
+ int i, j;
+
+ for (i = 0, j = 0; i < n_replacements; i++)
+ {
+ if (replacements[i].what == from)
+ continue;
+ replacements[j++] = replacements[i];
+ }
+}
+\f
/* If there is only one output reload, and it is not for an earlyclobber
operand, try to combine it with a (logically unrelated) input reload
to reduce the number of reload registers needed.
|| rtx_equal_p (secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[i]],
secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]]))
#endif
- && (
-#ifdef SMALL_REGISTER_CLASSES
- SMALL_REGISTER_CLASSES
-#else
- 0
-#endif
- ? reload_reg_class[i] == reload_reg_class[output_reload]
- : (reg_class_subset_p (reload_reg_class[i],
- reload_reg_class[output_reload])
- || reg_class_subset_p (reload_reg_class[output_reload],
- reload_reg_class[i])))
+ && (SMALL_REGISTER_CLASSES
+ ? (reload_reg_class[i] == reload_reg_class[output_reload])
+ : (reg_class_subset_p (reload_reg_class[i],
+ reload_reg_class[output_reload])
+ || reg_class_subset_p (reload_reg_class[output_reload],
+ reload_reg_class[i])))
&& (MATCHES (reload_in[i], reload_out[output_reload])
/* Args reversed because the first arg seems to be
the one that we imagine being modified
&& reg_overlap_mentioned_for_reload_p (reload_in[i],
reload_out[output_reload]))))
&& (reg_class_size[(int) reload_reg_class[i]]
-#ifdef SMALL_REGISTER_CLASSES
- || SMALL_REGISTER_CLASSES
-#endif
- )
+ || SMALL_REGISTER_CLASSES)
/* We will allow making things slightly worse by combining an
input and an output, but no worse than that. */
&& (reload_when_needed[i] == RELOAD_FOR_INPUT
REGNO (XEXP (note, 0)))))))
&& ! fixed_regs[REGNO (XEXP (note, 0))])
{
- reload_reg_rtx[output_reload] = gen_rtx (REG,
- reload_outmode[output_reload],
- REGNO (XEXP (note, 0)));
+ reload_reg_rtx[output_reload]
+ = gen_rtx_REG (reload_outmode[output_reload],
+ REGNO (XEXP (note, 0)));
return;
}
}
to be computed, clear out reload_out[FOR_REAL].
If FOR_REAL is -1, this should not be done, because this call
- is just to see if a register can be found, not to find and install it. */
+ is just to see if a register can be found, not to find and install it.
+
+ EARLYCLOBBER is non-zero if OUT is an earlyclobber operand. This
+ puts an additional constraint on being able to use IN for OUT since
+ IN must not appear elsewhere in the insn (it is assumed that IN itself
+ is safe from the earlyclobber). */
static rtx
find_dummy_reload (real_in, real_out, inloc, outloc,
- inmode, outmode, class, for_real)
+ inmode, outmode, class, for_real, earlyclobber)
rtx real_in, real_out;
rtx *inloc, *outloc;
enum machine_mode inmode, outmode;
enum reg_class class;
int for_real;
+ int earlyclobber;
{
rtx in = real_in;
rtx out = real_out;
if (GET_CODE (real_out) == REG)
value = real_out;
else
- value = gen_rtx (REG, outmode, regno);
+ value = gen_rtx_REG (outmode, regno);
}
}
or if OUT dies in this insn (like the quotient in a divmod insn).
We can't use IN unless it is dies in this insn,
which means we must know accurately which hard regs are live.
- Also, the result can't go in IN if IN is used within OUT. */
+ Also, the result can't go in IN if IN is used within OUT,
+ or if OUT is an earlyclobber and IN appears elsewhere in the insn. */
if (hard_regs_live_known
&& GET_CODE (in) == REG
&& REGNO (in) < FIRST_PSEUDO_REGISTER
if (! refers_to_regno_for_reload_p (regno, regno + nwords, out, NULL_PTR)
&& ! hard_reg_set_here_p (regno, regno + nwords,
- PATTERN (this_insn)))
+ PATTERN (this_insn))
+ && (! earlyclobber
+ || ! refers_to_regno_for_reload_p (regno, regno + nwords,
+ PATTERN (this_insn), inloc)))
{
int i;
for (i = 0; i < nwords; i++)
if (GET_CODE (real_in) == REG)
value = real_in;
else
- value = gen_rtx (REG, inmode, regno);
+ value = gen_rtx_REG (inmode, regno);
}
}
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
- int val;
+ int val, j;
switch (fmt[i])
{
case 'w':
case '0':
break;
+ case 'E':
+ if (XVECLEN (x, i) != XVECLEN (y, i))
+ return 0;
+ for (j = XVECLEN (x, i) - 1; j >= 0; --j)
+ {
+ val = operands_match_p (XVECEXP (x, i, j), XVECEXP (y, i, j));
+ if (val == 0)
+ return 0;
+ if (val == 2)
+ success_2 = 1;
+ }
+ break;
+
/* It is believed that rtx's at this level will never
contain anything but integers and other rtx's,
except for within LABEL_REFs and SYMBOL_REFs. */
val.reg_flag = 0;
val.safe = 0;
+ val.base = 0;
if (GET_CODE (x) == MEM)
{
rtx base, offset = 0;
{
if (GET_CODE (XEXP (offset, 0)) == CONST_INT)
{
- base = gen_rtx (PLUS, GET_MODE (base), base, XEXP (offset, 1));
+ base = gen_rtx_PLUS (GET_MODE (base), base, XEXP (offset, 1));
offset = XEXP (offset, 0);
}
else if (GET_CODE (XEXP (offset, 1)) == CONST_INT)
{
- base = gen_rtx (PLUS, GET_MODE (base), base, XEXP (offset, 0));
+ base = gen_rtx_PLUS (GET_MODE (base), base, XEXP (offset, 0));
offset = XEXP (offset, 1);
}
else
{
- base = gen_rtx (PLUS, GET_MODE (base), base, offset);
+ base = gen_rtx_PLUS (GET_MODE (base), base, offset);
offset = const0_rtx;
}
}
else if (GET_CODE (offset) != CONST_INT)
{
- base = gen_rtx (PLUS, GET_MODE (base), base, offset);
+ base = gen_rtx_PLUS (GET_MODE (base), base, offset);
offset = const0_rtx;
}
if (all_const && GET_CODE (base) == PLUS)
- base = gen_rtx (CONST, GET_MODE (base), base);
+ base = gen_rtx_CONST (GET_MODE (base), base);
if (GET_CODE (offset) != CONST_INT)
abort ();
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;
enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
+ /* Cache the last regno for the last pseudo we did an output reload
+ for in case the next insn uses it. */
+ static int last_output_reload_regno = -1;
this_insn = insn;
this_insn_is_asm = 0; /* Tentative. */
{
error_for_asm (insn, "operand constraints differ in number of alternatives");
/* Avoid further trouble with this insn. */
- PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx);
+ PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
n_reloads = 0;
return;
}
/* Scan this operand's constraint to see if it is an output operand,
an in-out operand, is commutative, or should match another. */
- while (c = *p++)
+ while ((c = *p++))
{
if (c == '=')
modified[i] = RELOAD_WRITE;
{
find_reloads_address (VOIDmode, NULL_PTR,
recog_operand[i], recog_operand_loc[i],
- i, operand_type[i], ind_levels);
+ i, operand_type[i], ind_levels, insn);
/* If we now have a simple operand where we used to have a
PLUS or MULT, re-recognize and try again. */
recog_operand_loc[i],
XEXP (recog_operand[i], 0),
&XEXP (recog_operand[i], 0),
- i, address_type[i], ind_levels))
+ i, address_type[i], ind_levels, insn))
address_reloaded[i] = 1;
substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
}
else if (code == SUBREG)
- substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]
- = find_reloads_toplev (recog_operand[i], i, address_type[i],
- ind_levels,
- set != 0
- && &SET_DEST (set) == recog_operand_loc[i]);
+ {
+ rtx reg = SUBREG_REG (recog_operand[i]);
+ rtx op
+ = find_reloads_toplev (recog_operand[i], i, address_type[i],
+ ind_levels,
+ set != 0
+ && &SET_DEST (set) == recog_operand_loc[i]);
+
+ /* If we made a MEM to load (a part of) the stackslot of a pseudo
+ that didn't get a hard register, emit a USE with a REG_EQUAL
+ note in front so that we might inherit a previous, possibly
+ wider reload. */
+
+ if (GET_CODE (op) == MEM
+ && GET_CODE (reg) == REG
+ && (GET_MODE_SIZE (GET_MODE (reg))
+ >= GET_MODE_SIZE (GET_MODE (op))))
+ REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode, reg), insn))
+ = gen_rtx_EXPR_LIST (REG_EQUAL,
+ reg_equiv_memory_loc[REGNO (reg)], NULL_RTX);
+
+ substed_operand[i] = recog_operand[i] = *recog_operand_loc[i] = op;
+ }
else if (code == PLUS || GET_RTX_CLASS (code) == '1')
/* We can get a PLUS as an "operand" as a result of register
elimination. See eliminate_regs and gen_reload. We handle
register int regno = REGNO (recog_operand[i]);
if (reg_equiv_constant[regno] != 0
&& (set == 0 || &SET_DEST (set) != recog_operand_loc[i]))
- substed_operand[i] = recog_operand[i]
- = reg_equiv_constant[regno];
+ {
+ /* Record the existing mode so that the check if constants are
+ allowed will work when operand_mode isn't specified. */
+
+ if (operand_mode[i] == VOIDmode)
+ operand_mode[i] = GET_MODE (recog_operand[i]);
+
+ substed_operand[i] = recog_operand[i]
+ = reg_equiv_constant[regno];
+ }
#if 0 /* This might screw code in reload1.c to delete prior output-reload
that feeds this insn. */
if (reg_equiv_mem[regno] != 0)
substed_operand[i] = recog_operand[i]
= reg_equiv_mem[regno];
#endif
- if (reg_equiv_address[regno] != 0)
+ if (reg_equiv_address[regno] != 0
+ && (set == 0 || &SET_DEST (set) != recog_operand_loc[i]))
{
/* If reg_equiv_address is not a constant address, copy it,
since it may be shared. */
/* We must rerun eliminate_regs, in case the elimination
offsets have changed. */
rtx address = XEXP (eliminate_regs (reg_equiv_memory_loc[regno],
- 0, NULL_RTX, 0),
+ 0, NULL_RTX),
0);
if (rtx_varies_p (address))
address = copy_rtx (address);
- /* If this is an output operand, we must output a CLOBBER
- after INSN so find_equiv_reg knows REGNO is being written.
- Mark this insn specially, do we can put our output reloads
- after it. */
-
- if (modified[i] != RELOAD_READ)
- PUT_MODE (emit_insn_after (gen_rtx (CLOBBER, VOIDmode,
- recog_operand[i]),
- insn),
- DImode);
+ /* Emit a USE that shows what register is being used/modified. */
+ REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode,
+ recog_operand[i]),
+ insn))
+ = gen_rtx_EXPR_LIST (REG_EQUAL,
+ reg_equiv_memory_loc[regno],
+ NULL_RTX);
*recog_operand_loc[i] = recog_operand[i]
- = gen_rtx (MEM, GET_MODE (recog_operand[i]), address);
+ = gen_rtx_MEM (GET_MODE (recog_operand[i]), address);
RTX_UNCHANGING_P (recog_operand[i])
= RTX_UNCHANGING_P (regno_reg_rtx[regno]);
find_reloads_address (GET_MODE (recog_operand[i]),
recog_operand_loc[i],
XEXP (recog_operand[i], 0),
&XEXP (recog_operand[i], 0),
- i, address_type[i], ind_levels);
+ i, address_type[i], ind_levels, insn);
substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
}
}
or got the wrong kind of hard reg. For this, we must consider
all the operands together against the register constraints. */
- best = MAX_RECOG_OPERANDS + 300;
+ best = MAX_RECOG_OPERANDS * 2 + 600;
swapped = 0;
goal_alternative_swapped = 0;
int earlyclobber = 0;
/* If the predicate accepts a unary operator, it means that
- we need to reload the operand. */
- if (GET_RTX_CLASS (GET_CODE (operand)) == '1')
+ we need to reload the operand, but do not do this for
+ match_operator and friends. */
+ if (GET_RTX_CLASS (GET_CODE (operand)) == '1' && *p != 0)
operand = XEXP (operand, 0);
/* If the operand is a SUBREG, extract
{
offset += SUBREG_WORD (operand);
operand = SUBREG_REG (operand);
- /* Force reload if this is a constant or PLUS or if there may may
+ /* Force reload if this is a constant or PLUS or if there may
be a problem accessing OPERAND in the outer mode. */
if (CONSTANT_P (operand)
|| GET_CODE (operand) == PLUS
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. */
+ accesses.
+
+ This is doubly true if WORD_REGISTER_OPERATIONS. In
+ this case eliminate_regs has left non-paradoxical
+ subregs for push_reloads to see. Make sure it does
+ by forcing the reload.
+
+ ??? When is it right at this stage to have a subreg
+ of a mem that is _not_ to be handled specialy? IMO
+ those should have been reduced to just a mem. */
|| ((GET_CODE (operand) == MEM
|| (GET_CODE (operand)== REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER))
+#ifndef WORD_REGISTER_OPERATIONS
&& (((GET_MODE_BITSIZE (GET_MODE (operand))
< BIGGEST_ALIGNMENT)
&& (GET_MODE_SIZE (operand_mode[i])
&& INTEGRAL_MODE_P (GET_MODE (operand))
&& LOAD_EXTEND_OP (GET_MODE (operand)) != NIL)
#endif
- ))
+ )
+#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. */
break;
case '?':
- reject += 3;
+ reject += 6;
break;
case '!':
- reject = 300;
+ reject = 600;
break;
case '#':
[(i == commutative || i == commutative + 1)
? 2*commutative + 1 - i : i])
: operands_match[c][i])
- win = this_alternative_win[c];
+ {
+ /* If we are matching a non-offsettable address where an
+ offsettable address was expected, then we must reject
+ this combination, because we can't reload it. */
+ if (this_alternative_offmemok[c]
+ && GET_CODE (recog_operand[c]) == MEM
+ && this_alternative[c] == (int) NO_REGS
+ && ! this_alternative_win[c])
+ bad = 1;
+
+ win = this_alternative_win[c];
+ }
else
{
/* Operands don't match. */
= 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);
+ this_alternative[c], -1,
+ this_alternative_earlyclobber[c]);
if (value != 0)
losers--;
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (operand)] < 0))
win = 1;
- if (CONSTANT_P (operand))
+ if (CONSTANT_P (operand)
+ /* force_const_mem does not accept HIGH. */
+ && GET_CODE (operand) != HIGH)
badop = 0;
constmemok = 1;
break;
&& offsettable_memref_p (reg_equiv_mem[REGNO (operand)]))
|| (reg_equiv_address[REGNO (operand)] != 0))))
win = 1;
- if (CONSTANT_P (operand) || GET_CODE (operand) == MEM)
+ /* force_const_mem does not accept HIGH. */
+ if ((CONSTANT_P (operand) && GET_CODE (operand) != HIGH)
+ || GET_CODE (operand) == MEM)
badop = 0;
constmemok = 1;
offmemok = 1;
&& this_alternative_matches[i] < 0)
bad = 1;
- /* Alternative loses if it requires a type of reload not
- permitted for this insn. We can always reload SCRATCH
- and objects with a REG_UNUSED note. */
- if (GET_CODE (operand) != SCRATCH
- && modified[i] != RELOAD_READ && no_output_reloads
- && ! find_reg_note (insn, REG_UNUSED, operand))
- bad = 1;
- else if (modified[i] != RELOAD_WRITE && no_input_reloads)
- bad = 1;
+#if 0
+ /* If this is a pseudo-register that is set in the previous
+ insns, there's a good chance that it will already be in a
+ spill register and we can use that spill register. So
+ make this case cheaper.
+
+ Disabled for egcs. egcs has better inheritance code and
+ this change causes problems with the improved reload
+ inheritance code. */
+ if (GET_CODE (operand) == REG
+ && REGNO (operand) >= FIRST_PSEUDO_REGISTER
+ && REGNO (operand) == last_output_reload_regno)
+ reject--;
+#endif
/* If this is a constant that is reloaded into the desired
class by copying it to memory first, count that as another
if (CONSTANT_P (operand)
/* force_const_mem does not accept HIGH. */
&& GET_CODE (operand) != HIGH
- && (PREFERRED_RELOAD_CLASS (operand,
+ && ((PREFERRED_RELOAD_CLASS (operand,
(enum reg_class) this_alternative[i])
- == NO_REGS)
+ == NO_REGS)
+ || no_input_reloads)
&& operand_mode[i] != VOIDmode)
{
const_to_mem = 1;
== NO_REGS))
bad = 1;
+ /* Alternative loses if it requires a type of reload not
+ permitted for this insn. We can always reload SCRATCH
+ and objects with a REG_UNUSED note. */
+ else if (GET_CODE (operand) != SCRATCH
+ && modified[i] != RELOAD_READ && no_output_reloads
+ && ! find_reg_note (insn, REG_UNUSED, operand))
+ bad = 1;
+ else if (modified[i] != RELOAD_WRITE && no_input_reloads
+ && ! const_to_mem)
+ 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
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER)
&& GET_CODE (operand) != SCRATCH
&& ! (const_to_mem && constmemok))
+ reject += 2;
+
+ /* Input reloads can be inherited more often than output
+ reloads can be removed, so penalize output reloads. */
+ if (operand_type[i] != RELOAD_FOR_INPUT
+ && GET_CODE (operand) != SCRATCH)
reject++;
}
this_alternative[i]))
this_alternative[i] = (int) preferred_class[i];
else
- reject += (1 + pref_or_nothing[i]);
+ reject += (2 + 2 * pref_or_nothing[i]);
}
}
}
/* REJECT, set by the ! and ? constraint characters and when a register
would be reloaded into a non-preferred class, discourages the use of
- this alternative for a reload goal. REJECT is incremented by three
- for each ? and one for each non-preferred class. */
- losers = losers * 3 + reject;
+ this alternative for a reload goal. REJECT is incremented by six
+ for each ? and two for each non-preferred class. */
+ losers = losers * 6 + reject;
/* If this alternative can be made to work by reloading,
and it needs less reloading than the others checked so far,
that we could reach by reloading the fewest operands.
Reload so as to fit it. */
- if (best == MAX_RECOG_OPERANDS + 300)
+ if (best == MAX_RECOG_OPERANDS * 2 + 600)
{
/* No alternative works with reloads?? */
if (insn_code_number >= 0)
abort ();
error_for_asm (insn, "inconsistent operand constraints in an `asm'");
/* Avoid further trouble with this insn. */
- PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx);
+ PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
n_reloads = 0;
return;
}
a SCRATCH). In this case, we only need have the reload live
through the insn itself, but not for any of our input or output
reloads.
+ But we must not accidentally narrow the scope of an existing
+ RELOAD_OTHER reload - leave these alone.
In any case, anything needed to address this operand can remain
however they were previously categorized. */
- if (goal_alternative_earlyclobber[i])
+ if (goal_alternative_earlyclobber[i] && operand_type[i] != RELOAD_OTHER)
operand_type[i]
= (find_reg_note (insn, REG_UNUSED, recog_operand[i])
? RELOAD_FOR_INSN : RELOAD_OTHER);
&& CONSTANT_P (recog_operand[i])
/* force_const_mem does not accept HIGH. */
&& GET_CODE (recog_operand[i]) != HIGH
- && (PREFERRED_RELOAD_CLASS (recog_operand[i],
+ && ((PREFERRED_RELOAD_CLASS (recog_operand[i],
(enum reg_class) goal_alternative[i])
- == NO_REGS)
+ == NO_REGS)
+ || no_input_reloads)
&& operand_mode[i] != VOIDmode)
{
*recog_operand_loc[i] = recog_operand[i]
reload_earlyclobbers[n_earlyclobbers++] = recog_operand[i];
/* Now record reloads for all the operands that need them. */
+ last_output_reload_regno = -1;
for (i = 0; i < noperands; i++)
if (! goal_alternative_win[i])
{
}
}
else if (goal_alternative_matched[i] == -1)
- operand_reloadnum[i] =
- push_reload (modified[i] != RELOAD_WRITE ? recog_operand[i] : 0,
- modified[i] != RELOAD_READ ? recog_operand[i] : 0,
- (modified[i] != RELOAD_WRITE ?
- recog_operand_loc[i] : 0),
- modified[i] != RELOAD_READ ? recog_operand_loc[i] : 0,
- (enum reg_class) goal_alternative[i],
- (modified[i] == RELOAD_WRITE
- ? VOIDmode : operand_mode[i]),
- (modified[i] == RELOAD_READ
- ? VOIDmode : operand_mode[i]),
- (insn_code_number < 0 ? 0
- : insn_operand_strict_low[insn_code_number][i]),
- 0, i, operand_type[i]);
+ {
+ operand_reloadnum[i]
+ = push_reload ((modified[i] != RELOAD_WRITE
+ ? recog_operand[i] : 0),
+ modified[i] != RELOAD_READ ? recog_operand[i] : 0,
+ (modified[i] != RELOAD_WRITE
+ ? recog_operand_loc[i] : 0),
+ (modified[i] != RELOAD_READ
+ ? recog_operand_loc[i] : 0),
+ (enum reg_class) goal_alternative[i],
+ (modified[i] == RELOAD_WRITE
+ ? VOIDmode : operand_mode[i]),
+ (modified[i] == RELOAD_READ
+ ? VOIDmode : operand_mode[i]),
+ (insn_code_number < 0 ? 0
+ : insn_operand_strict_low[insn_code_number][i]),
+ 0, i, operand_type[i]);
+ if (modified[i] != RELOAD_READ
+ && GET_CODE (recog_operand[i]) == REG)
+ last_output_reload_regno = REGNO (recog_operand[i]);
+ }
/* In a matching pair of operands, one must be input only
and the other must be output only.
Pass the input operand as IN and the other as OUT. */
operand_mode[goal_alternative_matched[i]],
0, 0, i, RELOAD_OTHER);
operand_reloadnum[goal_alternative_matched[i]] = output_reloadnum;
+ if (GET_CODE (recog_operand[goal_alternative_matched[i]]) == REG)
+ last_output_reload_regno
+ = REGNO (recog_operand[goal_alternative_matched[i]]);
}
else if (modified[i] == RELOAD_WRITE
&& modified[goal_alternative_matched[i]] == RELOAD_READ)
operand_mode[i],
0, 0, i, RELOAD_OTHER);
operand_reloadnum[i] = output_reloadnum;
+ if (GET_CODE (recog_operand[i]) == REG)
+ last_output_reload_regno = REGNO (recog_operand[i]);
}
else if (insn_code_number >= 0)
abort ();
{
error_for_asm (insn, "inconsistent operand constraints in an `asm'");
/* Avoid further trouble with this insn. */
- PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx);
+ PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
n_reloads = 0;
return;
}
{
int secondary_in_reload = reload_secondary_in_reload[i];
- reload_when_needed[secondary_in_reload] =
- RELOAD_FOR_OPADDR_ADDR;
+ 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
{
int secondary_out_reload = reload_secondary_out_reload[i];
- reload_when_needed[secondary_out_reload] =
- RELOAD_FOR_OPADDR_ADDR;
+ 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_when_needed[reload_secondary_out_reload[secondary_out_reload]]
= RELOAD_FOR_OPADDR_ADDR;
}
- if (reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
- || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
- reload_when_needed[i] = RELOAD_FOR_OPADDR_ADDR;
- else
- reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
+
+ reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
}
if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
reload_opnum[i] = goal_alternative_matches[reload_opnum[i]];
}
+ /* Scan all the reloads, and check for RELOAD_FOR_OPERAND_ADDRESS reloads.
+ If we have more than one, then convert all RELOAD_FOR_OPADDR_ADDR
+ reloads to RELOAD_FOR_OPERAND_ADDRESS reloads.
+
+ choose_reload_regs assumes that RELOAD_FOR_OPADDR_ADDR reloads never
+ conflict with RELOAD_FOR_OPERAND_ADDRESS reloads. This is true for a
+ single pair of RELOAD_FOR_OPADDR_ADDR/RELOAD_FOR_OPERAND_ADDRESS reloads.
+ However, if there is more than one RELOAD_FOR_OPERAND_ADDRESS reload,
+ then a RELOAD_FOR_OPADDR_ADDR reload conflicts with all
+ RELOAD_FOR_OPERAND_ADDRESS reloads other than the one that uses it.
+ This is complicated by the fact that a single operand can have more
+ than one RELOAD_FOR_OPERAND_ADDRESS reload. It is very difficult to fix
+ choose_reload_regs without affecting code quality, and cases that
+ actually fail are extremely rare, so it turns out to be better to fix
+ the problem here by not generating cases that choose_reload_regs will
+ fail for. */
+ /* There is a similar problem with RELOAD_FOR_INPUT_ADDRESS /
+ RELOAD_FOR_OUTPUT_ADDRESS when there is more than one of a kind for
+ a single operand.
+ We can reduce the register pressure by exploiting that a
+ RELOAD_FOR_X_ADDR_ADDR that precedes all RELOAD_FOR_X_ADDRESS reloads
+ does not conflict with any of them. */
+ {
+ int first_op_addr_num = -2;
+ int first_inpaddr_num[MAX_RECOG_OPERANDS];
+ int first_outpaddr_num[MAX_RECOG_OPERANDS];
+ int need_change= 0;
+ /* We use last_op_addr_reload and the contents of the above arrays
+ first as flags - -2 means no instance encountered, -1 means exactly
+ one instance encountered.
+ If more than one instance has been encountered, we store the reload
+ number of the first reload of the kind in question; reload numbers
+ are known to be non-negative. */
+ for (i = 0; i < noperands; i++)
+ first_inpaddr_num[i] = first_outpaddr_num[i] = -2;
+ for (i = n_reloads - 1; i >= 0; i--)
+ {
+ switch (reload_when_needed[i])
+ {
+ case RELOAD_FOR_OPERAND_ADDRESS:
+ if (! ++first_op_addr_num)
+ {
+ first_op_addr_num= i;
+ need_change = 1;
+ }
+ break;
+ case RELOAD_FOR_INPUT_ADDRESS:
+ if (! ++first_inpaddr_num[reload_opnum[i]])
+ {
+ first_inpaddr_num[reload_opnum[i]] = i;
+ need_change = 1;
+ }
+ break;
+ case RELOAD_FOR_OUTPUT_ADDRESS:
+ if (! ++first_outpaddr_num[reload_opnum[i]])
+ {
+ first_outpaddr_num[reload_opnum[i]] = i;
+ need_change = 1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (need_change)
+ {
+ for (i = 0; i < n_reloads; i++)
+ {
+ int first_num, type;
+
+ switch (reload_when_needed[i])
+ {
+ case RELOAD_FOR_OPADDR_ADDR:
+ first_num = first_op_addr_num;
+ type = RELOAD_FOR_OPERAND_ADDRESS;
+ break;
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ first_num = first_inpaddr_num[reload_opnum[i]];
+ type = RELOAD_FOR_INPUT_ADDRESS;
+ break;
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ first_num = first_outpaddr_num[reload_opnum[i]];
+ type = RELOAD_FOR_OUTPUT_ADDRESS;
+ break;
+ default:
+ continue;
+ }
+ if (i > first_num)
+ reload_when_needed[i] = type;
+ }
+ }
+ }
+
/* See if we have any reloads that are now allowed to be merged
because we've changed when the reload is needed to
RELOAD_FOR_OPERAND_ADDRESS or RELOAD_FOR_OTHER_ADDRESS. Only
reload_in[j] = 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. */
+
+ changed = 0;
+ for (i = 0; i < n_reloads; i++)
+ {
+ enum machine_mode mode = reload_inmode[i];
+ enum reg_class class = reload_reg_class[i];
+ int size;
+
+ if (GET_MODE_SIZE (reload_outmode[i]) > GET_MODE_SIZE (mode))
+ mode = reload_outmode[i];
+ size = CLASS_MAX_NREGS (class, mode);
+
+ if (size == 1)
+ for (j = 0; j < n_reloads; j++)
+ if ((CLASS_MAX_NREGS (reload_reg_class[j],
+ (GET_MODE_SIZE (reload_outmode[j])
+ > GET_MODE_SIZE (reload_inmode[j]))
+ ? reload_outmode[j] : reload_inmode[j])
+ > 1)
+ && !reload_optional[j]
+ && (reload_in[j] != 0 || reload_out[j] != 0
+ || reload_secondary_p[j])
+ && reloads_conflict (i, j)
+ && reg_classes_intersect_p (class, reload_reg_class[j]))
+ {
+ reload_nongroup[i] = 1;
+ changed = 1;
+ break;
+ }
+ }
+
+ while (changed)
+ {
+ changed = 0;
+
+ for (i = 0; i < n_reloads; i++)
+ {
+ enum machine_mode mode = reload_inmode[i];
+ enum reg_class class = reload_reg_class[i];
+ int size;
+
+ if (GET_MODE_SIZE (reload_outmode[i]) > GET_MODE_SIZE (mode))
+ mode = reload_outmode[i];
+ size = CLASS_MAX_NREGS (class, mode);
+
+ if (! reload_nongroup[i] && size == 1)
+ for (j = 0; j < n_reloads; j++)
+ if (reload_nongroup[j]
+ && reloads_conflict (i, j)
+ && reg_classes_intersect_p (class, reload_reg_class[j]))
+ {
+ reload_nongroup[i] = 1;
+ changed = 1;
+ break;
+ }
+ }
+ }
+
#else /* no REGISTER_CONSTRAINTS */
int noperands;
int insn_code_number;
if (insn_operand_address_p[insn_code_number][i])
find_reloads_address (VOIDmode, NULL_PTR,
recog_operand[i], recog_operand_loc[i],
- i, RELOAD_FOR_INPUT, ind_levels);
+ i, RELOAD_FOR_INPUT, ind_levels, insn);
/* In these cases, we can't tell if the operand is an input
or an output, so be conservative. In practice it won't be
recog_operand_loc[i],
XEXP (recog_operand[i], 0),
&XEXP (recog_operand[i], 0),
- i, RELOAD_OTHER, ind_levels);
+ i, RELOAD_OTHER, ind_levels, insn);
if (code == SUBREG)
recog_operand[i] = *recog_operand_loc[i]
= find_reloads_toplev (recog_operand[i], i, RELOAD_OTHER,
/* We must rerun eliminate_regs, in case the elimination
offsets have changed. */
rtx addr = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0,
- NULL_RTX, 0),
+ NULL_RTX),
0);
if (rtx_varies_p (addr))
addr = copy_rtx (addr);
- x = gen_rtx (MEM, GET_MODE (x), addr);
+ x = gen_rtx_MEM (GET_MODE (x), addr);
RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
find_reloads_address (GET_MODE (x), NULL_PTR,
XEXP (x, 0),
- &XEXP (x, 0), opnum, type, ind_levels);
+ &XEXP (x, 0), opnum, type, ind_levels, 0);
}
return x;
}
{
rtx tem = x;
find_reloads_address (GET_MODE (x), &tem, XEXP (x, 0), &XEXP (x, 0),
- opnum, type, ind_levels);
+ opnum, type, ind_levels, 0);
return tem;
}
&& (tem = operand_subword (reg_equiv_constant[regno],
SUBREG_WORD (x), 0,
GET_MODE (SUBREG_REG (x)))) != 0)
- return tem;
+ {
+ /* TEM is now a word sized constant for the bits from X that
+ we wanted. However, TEM may be the wrong representation.
+
+ Use gen_lowpart_common to convert a CONST_INT into a
+ CONST_DOUBLE and vice versa as needed according to by the mode
+ of the SUBREG. */
+ tem = gen_lowpart_common (GET_MODE (x), tem);
+ if (!tem)
+ abort ();
+ return tem;
+ }
+
+ /* If the SUBREG is wider than a word, the above test will fail.
+ For example, we might have a SImode SUBREG of a DImode SUBREG_REG
+ for a 16 bit target, or a DImode SUBREG of a TImode SUBREG_REG for
+ a 32 bit target. We still can - and have to - handle this
+ for non-paradoxical subregs of CONST_INTs. */
+ if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
+ && reg_equiv_constant[regno] != 0
+ && GET_CODE (reg_equiv_constant[regno]) == CONST_INT
+ && (GET_MODE_SIZE (GET_MODE (x))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+ {
+ int shift = SUBREG_WORD (x) * BITS_PER_WORD;
+ if (WORDS_BIG_ENDIAN)
+ shift = (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
+ - GET_MODE_BITSIZE (GET_MODE (x))
+ - shift);
+ /* Here we use the knowledge that CONST_INTs have a
+ HOST_WIDE_INT field. */
+ if (shift >= HOST_BITS_PER_WIDE_INT)
+ shift = HOST_BITS_PER_WIDE_INT - 1;
+ return GEN_INT (INTVAL (reg_equiv_constant[regno]) >> shift);
+ }
if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0
/* We must rerun eliminate_regs, in case the elimination
offsets have changed. */
rtx addr = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0,
- NULL_RTX, 0),
+ NULL_RTX),
0);
if (BYTES_BIG_ENDIAN)
{
offset -= MIN (size, UNITS_PER_WORD);
}
addr = plus_constant (addr, offset);
- x = gen_rtx (MEM, GET_MODE (x), addr);
+ x = gen_rtx_MEM (GET_MODE (x), addr);
RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
find_reloads_address (GET_MODE (x), NULL_PTR,
XEXP (x, 0),
- &XEXP (x, 0), opnum, type, ind_levels);
+ &XEXP (x, 0), opnum, type, ind_levels, 0);
}
}
rtx ad;
int regno;
{
+#if 0
register int i;
+#endif
/* We must rerun eliminate_regs, in case the elimination
offsets have changed. */
- rtx tem = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0, NULL_RTX, 0),
- 0);
+ rtx tem = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0, NULL_RTX), 0);
#if 0 /* We cannot safely reuse a memloc made here;
if the pseudo appears twice, and its mem needs a reload,
if (rtx_varies_p (tem))
tem = copy_rtx (tem);
- tem = gen_rtx (MEM, GET_MODE (ad), tem);
+ tem = gen_rtx_MEM (GET_MODE (ad), tem);
RTX_UNCHANGING_P (tem) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
memlocs[n_memlocs++] = tem;
return tem;
IND_LEVELS says how many levels of indirect addressing this machine
supports.
+ INSN, if nonzero, is the insn in which we do the reload. It is used
+ to determine if we may generate output reloads.
+
Value is nonzero if this address is reloaded or replaced as a whole.
This is interesting to the caller if the address is an autoincrement.
to a hard register, and frame pointer elimination. */
static int
-find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
+find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
enum machine_mode mode;
rtx *memrefloc;
rtx ad;
int opnum;
enum reload_type type;
int ind_levels;
+ rtx insn;
{
register int regno;
rtx tem;
tem = make_memloc (ad, regno);
find_reloads_address (GET_MODE (tem), NULL_PTR, XEXP (tem, 0),
&XEXP (tem, 0), opnum, ADDR_TYPE (type),
- ind_levels);
+ ind_levels, insn);
push_reload (tem, NULL_RTX, loc, NULL_PTR,
reload_address_base_reg_class,
GET_MODE (ad), VOIDmode, 0, 0,
return 0;
}
+#ifdef LEGITIMIZE_RELOAD_ADDRESS
+ do
+ {
+ if (memrefloc)
+ {
+ LEGITIMIZE_RELOAD_ADDRESS (ad, GET_MODE (*memrefloc), opnum, type,
+ ind_levels, win);
+ }
+ break;
+ win:
+ *memrefloc = copy_rtx (*memrefloc);
+ XEXP (*memrefloc, 0) = ad;
+ move_replacements (&ad, &XEXP (*memrefloc, 0));
+ return 1;
+ }
+ while (0);
+#endif
+
/* The address is not valid. We have to figure out why. One possibility
is that it is itself a MEM. This can happen when the frame pointer is
being eliminated, a pseudo is not allocated to a hard register, and the
tem = ad;
find_reloads_address (GET_MODE (ad), &tem, XEXP (ad, 0), &XEXP (ad, 0),
opnum, ADDR_TYPE (type),
- ind_levels == 0 ? 0 : ind_levels - 1);
+ ind_levels == 0 ? 0 : ind_levels - 1, insn);
/* If tem was changed, then we must create a new memory reference to
hold it and store it back into memrefloc. */
|| XEXP (XEXP (ad, 0), 0) == stack_pointer_rtx)
&& ! memory_address_p (mode, ad))
{
- *loc = ad = gen_rtx (PLUS, GET_MODE (ad),
- plus_constant (XEXP (XEXP (ad, 0), 0),
- INTVAL (XEXP (ad, 1))),
+ *loc = ad = gen_rtx_PLUS (GET_MODE (ad),
+ plus_constant (XEXP (XEXP (ad, 0), 0),
+ INTVAL (XEXP (ad, 1))),
XEXP (XEXP (ad, 0), 1));
find_reloads_address_part (XEXP (ad, 0), &XEXP (ad, 0),
reload_address_base_reg_class,
GET_MODE (ad), opnum, type, ind_levels);
find_reloads_address_1 (mode, XEXP (ad, 1), 1, &XEXP (ad, 1), opnum,
- type, 0);
+ type, 0, insn);
return 1;
}
|| XEXP (XEXP (ad, 0), 1) == stack_pointer_rtx)
&& ! 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))));
+ *loc = ad = gen_rtx_PLUS (GET_MODE (ad),
+ XEXP (XEXP (ad, 0), 0),
+ plus_constant (XEXP (XEXP (ad, 0), 1),
+ INTVAL (XEXP (ad, 1))));
find_reloads_address_part (XEXP (ad, 1), &XEXP (ad, 1),
reload_address_base_reg_class,
GET_MODE (ad), opnum, type, ind_levels);
find_reloads_address_1 (mode, XEXP (ad, 0), 1, &XEXP (ad, 0), opnum,
- type, 0);
+ type, 0, insn);
return 1;
}
return 1;
}
- return find_reloads_address_1 (mode, ad, 0, loc, opnum, type, ind_levels);
+ return find_reloads_address_1 (mode, ad, 0, loc, opnum, type, ind_levels,
+ insn);
}
\f
/* Find all pseudo regs appearing in AD
if (XEXP (ad, 0) == frame_pointer_rtx
&& GET_CODE (XEXP (ad, 1)) == CONST_INT)
return ad;
+ break;
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
if (GET_CODE (y) == CONST)
y = XEXP (y, 0);
- return gen_rtx (CONST, VOIDmode, gen_rtx (PLUS, mode, x, y));
+ return gen_rtx_CONST (VOIDmode, gen_rtx_PLUS (mode, x, y));
}
- return gen_rtx (PLUS, mode, x, y);
+ return gen_rtx_PLUS (mode, x, y);
}
\f
/* If ADDR is a sum containing a pseudo register that should be
IND_LEVELS says how many levels of indirect addressing are
supported at this point in the address.
+ INSN, if nonzero, is the insn in which we do the reload. It is used
+ to determine if we may generate output reloads.
+
We return nonzero if X, as a whole, is reloaded or replaced. */
/* Note that we take shortcuts assuming that no multi-reg machine mode
could have addressing modes that this does not handle right. */
static int
-find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels)
+find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
enum machine_mode mode;
rtx x;
int context;
int opnum;
enum reload_type type;
int ind_levels;
+ rtx insn;
{
register RTX_CODE code = GET_CODE (x);
op0 = SUBREG_REG (op0);
code0 = GET_CODE (op0);
if (code0 == REG && REGNO (op0) < FIRST_PSEUDO_REGISTER)
- op0 = gen_rtx (REG, word_mode,
- REGNO (op0) + SUBREG_WORD (orig_op0));
+ op0 = gen_rtx_REG (word_mode,
+ REGNO (op0) + SUBREG_WORD (orig_op0));
}
if (GET_CODE (op1) == SUBREG)
op1 = SUBREG_REG (op1);
code1 = GET_CODE (op1);
if (code1 == REG && REGNO (op1) < FIRST_PSEUDO_REGISTER)
- op1 = gen_rtx (REG, GET_MODE (op1),
- REGNO (op1) + SUBREG_WORD (orig_op1));
+ op1 = gen_rtx_REG (GET_MODE (op1),
+ REGNO (op1) + SUBREG_WORD (orig_op1));
}
if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
|| code0 == ZERO_EXTEND || code1 == MEM)
{
find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
}
else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE
|| code1 == ZERO_EXTEND || code0 == MEM)
{
find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
}
else if (code0 == CONST_INT || code0 == CONST
|| code0 == SYMBOL_REF || code0 == LABEL_REF)
find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
else if (code1 == CONST_INT || code1 == CONST
|| code1 == SYMBOL_REF || code1 == LABEL_REF)
find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
else if (code0 == REG && code1 == REG)
{
return 0;
else if (REG_MODE_OK_FOR_BASE_P (op1, mode))
find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
else if (REG_MODE_OK_FOR_BASE_P (op0, mode))
find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
else if (REG_OK_FOR_INDEX_P (op1))
find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
else if (REG_OK_FOR_INDEX_P (op0))
find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
else
{
find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
}
}
else if (code0 == REG)
{
find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
}
else if (code1 == REG)
{
find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
- type, ind_levels);
+ type, ind_levels, insn);
}
}
need two registers. */
find_reloads_address (GET_MODE (tem), 0, XEXP (tem, 0),
&XEXP (tem, 0), opnum, type,
- ind_levels);
+ ind_levels, insn);
/* Put this inside a new increment-expression. */
- x = gen_rtx (GET_CODE (x), GET_MODE (x), tem);
+ x = gen_rtx_fmt_e (GET_CODE (x), GET_MODE (x), tem);
/* Proceed to reload that, as if it contained a register. */
}
|| !(context ? REGNO_OK_FOR_INDEX_P (regno)
: REGNO_MODE_OK_FOR_BASE_P (regno, mode))))
{
+#ifdef AUTO_INC_DEC
register rtx link;
-
- int reloadnum
- = push_reload (x, NULL_RTX, loc, NULL_PTR,
- (context
- ? reload_address_index_reg_class
- : reload_address_base_reg_class),
- GET_MODE (x), GET_MODE (x), VOIDmode, 0,
- opnum, type);
- reload_inc[reloadnum]
- = find_inc_amount (PATTERN (this_insn), XEXP (x_orig, 0));
-
- value = 1;
+#endif
+ int reloadnum;
+
+ /* If we can output the register afterwards, do so, this
+ saves the extra update.
+ We can do so if we have an INSN - i.e. no JUMP_INSN nor
+ CALL_INSN - and it does not set CC0.
+ But don't do this if we cannot directly address the
+ memory location, since this will make it harder to
+ reuse address reloads, and increases register pressure.
+ Also don't do this if we can probably update x directly. */
+ rtx equiv = reg_equiv_mem[regno];
+ int icode = (int) add_optab->handlers[(int) Pmode].insn_code;
+ if (insn && GET_CODE (insn) == INSN && equiv
+#ifdef HAVE_cc0
+ && ! sets_cc0_p (PATTERN (insn))
+#endif
+ && ! (icode != CODE_FOR_nothing
+ && (*insn_operand_predicate[icode][0]) (equiv, Pmode)
+ && (*insn_operand_predicate[icode][1]) (equiv, Pmode)))
+ {
+ loc = &XEXP (x, 0);
+ x = XEXP (x, 0);
+ reloadnum
+ = push_reload (x, x, loc, loc,
+ (context
+ ? reload_address_index_reg_class
+ : reload_address_base_reg_class),
+ GET_MODE (x), GET_MODE (x), 0, 0,
+ opnum, RELOAD_OTHER);
+ }
+ else
+ {
+ reloadnum
+ = push_reload (x, NULL_RTX, loc, NULL_PTR,
+ (context
+ ? reload_address_index_reg_class
+ : reload_address_base_reg_class),
+ GET_MODE (x), GET_MODE (x), 0, 0,
+ opnum, type);
+ reload_inc[reloadnum]
+ = find_inc_amount (PATTERN (this_insn), XEXP (x_orig, 0));
+
+ value = 1;
+ }
#ifdef AUTO_INC_DEC
/* Update the REG_INC notes. */
need two registers. */
find_reloads_address (GET_MODE (x), &XEXP (x, 0),
XEXP (XEXP (x, 0), 0), &XEXP (XEXP (x, 0), 0),
- opnum, type, ind_levels);
+ opnum, type, ind_levels, insn);
reloadnum = push_reload (x, NULL_RTX, loc, NULL_PTR,
(context
reload1.c here. */
find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0),
- opnum, ADDR_TYPE (type), ind_levels);
+ opnum, ADDR_TYPE (type), ind_levels, insn);
push_reload (*loc, NULL_RTX, loc, NULL_PTR,
(context ? reload_address_index_reg_class
: reload_address_base_reg_class),
{
x = make_memloc (x, regno);
find_reloads_address (GET_MODE (x), 0, XEXP (x, 0), &XEXP (x, 0),
- opnum, ADDR_TYPE (type), ind_levels);
+ opnum, ADDR_TYPE (type), ind_levels, insn);
}
if (reg_renumber[regno] >= 0)
}
}
break;
+
+ default:
+ break;
}
{
{
if (fmt[i] == 'e')
find_reloads_address_1 (mode, XEXP (x, i), context, &XEXP (x, i),
- opnum, type, ind_levels);
+ opnum, type, ind_levels, insn);
}
}
{
rtx tem = x = force_const_mem (mode, x);
find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
- opnum, type, ind_levels);
+ opnum, type, ind_levels, 0);
}
else if (GET_CODE (x) == PLUS
{
rtx tem = force_const_mem (GET_MODE (x), XEXP (x, 1));
- x = gen_rtx (PLUS, GET_MODE (x), XEXP (x, 0), tem);
+ x = gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0), tem);
find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
- opnum, type, ind_levels);
+ opnum, type, ind_levels, 0);
}
push_reload (x, NULL_RTX, loc, NULL_PTR, class,
do the wrong thing if RELOADREG is multi-word. RELOADREG
will always be a REG here. */
if (GET_MODE (reloadreg) != r->mode && r->mode != VOIDmode)
- reloadreg = gen_rtx (REG, r->mode, REGNO (reloadreg));
+ reloadreg = gen_rtx_REG (r->mode, REGNO (reloadreg));
/* If we are putting this into a SUBREG and RELOADREG is a
SUBREG, we would be making nested SUBREGs, so we have to fix
}
}
}
+
+/* Change any replacements being done to *X to be done to *Y */
+
+void
+move_replacements (x, y)
+ rtx *x;
+ rtx *y;
+{
+ int i;
+
+ for (i = 0; i < n_replacements; i++)
+ if (replacements[i].subreg_loc == x)
+ replacements[i].subreg_loc = y;
+ else if (replacements[i].where == x)
+ {
+ replacements[i].where = y;
+ replacements[i].subreg_loc = 0;
+ }
+}
\f
/* If LOC was scheduled to be replaced by something, return the replacement.
Otherwise, return *LOC. */
if (reloadreg && r->where == loc)
{
if (r->mode != VOIDmode && GET_MODE (reloadreg) != r->mode)
- reloadreg = gen_rtx (REG, r->mode, REGNO (reloadreg));
+ reloadreg = gen_rtx_REG (r->mode, REGNO (reloadreg));
return reloadreg;
}
??? Is it actually still ever a SUBREG? If so, why? */
if (GET_CODE (reloadreg) == REG)
- return gen_rtx (REG, GET_MODE (*loc),
- REGNO (reloadreg) + SUBREG_WORD (*loc));
+ return gen_rtx_REG (GET_MODE (*loc),
+ REGNO (reloadreg) + SUBREG_WORD (*loc));
else if (GET_MODE (reloadreg) == GET_MODE (*loc))
return reloadreg;
else
- return gen_rtx (SUBREG, GET_MODE (*loc), SUBREG_REG (reloadreg),
- SUBREG_WORD (reloadreg) + SUBREG_WORD (*loc));
+ return gen_rtx_SUBREG (GET_MODE (*loc), SUBREG_REG (reloadreg),
+ SUBREG_WORD (reloadreg) + SUBREG_WORD (*loc));
}
}
+ /* If *LOC is a PLUS, MINUS, or MULT, see if a replacement is scheduled for
+ what's inside and make a new rtl if so. */
+ if (GET_CODE (*loc) == PLUS || GET_CODE (*loc) == MINUS
+ || GET_CODE (*loc) == MULT)
+ {
+ rtx x = find_replacement (&XEXP (*loc, 0));
+ rtx y = find_replacement (&XEXP (*loc, 1));
+
+ if (x != XEXP (*loc, 0) || y != XEXP (*loc, 1))
+ return gen_rtx_fmt_ee (GET_CODE (*loc), GET_MODE (*loc), x, y);
+ }
+
return *loc;
}
\f
return 0;
x = SET_SRC (x);
goto repeat;
+
+ default:
+ break;
}
/* X does not match, so try its subexpressions. */
{
int regno, endregno;
- if (GET_CODE (x) == SUBREG)
+ /* Overly conservative. */
+ if (GET_CODE (x) == STRICT_LOW_PART)
+ x = XEXP (x, 0);
+
+ /* If either argument is a constant, then modifying X can not affect IN. */
+ if (CONSTANT_P (x) || CONSTANT_P (in))
+ return 0;
+ else if (GET_CODE (x) == SUBREG)
{
regno = REGNO (SUBREG_REG (x));
if (regno < FIRST_PSEUDO_REGISTER)
abort ();
}
}
- else if (CONSTANT_P (x))
- return 0;
else if (GET_CODE (x) == MEM)
return refers_to_mem_for_reload_p (in);
else if (GET_CODE (x) == SCRATCH || GET_CODE (x) == PC
case POST_DEC:
case PRE_DEC:
return 0;
+ default:
+ break;
}
goal_mem = 1;
}
&& XEXP (goal, 0) == stack_pointer_rtx
&& CONSTANT_P (XEXP (goal, 1)))
goal_const = need_stable_sp = 1;
+ else if (GET_CODE (goal) == PLUS
+ && XEXP (goal, 0) == frame_pointer_rtx
+ && CONSTANT_P (XEXP (goal, 1)))
+ goal_const = 1;
else
return 0;
&& (valueno = true_regnum (valtry = SET_SRC (pat))) >= 0)
||
(goal_const && rtx_equal_p (SET_SRC (pat), goal)
+ /* When looking for stack pointer + const,
+ make sure we don't use a stack adjust. */
+ && !reg_overlap_mentioned_for_reload_p (SET_DEST (pat), goal)
&& (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0)
|| (goal_mem
&& (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0
if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
{
+ pat = PATTERN (p);
+
+ /* Watch out for unspec_volatile, and volatile asms. */
+ if (volatile_insn_p (pat))
+ return 0;
+
/* If this insn P stores in either GOAL or VALUE, return 0.
If GOAL is a memory ref and this insn writes memory, return 0.
If GOAL is a memory ref and its address is not constant,
and this insn P changes a register used in GOAL, return 0. */
- pat = PATTERN (p);
if (GET_CODE (pat) == SET || GET_CODE (pat) == CLOBBER)
{
register rtx dest = SET_DEST (pat);
if (goal_mem_addr_varies
&& reg_overlap_mentioned_for_reload_p (dest, goal))
return 0;
+ if (xregno == STACK_POINTER_REGNUM && need_stable_sp)
+ return 0;
}
else if (goal_mem && GET_CODE (dest) == MEM
&& ! push_operand (dest, GET_MODE (dest)))
&& reg_overlap_mentioned_for_reload_p (dest,
goal))
return 0;
+ if (xregno == STACK_POINTER_REGNUM && need_stable_sp)
+ return 0;
}
else if (goal_mem && GET_CODE (dest) == MEM
&& ! push_operand (dest, GET_MODE (dest)))
return 0;
+ else if (GET_CODE (dest) == MEM && regno >= FIRST_PSEUDO_REGISTER
+ && reg_equiv_memory_loc[regno] != 0)
+ return 0;
else if (need_stable_sp
&& push_operand (dest, GET_MODE (dest)))
return 0;
static char *reg_class_names[] = REG_CLASS_NAMES;
-/* This function is used to print the variables set by 'find_reloads' */
+/* These functions are used to print the variables set by 'find_reloads' */
void
-debug_reload()
+debug_reload_to_stream (f)
+ FILE *f;
{
int r;
+ char *prefix;
- fprintf (stderr, "\nn_reloads = %d\n", n_reloads);
-
+ if (! f)
+ f = stderr;
for (r = 0; r < n_reloads; r++)
{
- fprintf (stderr, "\nRELOAD %d\n", r);
+ fprintf (f, "Reload %d: ", r);
- if (reload_in[r])
+ if (reload_in[r] != 0)
{
- fprintf (stderr, "\nreload_in (%s) = ",
+ fprintf (f, "reload_in (%s) = ",
GET_MODE_NAME (reload_inmode[r]));
- debug_rtx (reload_in[r]);
+ print_inline_rtx (f, reload_in[r], 24);
+ fprintf (f, "\n\t");
}
- if (reload_out[r])
+ if (reload_out[r] != 0)
{
- fprintf (stderr, "\nreload_out (%s) = ",
+ fprintf (f, "reload_out (%s) = ",
GET_MODE_NAME (reload_outmode[r]));
- debug_rtx (reload_out[r]);
+ print_inline_rtx (f, reload_out[r], 24);
+ fprintf (f, "\n\t");
}
- fprintf (stderr, "%s, ", reg_class_names[(int) reload_reg_class[r]]);
+ fprintf (f, "%s, ", reg_class_names[(int) reload_reg_class[r]]);
- fprintf (stderr, "%s (opnum = %d)",
- reload_when_needed_name[(int)reload_when_needed[r]],
+ fprintf (f, "%s (opnum = %d)",
+ reload_when_needed_name[(int) reload_when_needed[r]],
reload_opnum[r]);
if (reload_optional[r])
- fprintf (stderr, ", optional");
+ fprintf (f, ", optional");
+
+ if (reload_nongroup[r])
+ fprintf (stderr, ", nongroup");
- if (reload_in[r])
- fprintf (stderr, ", inc by %d\n", reload_inc[r]);
+ if (reload_inc[r] != 0)
+ fprintf (f, ", inc by %d", reload_inc[r]);
if (reload_nocombine[r])
- fprintf (stderr, ", can't combine");
+ fprintf (f, ", can't combine");
if (reload_secondary_p[r])
- fprintf (stderr, ", secondary_reload_p");
+ fprintf (f, ", secondary_reload_p");
- if (reload_in_reg[r])
+ if (reload_in_reg[r] != 0)
{
- fprintf (stderr, "\nreload_in_reg:\t\t\t");
- debug_rtx (reload_in_reg[r]);
+ fprintf (f, "\n\treload_in_reg: ");
+ print_inline_rtx (f, reload_in_reg[r], 24);
}
- if (reload_reg_rtx[r])
+ if (reload_reg_rtx[r] != 0)
{
- fprintf (stderr, "\nreload_reg_rtx:\t\t\t");
- debug_rtx (reload_reg_rtx[r]);
+ fprintf (f, "\n\treload_reg_rtx: ");
+ print_inline_rtx (f, reload_reg_rtx[r], 24);
}
+ prefix = "\n\t";
if (reload_secondary_in_reload[r] != -1)
{
- fprintf (stderr, "\nsecondary_in_reload = ");
- fprintf (stderr, "%d ", reload_secondary_in_reload[r]);
+ fprintf (f, "%ssecondary_in_reload = %d",
+ prefix, reload_secondary_in_reload[r]);
+ prefix = ", ";
}
if (reload_secondary_out_reload[r] != -1)
- {
- if (reload_secondary_in_reload[r] != -1)
- fprintf (stderr, ", secondary_out_reload = ");
- else
- fprintf (stderr, "\nsecondary_out_reload = ");
-
- fprintf (stderr, "%d", reload_secondary_out_reload[r]);
- }
-
+ fprintf (f, "%ssecondary_out_reload = %d\n",
+ prefix, reload_secondary_out_reload[r]);
+ prefix = "\n\t";
if (reload_secondary_in_icode[r] != CODE_FOR_nothing)
{
- fprintf (stderr, "\nsecondary_in_icode = ");
- fprintf (stderr, "%s", insn_name[r]);
+ fprintf (stderr, "%ssecondary_in_icode = %s", prefix,
+ insn_name[reload_secondary_in_icode[r]]);
+ prefix = ", ";
}
if (reload_secondary_out_icode[r] != CODE_FOR_nothing)
- {
- if (reload_secondary_in_icode[r] != CODE_FOR_nothing)
- fprintf (stderr, ", secondary_out_icode = ");
- else
- fprintf (stderr, "\nsecondary_out_icode = ");
+ fprintf (stderr, "%ssecondary_out_icode = %s", prefix,
+ insn_name[reload_secondary_out_icode[r]]);
- fprintf (stderr, "%s ", insn_name[r]);
- }
- fprintf (stderr, "\n");
+ fprintf (f, "\n");
}
+}
- fprintf (stderr, "\n");
+void
+debug_reload ()
+{
+ debug_reload_to_stream (stderr);
}