#define REG_OK_STRICT
#include "config.h"
#include "system.h"
#include "rtl.h"
#include "insn-config.h"
#include "insn-codes.h"
#include "recog.h"
#include "reload.h"
#include "regs.h"
#include "hard-reg-set.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
#endif
#ifndef REGNO_MODE_OK_FOR_BASE_P
#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) REGNO_OK_FOR_BASE_P (REGNO)
#endif
#ifndef REG_MODE_OK_FOR_BASE_P
#define REG_MODE_OK_FOR_BASE_P(REGNO, MODE) REG_OK_FOR_BASE_P (REGNO)
#endif
int n_reloads;
rtx reload_in[MAX_RELOADS];
rtx reload_out[MAX_RELOADS];
enum reg_class reload_reg_class[MAX_RELOADS];
enum machine_mode reload_inmode[MAX_RELOADS];
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];
rtx reload_out_reg[MAX_RELOADS];
char reload_nocombine[MAX_RELOADS];
int reload_opnum[MAX_RELOADS];
enum reload_type reload_when_needed[MAX_RELOADS];
int reload_secondary_p[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];
int n_earlyclobbers;
rtx reload_earlyclobbers[MAX_RECOG_OPERANDS];
int reload_n_operands;
static int replace_reloads;
struct replacement
{
rtx *where;
rtx *subreg_loc;
int what;
enum machine_mode mode;
};
static struct replacement replacements[MAX_RECOG_OPERANDS * ((MAX_REGS_PER_ADDRESS * 2) + 1)];
static int n_replacements;
struct decomposition
{
int reg_flag;
int safe;
rtx base;
HOST_WIDE_INT start;
HOST_WIDE_INT end;
};
#ifdef SECONDARY_MEMORY_NEEDED
static rtx secondary_memlocs[NUM_MACHINE_MODES];
static rtx secondary_memlocs_elim[NUM_MACHINE_MODES][MAX_RECOG_OPERANDS];
#endif
static rtx this_insn;
static int this_insn_is_asm;
static int hard_regs_live_known;
static short *static_reload_reg_p;
static int subst_reg_equivs_changed;
static int output_reloadnum;
#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))))
#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))
#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))
#define ADDR_TYPE(type) \
((type) == RELOAD_FOR_INPUT_ADDRESS \
? RELOAD_FOR_INPADDR_ADDRESS \
: ((type) == RELOAD_FOR_OUTPUT_ADDRESS \
? 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,
int, int, int, enum reload_type));
static void push_replacement PROTO((rtx *, int, enum machine_mode));
static void combine_reloads PROTO((void));
static int find_reusable_reload PROTO((rtx *, rtx, enum reg_class,
enum reload_type, int, int));
static rtx find_dummy_reload PROTO((rtx, rtx, rtx *, rtx *,
enum machine_mode, enum machine_mode,
enum reg_class, int, int));
static int earlyclobber_operand_p PROTO((rtx));
static int hard_reg_set_here_p PROTO((int, int, rtx));
static struct decomposition decompose PROTO((rtx));
static int immune_p PROTO((rtx, rtx, struct decomposition));
static int alternative_allows_memconst PROTO((const char *, int));
static rtx find_reloads_toplev PROTO((rtx, int, enum reload_type, int, int, rtx));
static rtx make_memloc PROTO((rtx, int));
static int find_reloads_address PROTO((enum machine_mode, rtx *, rtx, rtx *,
int, enum reload_type, int, rtx));
static rtx subst_reg_equivs PROTO((rtx, rtx));
static rtx subst_indexed_address PROTO((rtx));
static int find_reloads_address_1 PROTO((enum machine_mode, rtx, int, rtx *,
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));
static rtx find_reloads_subreg_address PROTO((rtx, int, int, enum reload_type,
int, rtx));
static int find_inc_amount PROTO((rtx, rtx));
static int loc_mentioned_in_p PROTO((rtx *, rtx));
#ifdef HAVE_SECONDARY_RELOADS
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;
enum reload_type type;
enum insn_code *picode;
{
enum reg_class class = NO_REGS;
enum machine_mode mode = reload_mode;
enum insn_code icode = CODE_FOR_nothing;
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 s_reload, t_reload = -1;
if (type == RELOAD_FOR_INPUT_ADDRESS
|| type == RELOAD_FOR_OUTPUT_ADDRESS
|| type == RELOAD_FOR_INPADDR_ADDRESS
|| type == RELOAD_FOR_OUTADDR_ADDRESS)
secondary_type = type;
else
secondary_type = in_p ? RELOAD_FOR_INPUT_ADDRESS : RELOAD_FOR_OUTPUT_ADDRESS;
*picode = CODE_FOR_nothing;
if (GET_CODE (x) == SUBREG
&& (GET_MODE_SIZE (GET_MODE (x))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
{
x = SUBREG_REG (x);
reload_mode = GET_MODE (x);
}
if (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER
&& reg_equiv_mem[REGNO (x)] != 0)
x = reg_equiv_mem[REGNO (x)];
#ifdef SECONDARY_INPUT_RELOAD_CLASS
if (in_p)
class = SECONDARY_INPUT_RELOAD_CLASS (reload_class, reload_mode, x);
#endif
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
if (! in_p)
class = SECONDARY_OUTPUT_RELOAD_CLASS (reload_class, reload_mode, x);
#endif
if (class == NO_REGS)
return -1;
icode = (in_p ? reload_in_optab[(int) reload_mode]
: reload_out_optab[(int) reload_mode]);
if (icode != CODE_FOR_nothing
&& insn_operand_predicate[(int) icode][in_p]
&& (! (insn_operand_predicate[(int) icode][in_p]) (x, reload_mode)))
icode = CODE_FOR_nothing;
if (icode != CODE_FOR_nothing)
{
char insn_letter = insn_operand_constraint[(int) icode][!in_p][in_p];
enum reg_class insn_class
= (insn_letter == 'r' ? GENERAL_REGS
: REG_CLASS_FROM_LETTER ((unsigned char) insn_letter));
if (insn_class == NO_REGS
|| (in_p && insn_operand_constraint[(int) icode][!in_p][0] != '=')
|| insn_operand_constraint[(int) icode][2][0] != '='
|| insn_operand_constraint[(int) icode][2][1] != '&')
abort ();
if (reg_class_subset_p (reload_class, insn_class))
mode = insn_operand_mode[(int) icode][2];
else
{
char t_letter = insn_operand_constraint[(int) icode][2][2];
class = insn_class;
t_mode = insn_operand_mode[(int) icode][2];
t_class = (t_letter == 'r' ? GENERAL_REGS
: REG_CLASS_FROM_LETTER ((unsigned char) t_letter));
t_icode = icode;
icode = CODE_FOR_nothing;
}
}
if (in_p && class == reload_class && mode == reload_mode)
abort ();
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 || SMALL_REGISTER_CLASSES)
&& 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)
{
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_nongroup[t_reload] = 0;
reload_inc[t_reload] = 0;
reload_nocombine[t_reload] = 1;
reload_in_reg[t_reload] = 0;
reload_out_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++;
}
}
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 || SMALL_REGISTER_CLASSES)
&& 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)
{
#ifdef SECONDARY_MEMORY_NEEDED
if (in_p && icode == CODE_FOR_nothing
&& SECONDARY_MEMORY_NEEDED (class, reload_class, mode))
get_secondary_mem (x, reload_mode, opnum, type);
#endif
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_nongroup[s_reload] = 0;
reload_inc[s_reload] = 0;
reload_nocombine[s_reload] = 1;
reload_in_reg[s_reload] = 0;
reload_out_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 (! in_p && icode == CODE_FOR_nothing
&& SECONDARY_MEMORY_NEEDED (reload_class, class, mode))
get_secondary_mem (x, mode, opnum, type);
#endif
}
*picode = icode;
return s_reload;
}
#endif
#ifdef SECONDARY_MEMORY_NEEDED
rtx
get_secondary_mem (x, mode, opnum, type)
rtx x;
enum machine_mode mode;
int opnum;
enum reload_type type;
{
rtx loc;
int mem_valid;
#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 (secondary_memlocs_elim[(int) mode][opnum] != 0)
return secondary_memlocs_elim[(int) mode][opnum];
if (secondary_memlocs[(int) mode] == 0)
{
#ifdef SECONDARY_MEMORY_NEEDED_RTX
secondary_memlocs[(int) mode] = SECONDARY_MEMORY_NEEDED_RTX (mode);
#else
secondary_memlocs[(int) mode]
= assign_stack_local (mode, GET_MODE_SIZE (mode), 0);
#endif
}
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])
loc = copy_rtx (loc);
if (! mem_valid)
{
type = (type == RELOAD_FOR_INPUT ? RELOAD_FOR_INPUT_ADDRESS
: type == RELOAD_FOR_OUTPUT ? RELOAD_FOR_OUTPUT_ADDRESS
: RELOAD_OTHER);
find_reloads_address (mode, NULL_PTR, XEXP (loc, 0), &XEXP (loc, 0),
opnum, type, 0, 0);
}
secondary_memlocs_elim[(int) mode][opnum] = loc;
return loc;
}
void
clear_secondary_mem ()
{
bzero ((char *) secondary_memlocs, sizeof secondary_memlocs);
}
#endif
static enum reg_class
find_valid_class (m1, n)
enum machine_mode m1;
int n;
{
int class;
int regno;
enum reg_class best_class;
int best_size = 0;
for (class = 1; class < N_REG_CLASSES; class++)
{
int bad = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER && ! bad; regno++)
if (TEST_HARD_REG_BIT (reg_class_contents[class], regno)
&& TEST_HARD_REG_BIT (reg_class_contents[class], regno + n)
&& ! HARD_REGNO_MODE_OK (regno + n, m1))
bad = 1;
if (! bad && reg_class_size[class] > best_size)
best_class = class, best_size = reg_class_size[class];
}
if (best_size == 0)
abort ();
return best_class;
}
static int
find_reusable_reload (p_in, out, class, type, opnum, dont_share)
rtx *p_in, out;
enum reg_class class;
enum reload_type type;
int opnum, dont_share;
{
rtx in = *p_in;
int i;
if (earlyclobber_operand_p (out))
return n_reloads;
for (i = 0; i < n_reloads; i++)
if ((reg_class_subset_p (class, reload_reg_class[i])
|| reg_class_subset_p (reload_reg_class[i], class))
&& (reload_reg_rtx[i] == 0
|| TEST_HARD_REG_BIT (reg_class_contents[(int) class],
true_regnum (reload_reg_rtx[i])))
&& ((in != 0 && MATCHES (reload_in[i], in) && ! dont_share
&& (out == 0 || reload_out[i] == 0 || MATCHES (reload_out[i], out)))
||
(out != 0 && MATCHES (reload_out[i], out)
&& (in == 0 || reload_in[i] == 0 || MATCHES (reload_in[i], in))))
&& (reload_out[i] == 0 || ! earlyclobber_operand_p (reload_out[i]))
&& (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES)
&& MERGABLE_RELOADS (type, reload_when_needed[i],
opnum, reload_opnum[i]))
return i;
for (i = 0; i < n_reloads; i++)
if ((reg_class_subset_p (class, reload_reg_class[i])
|| reg_class_subset_p (reload_reg_class[i], class))
&& (reload_reg_rtx[i] == 0
|| TEST_HARD_REG_BIT (reg_class_contents[(int) class],
true_regnum (reload_reg_rtx[i])))
&& out == 0 && reload_out[i] == 0 && reload_in[i] != 0
&& ((GET_CODE (in) == REG
&& (GET_CODE (reload_in[i]) == POST_INC
|| GET_CODE (reload_in[i]) == POST_DEC
|| GET_CODE (reload_in[i]) == PRE_INC
|| GET_CODE (reload_in[i]) == PRE_DEC)
&& MATCHES (XEXP (reload_in[i], 0), in))
||
(GET_CODE (reload_in[i]) == REG
&& (GET_CODE (in) == POST_INC
|| GET_CODE (in) == POST_DEC
|| GET_CODE (in) == PRE_INC
|| GET_CODE (in) == PRE_DEC)
&& MATCHES (XEXP (in, 0), reload_in[i])))
&& (reload_out[i] == 0 || ! earlyclobber_operand_p (reload_out[i]))
&& (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES)
&& MERGABLE_RELOADS (type, reload_when_needed[i],
opnum, reload_opnum[i]))
{
if (GET_CODE (in) == REG)
*p_in = reload_in[i];
return i;
}
return n_reloads;
}
static int
push_reload (in, out, inloc, outloc, class,
inmode, outmode, strict_low, optional, opnum, type)
rtx in, out;
rtx *inloc, *outloc;
enum reg_class class;
enum machine_mode inmode, outmode;
int strict_low;
int optional;
int opnum;
enum reload_type type;
{
register int i;
int dont_share = 0;
int dont_remove_subreg = 0;
rtx *in_subreg_loc = 0, *out_subreg_loc = 0;
int secondary_in_reload = -1, secondary_out_reload = -1;
enum insn_code secondary_in_icode = CODE_FOR_nothing;
enum insn_code secondary_out_icode = CODE_FOR_nothing;
if (inmode == VOIDmode && in != 0)
inmode = GET_MODE (in);
if (outmode == VOIDmode && out != 0)
outmode = GET_MODE (out);
if (in != 0 && GET_CODE (in) == REG)
{
register int regno = REGNO (in);
if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0)
in = reg_equiv_constant[regno];
}
if (out != 0 && GET_CODE (out) == REG)
{
register int regno = REGNO (out);
if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0)
out = reg_equiv_constant[regno];
}
if (in != 0 && out != 0 && GET_CODE (in) == MEM && rtx_equal_p (in, out))
{
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));
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));
}
if (in != 0 && GET_CODE (in) == SUBREG
&& (SUBREG_WORD (in) == 0 || strict_low)
#ifdef CLASS_CANNOT_CHANGE_SIZE
&& class != CLASS_CANNOT_CHANGE_SIZE
#endif
&& (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)
&& ((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
#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
&& (out == 0 || SUBREG_WORD (in) == 0)
&& ((GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
> UNITS_PER_WORD)
&& ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
/ UNITS_PER_WORD)
!= HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)),
GET_MODE (SUBREG_REG (in)))))
|| ! HARD_REGNO_MODE_OK ((REGNO (SUBREG_REG (in))
+ SUBREG_WORD (in)),
inmode)))
#ifdef SECONDARY_INPUT_RELOAD_CLASS
|| (SECONDARY_INPUT_RELOAD_CLASS (class, inmode, in) != NO_REGS
&& (SECONDARY_INPUT_RELOAD_CLASS (class,
GET_MODE (SUBREG_REG (in)),
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 (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS)
if (GET_CODE (in) == MEM)
if (GET_MODE_SIZE (GET_MODE (in)) > GET_MODE_SIZE (inmode))
abort ();
#endif
inmode = GET_MODE (in);
}
if (in != 0 && GET_CODE (in) == SUBREG
&& (CONSTANT_P (SUBREG_REG (in))
|| (GET_CODE (SUBREG_REG (in)) == REG
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
&& (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (in))
+ SUBREG_WORD (in),
inmode)
|| (GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
> UNITS_PER_WORD)
&& ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
/ UNITS_PER_WORD)
!= HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)),
GET_MODE (SUBREG_REG (in)))))))))
{
push_reload (SUBREG_REG (in), NULL_RTX, &SUBREG_REG (in), NULL_PTR,
find_valid_class (inmode, SUBREG_WORD (in)),
VOIDmode, VOIDmode, 0, 0, opnum, type);
dont_remove_subreg = 1;
}
if (out != 0 && GET_CODE (out) == SUBREG
&& (SUBREG_WORD (out) == 0 || strict_low)
#ifdef CLASS_CANNOT_CHANGE_SIZE
&& class != CLASS_CANNOT_CHANGE_SIZE
#endif
&& (CONSTANT_P (SUBREG_REG (out))
|| strict_low
|| (((GET_CODE (SUBREG_REG (out)) == REG
&& 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))))
#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
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))
> UNITS_PER_WORD)
&& ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))
/ UNITS_PER_WORD)
!= HARD_REGNO_NREGS (REGNO (SUBREG_REG (out)),
GET_MODE (SUBREG_REG (out)))))
|| ! HARD_REGNO_MODE_OK ((REGNO (SUBREG_REG (out))
+ SUBREG_WORD (out)),
outmode)))
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
|| (SECONDARY_OUTPUT_RELOAD_CLASS (class, outmode, out) != NO_REGS
&& (SECONDARY_OUTPUT_RELOAD_CLASS (class,
GET_MODE (SUBREG_REG (out)),
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 (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS)
if (GET_CODE (out) == MEM
&& GET_MODE_SIZE (GET_MODE (out)) > GET_MODE_SIZE (outmode))
abort ();
#endif
outmode = GET_MODE (out);
}
if (out != 0 && GET_CODE (out) == SUBREG
&& GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
&& (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (out)) + SUBREG_WORD (out),
outmode)
|| (GET_MODE_SIZE (outmode) <= UNITS_PER_WORD
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))
> UNITS_PER_WORD)
&& ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))
/ UNITS_PER_WORD)
!= HARD_REGNO_NREGS (REGNO (SUBREG_REG (out)),
GET_MODE (SUBREG_REG (out)))))))
{
dont_remove_subreg = 1;
push_reload (SUBREG_REG (out), SUBREG_REG (out), &SUBREG_REG (out),
&SUBREG_REG (out),
find_valid_class (outmode, SUBREG_WORD (out)),
VOIDmode, VOIDmode, 0, 0,
opnum, RELOAD_OTHER);
}
if (in != 0 && out != 0 && GET_CODE (out) == MEM
&& (GET_CODE (in) == REG || GET_CODE (in) == MEM)
&& reg_overlap_mentioned_for_reload_p (in, XEXP (out, 0)))
dont_share = 1;
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));
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));
if (in != 0)
class = PREFERRED_RELOAD_CLASS (in, class);
#ifdef PREFERRED_OUTPUT_RELOAD_CLASS
if (out != 0)
class = PREFERRED_OUTPUT_RELOAD_CLASS (out, class);
#endif
#ifdef LIMIT_RELOAD_CLASS
if (in_subreg_loc)
class = LIMIT_RELOAD_CLASS (inmode, class);
else if (in != 0 && GET_CODE (in) == SUBREG)
class = LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG (in)), class);
if (out_subreg_loc)
class = LIMIT_RELOAD_CLASS (outmode, class);
if (out != 0 && GET_CODE (out) == SUBREG)
class = LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG (out)), class);
#endif
if (this_insn_is_asm)
{
enum machine_mode mode;
if (GET_MODE_SIZE (inmode) > GET_MODE_SIZE (outmode))
mode = inmode;
else
mode = outmode;
if (mode == VOIDmode)
{
error_for_asm (this_insn, "cannot reload integer constant operand in `asm'");
mode = word_mode;
if (in != 0)
inmode = word_mode;
if (out != 0)
outmode = word_mode;
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (HARD_REGNO_MODE_OK (i, mode)
&& TEST_HARD_REG_BIT (reg_class_contents[(int) class], i))
{
int nregs = HARD_REGNO_NREGS (i, mode);
int j;
for (j = 1; j < nregs; j++)
if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class], i + j))
break;
if (j == nregs)
break;
}
if (i == FIRST_PSEUDO_REGISTER)
{
error_for_asm (this_insn, "impossible register constraint in `asm'");
class = ALL_REGS;
}
}
if (class == NO_REGS
&& (optional == 0 || type != RELOAD_FOR_OUTPUT))
abort ();
i = find_reusable_reload (&in, out, class, type, opnum, dont_share);
if (i == n_reloads)
{
#ifdef SECONDARY_INPUT_RELOAD_CLASS
if (in != 0)
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_reload
= push_secondary_reload (0, out, opnum, optional, class, outmode,
type, &secondary_out_icode);
#endif
#ifdef SECONDARY_MEMORY_NEEDED
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_reg_class[i] = class;
reload_inmode[i] = inmode;
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;
reload_out_reg[i] = outloc ? *outloc : 0;
reload_opnum[i] = opnum;
reload_when_needed[i] = type;
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++;
#ifdef SECONDARY_MEMORY_NEEDED
if (out != 0 && GET_CODE (out) == REG
&& REGNO (out) < FIRST_PSEUDO_REGISTER
&& SECONDARY_MEMORY_NEEDED (class, REGNO_REG_CLASS (REGNO (out)),
outmode))
get_secondary_mem (out, outmode, opnum, type);
#endif
}
else
{
if (inmode != VOIDmode
&& GET_MODE_SIZE (inmode) > GET_MODE_SIZE (reload_inmode[i]))
reload_inmode[i] = inmode;
if (outmode != VOIDmode
&& GET_MODE_SIZE (outmode) > GET_MODE_SIZE (reload_outmode[i]))
reload_outmode[i] = outmode;
if (in != 0)
{
rtx in_reg = inloc ? *inloc : 0;
if (reload_in[i] != in && rtx_equal_p (in, reload_in[i])
&& ! (reload_optional[i] && optional))
{
if (opnum > reload_opnum[i])
{
remove_address_replacements (in);
in = reload_in[i];
in_reg = reload_in_reg[i];
}
else
remove_address_replacements (reload_in[i]);
}
reload_in[i] = in;
reload_in_reg[i] = in_reg;
}
if (out != 0)
{
reload_out[i] = out;
reload_out_reg[i] = outloc ? *outloc : 0;
}
if (reg_class_subset_p (class, reload_reg_class[i]))
reload_reg_class[i] = class;
reload_optional[i] &= optional;
if (MERGE_TO_OTHER (type, reload_when_needed[i],
opnum, reload_opnum[i]))
reload_when_needed[i] = RELOAD_OTHER;
reload_opnum[i] = MIN (reload_opnum[i], opnum);
}
if (in != 0 && in != *inloc)
reload_nocombine[i] = 1;
#if 0
if (out != 0 && sets_cc0_p (PATTERN (this_insn)))
{
out = 0;
reload_out[i] = 0;
reload_inc[i] = find_inc_amount (PATTERN (this_insn), in);
if (reload_inc[i] == 0)
abort ();
}
#endif
if (replace_reloads)
{
if (inloc != 0)
{
register struct replacement *r = &replacements[n_replacements++];
r->what = i;
r->subreg_loc = in_subreg_loc;
r->where = inloc;
r->mode = inmode;
}
if (outloc != 0 && outloc != inloc)
{
register struct replacement *r = &replacements[n_replacements++];
r->what = i;
r->where = outloc;
r->subreg_loc = out_subreg_loc;
r->mode = outmode;
}
}
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,
earlyclobber_operand_p (out));
if (reload_reg_rtx[i] == out
&& (GET_CODE (in) == REG || CONSTANT_P (in))
&& 0 != find_equiv_reg (in, this_insn, 0, REGNO (out),
static_reload_reg_p, i, inmode))
reload_in[i] = out;
}
if (reload_reg_rtx[i] == 0 && in != 0)
{
rtx note;
int regno;
for (note = REG_NOTES (this_insn); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_DEAD
&& GET_CODE (XEXP (note, 0)) == REG
&& (regno = REGNO (XEXP (note, 0))) < FIRST_PSEUDO_REGISTER
&& reg_mentioned_p (XEXP (note, 0), in)
&& ! refers_to_regno_for_reload_p (regno,
(regno
+ HARD_REGNO_NREGS (regno,
inmode)),
PATTERN (this_insn), inloc)
&& (out == 0 || in == out
|| ! hard_reg_set_here_p (regno,
(regno
+ HARD_REGNO_NREGS (regno,
inmode)),
PATTERN (this_insn)))
&& (in != out
|| (GET_CODE (in) == SUBREG
&& (((GET_MODE_SIZE (GET_MODE (in)) + (UNITS_PER_WORD - 1))
/ UNITS_PER_WORD)
== ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))))
&& GET_MODE_SIZE (inmode) <= GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
&& HARD_REGNO_MODE_OK (regno, inmode)
&& GET_MODE_SIZE (outmode) <= GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
&& HARD_REGNO_MODE_OK (regno, outmode)
&& TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno)
&& !fixed_regs[regno])
{
reload_reg_rtx[i] = gen_rtx_REG (inmode, regno);
break;
}
}
if (out)
output_reloadnum = i;
return i;
}
static void
push_replacement (loc, reloadnum, mode)
rtx *loc;
int reloadnum;
enum machine_mode mode;
{
if (replace_reloads)
{
register struct replacement *r = &replacements[n_replacements++];
r->what = reloadnum;
r->where = loc;
r->subreg_loc = 0;
r->mode = mode;
}
}
void
transfer_replacements (to, from)
int to, from;
{
int i;
for (i = 0; i < n_replacements; i++)
if (replacements[i].what == from)
replacements[i].what = to;
}
int
remove_address_replacements (in_rtx)
rtx in_rtx;
{
int i, j;
char reload_flags[MAX_RELOADS];
int something_changed = 0;
bzero (reload_flags, sizeof reload_flags);
for (i = 0, j = 0; i < n_replacements; i++)
{
if (loc_mentioned_in_p (replacements[i].where, in_rtx))
reload_flags[replacements[i].what] |= 1;
else
{
replacements[j++] = replacements[i];
reload_flags[replacements[i].what] |= 2;
}
}
n_replacements = j;
for (i = n_reloads - 1; i >= 0; i--)
{
if (reload_flags[i] == 1)
{
deallocate_reload_reg (i);
remove_address_replacements (reload_in[i]);
reload_in[i] = 0;
something_changed = 1;
}
}
return something_changed;
}
static int
loc_mentioned_in_p (loc, in)
rtx *loc, in;
{
enum rtx_code code = GET_CODE (in);
char *fmt = GET_RTX_FORMAT (code);
int i, j;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (loc == &XEXP (in, i))
return 1;
if (fmt[i] == 'e')
{
if (loc_mentioned_in_p (loc, XEXP (in, i)))
return 1;
}
else if (fmt[i] == 'E')
for (j = XVECLEN (in, i) - 1; i >= 0; i--)
if (loc_mentioned_in_p (loc, XVECEXP (in, i, j)))
return 1;
}
return 0;
}
static void
combine_reloads ()
{
int i;
int output_reload = -1;
int secondary_out = -1;
rtx note;
for (i = 0; i < n_reloads; i++)
if (reload_out[i] != 0)
{
if (output_reload >= 0)
return;
output_reload = i;
}
if (output_reload < 0 || reload_optional[output_reload])
return;
if (reload_in[output_reload] != 0)
return;
if (earlyclobber_operand_p (reload_out[output_reload]))
return;
for (i = 0; i < n_reloads; i++)
if (reload_in[i] && ! reload_optional[i] && ! reload_nocombine[i]
&& reload_when_needed[i] != RELOAD_FOR_OUTPUT_ADDRESS
&& reload_when_needed[i] != RELOAD_FOR_OUTADDR_ADDRESS
&& reload_when_needed[i] != RELOAD_OTHER
&& (CLASS_MAX_NREGS (reload_reg_class[i], reload_inmode[i])
== CLASS_MAX_NREGS (reload_reg_class[output_reload],
reload_outmode[output_reload]))
&& reload_inc[i] == 0
&& reload_reg_rtx[i] == 0
#ifdef SECONDARY_MEMORY_NEEDED
&& (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]],
secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]]))
#endif
&& (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])
|| (! reg_overlap_mentioned_for_reload_p (reload_out[output_reload],
reload_in[i])
&& ! (GET_CODE (reload_in[i]) == REG
&& reg_overlap_mentioned_for_reload_p (reload_in[i],
reload_out[output_reload]))))
&& (reg_class_size[(int) reload_reg_class[i]]
|| SMALL_REGISTER_CLASSES)
&& (reload_when_needed[i] == RELOAD_FOR_INPUT
|| reload_when_needed[i] == RELOAD_FOR_OUTPUT))
{
int j;
reload_out[i] = reload_out[output_reload];
reload_out_reg[i] = reload_out_reg[output_reload];
reload_outmode[i] = reload_outmode[output_reload];
reload_out[output_reload] = 0;
reload_when_needed[i] = RELOAD_OTHER;
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
if (secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]] != 0)
secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[i]]
= secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]];
#endif
if (reg_class_subset_p (reload_reg_class[output_reload],
reload_reg_class[i]))
reload_reg_class[i] = reload_reg_class[output_reload];
for (j = 0; j < n_replacements; j++)
if (replacements[j].what == output_reload)
replacements[j].what = i;
return;
}
if (INSN_CODE (this_insn) == -1)
return;
for (i = 1; i < insn_n_operands[INSN_CODE (this_insn)]; i++)
if (insn_operand_constraint[INSN_CODE (this_insn)][i][0] == '='
|| insn_operand_constraint[INSN_CODE (this_insn)][i][0] == '+')
return;
for (note = REG_NOTES (this_insn); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_DEAD
&& GET_CODE (XEXP (note, 0)) == REG
&& ! reg_overlap_mentioned_for_reload_p (XEXP (note, 0),
reload_out[output_reload])
&& REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
&& HARD_REGNO_MODE_OK (REGNO (XEXP (note, 0)), reload_outmode[output_reload])
&& TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[output_reload]],
REGNO (XEXP (note, 0)))
&& (HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), reload_outmode[output_reload])
<= HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), GET_MODE (XEXP (note, 0))))
&& ((secondary_out = reload_secondary_out_reload[output_reload]) == -1
|| (! (TEST_HARD_REG_BIT
(reg_class_contents[(int) reload_reg_class[secondary_out]],
REGNO (XEXP (note, 0))))
&& ((secondary_out = reload_secondary_out_reload[secondary_out]) == -1
|| ! (TEST_HARD_REG_BIT
(reg_class_contents[(int) reload_reg_class[secondary_out]],
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)));
return;
}
}
static rtx
find_dummy_reload (real_in, real_out, inloc, outloc,
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;
int in_offset = 0;
int out_offset = 0;
rtx value = 0;
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;
while (GET_CODE (out) == SUBREG)
{
out_offset = SUBREG_WORD (out);
out = SUBREG_REG (out);
}
while (GET_CODE (in) == SUBREG)
{
in_offset = SUBREG_WORD (in);
in = SUBREG_REG (in);
}
class = PREFERRED_RELOAD_CLASS (in, class);
if (GET_CODE (out) == REG
&& REGNO (out) < FIRST_PSEUDO_REGISTER)
{
register int regno = REGNO (out) + out_offset;
int nwords = HARD_REGNO_NREGS (regno, outmode);
rtx saved_rtx;
saved_rtx = *inloc;
*inloc = const0_rtx;
if (regno < FIRST_PSEUDO_REGISTER
#ifdef OVERLAPPING_REGNO_P
&& ! (fixed_regs[regno] && OVERLAPPING_REGNO_P (regno))
#endif
&& ! refers_to_regno_for_reload_p (regno, regno + nwords,
PATTERN (this_insn), outloc))
{
int i;
for (i = 0; i < nwords; i++)
if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
regno + i))
break;
if (i == nwords)
{
if (GET_CODE (real_out) == REG)
value = real_out;
else
value = gen_rtx_REG (outmode, regno);
}
}
*inloc = saved_rtx;
}
if (hard_regs_live_known
&& GET_CODE (in) == REG
&& REGNO (in) < FIRST_PSEUDO_REGISTER
&& (value == 0
|| 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) != VOIDmode
? GET_MODE (out) : outmode)))
{
register int regno = REGNO (in) + in_offset;
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,
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 (! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
regno + i))
break;
if (i == nwords)
{
if (for_real >= 0 && value == real_out)
reload_out[for_real] = 0;
if (GET_CODE (real_in) == REG)
value = real_in;
else
value = gen_rtx_REG (inmode, regno);
}
}
}
return value;
}
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;
}
static int
hard_reg_set_here_p (beg_regno, end_regno, x)
register int beg_regno, end_regno;
rtx x;
{
if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
{
register rtx op0 = SET_DEST (x);
while (GET_CODE (op0) == SUBREG)
op0 = SUBREG_REG (op0);
if (GET_CODE (op0) == REG)
{
register int r = REGNO (op0);
if (r < end_regno
&& r + HARD_REGNO_NREGS (r, GET_MODE (op0)) > beg_regno)
return 1;
}
}
else if (GET_CODE (x) == PARALLEL)
{
register int i = XVECLEN (x, 0) - 1;
for (; i >= 0; i--)
if (hard_reg_set_here_p (beg_regno, end_regno, XVECEXP (x, 0, i)))
return 1;
}
return 0;
}
int
strict_memory_address_p (mode, addr)
enum machine_mode mode;
register rtx addr;
{
GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
return 0;
win:
return 1;
}
int
operands_match_p (x, y)
register rtx x, y;
{
register int i;
register RTX_CODE code = GET_CODE (x);
register char *fmt;
int success_2;
if (x == y)
return 1;
if ((code == REG || (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG))
&& (GET_CODE (y) == REG || (GET_CODE (y) == SUBREG
&& GET_CODE (SUBREG_REG (y)) == REG)))
{
register int j;
if (code == SUBREG)
{
i = REGNO (SUBREG_REG (x));
if (i >= FIRST_PSEUDO_REGISTER)
goto slow;
i += SUBREG_WORD (x);
}
else
i = REGNO (x);
if (GET_CODE (y) == SUBREG)
{
j = REGNO (SUBREG_REG (y));
if (j >= FIRST_PSEUDO_REGISTER)
goto slow;
j += SUBREG_WORD (y);
}
else
j = REGNO (y);
if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
&& i < FIRST_PSEUDO_REGISTER)
i += (GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD) - 1;
if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (y)) > UNITS_PER_WORD
&& j < FIRST_PSEUDO_REGISTER)
j += (GET_MODE_SIZE (GET_MODE (y)) / UNITS_PER_WORD) - 1;
return i == j;
}
if (code == POST_DEC || code == POST_INC)
return operands_match_p (XEXP (x, 0), y);
if (GET_CODE (y) == PRE_DEC || GET_CODE (y) == PRE_INC)
return operands_match_p (x, XEXP (y, 0)) ? 2 : 0;
slow:
if (code != GET_CODE (y))
return 0;
if (code == LABEL_REF)
return XEXP (x, 0) == XEXP (y, 0);
if (code == SYMBOL_REF)
return XSTR (x, 0) == XSTR (y, 0);
if (GET_MODE (x) != GET_MODE (y))
return 0;
success_2 = 0;
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
int val, j;
switch (fmt[i])
{
case 'w':
if (XWINT (x, i) != XWINT (y, i))
return 0;
break;
case 'i':
if (XINT (x, i) != XINT (y, i))
return 0;
break;
case 'e':
val = operands_match_p (XEXP (x, i), XEXP (y, i));
if (val == 0)
return 0;
if (val == 2)
success_2 = 1;
break;
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;
default:
abort ();
}
}
return 1 + success_2;
}
static struct decomposition
decompose (x)
rtx x;
{
struct decomposition val;
int all_const = 0;
val.reg_flag = 0;
val.safe = 0;
val.base = 0;
if (GET_CODE (x) == MEM)
{
rtx base, offset = 0;
rtx addr = XEXP (x, 0);
if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC
|| GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC)
{
val.base = XEXP (addr, 0);
val.start = - GET_MODE_SIZE (GET_MODE (x));
val.end = GET_MODE_SIZE (GET_MODE (x));
val.safe = REGNO (val.base) == STACK_POINTER_REGNUM;
return val;
}
if (GET_CODE (addr) == CONST)
{
addr = XEXP (addr, 0);
all_const = 1;
}
if (GET_CODE (addr) == PLUS)
{
if (CONSTANT_P (XEXP (addr, 0)))
{
base = XEXP (addr, 1);
offset = XEXP (addr, 0);
}
else if (CONSTANT_P (XEXP (addr, 1)))
{
base = XEXP (addr, 0);
offset = XEXP (addr, 1);
}
}
if (offset == 0)
{
base = addr;
offset = const0_rtx;
}
if (GET_CODE (offset) == CONST)
offset = XEXP (offset, 0);
if (GET_CODE (offset) == PLUS)
{
if (GET_CODE (XEXP (offset, 0)) == CONST_INT)
{
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));
offset = XEXP (offset, 1);
}
else
{
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);
offset = const0_rtx;
}
if (all_const && GET_CODE (base) == PLUS)
base = gen_rtx_CONST (GET_MODE (base), base);
if (GET_CODE (offset) != CONST_INT)
abort ();
val.start = INTVAL (offset);
val.end = val.start + GET_MODE_SIZE (GET_MODE (x));
val.base = base;
return val;
}
else if (GET_CODE (x) == REG)
{
val.reg_flag = 1;
val.start = true_regnum (x);
if (val.start < 0)
{
val.start = REGNO (x);
val.end = val.start + 1;
}
else
val.end = val.start + HARD_REGNO_NREGS (val.start, GET_MODE (x));
}
else if (GET_CODE (x) == SUBREG)
{
if (GET_CODE (SUBREG_REG (x)) != REG)
return decompose (SUBREG_REG (x));
val.reg_flag = 1;
val.start = true_regnum (x);
if (val.start < 0)
return decompose (SUBREG_REG (x));
else
val.end = val.start + HARD_REGNO_NREGS (val.start, GET_MODE (x));
}
else if (CONSTANT_P (x)
|| GET_CODE (x) == SCRATCH)
val.safe = 1;
else
abort ();
return val;
}
static int
immune_p (x, y, ydata)
rtx x, y;
struct decomposition ydata;
{
struct decomposition xdata;
if (ydata.reg_flag)
return !refers_to_regno_for_reload_p (ydata.start, ydata.end, x, NULL_PTR);
if (ydata.safe)
return 1;
if (GET_CODE (y) != MEM)
abort ();
if (GET_CODE (x) != MEM)
return 1;
xdata = decompose (x);
if (! rtx_equal_p (xdata.base, ydata.base))
{
if (CONSTANT_P (xdata.base) && CONSTANT_P (ydata.base))
return 1;
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;
return 0;
}
return (xdata.start >= ydata.end || ydata.start >= xdata.end);
}
int
safe_from_earlyclobber (op, clobber)
rtx op, clobber;
{
struct decomposition early_data;
early_data = decompose (clobber);
return immune_p (op, clobber, early_data);
}
int
find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
rtx insn;
int replace, ind_levels;
int live_known;
short *reload_reg_p;
{
#ifdef REGISTER_CONSTRAINTS
register int insn_code_number;
register int i, j;
int noperands;
char *constraints[MAX_RECOG_OPERANDS];
enum reg_class preferred_class[MAX_RECOG_OPERANDS];
char pref_or_nothing[MAX_RECOG_OPERANDS];
int address_reloaded[MAX_RECOG_OPERANDS];
enum reload_type operand_type[MAX_RECOG_OPERANDS];
enum reload_type address_type[MAX_RECOG_OPERANDS];
enum reload_usage { RELOAD_READ, RELOAD_READ_WRITE, RELOAD_WRITE } modified[MAX_RECOG_OPERANDS];
int no_input_reloads = 0, no_output_reloads = 0;
int n_alternatives;
int this_alternative[MAX_RECOG_OPERANDS];
char this_alternative_win[MAX_RECOG_OPERANDS];
char this_alternative_offmemok[MAX_RECOG_OPERANDS];
char this_alternative_earlyclobber[MAX_RECOG_OPERANDS];
int this_alternative_matches[MAX_RECOG_OPERANDS];
int swapped;
int goal_alternative[MAX_RECOG_OPERANDS];
int this_alternative_number;
int goal_alternative_number;
int operand_reloadnum[MAX_RECOG_OPERANDS];
int goal_alternative_matches[MAX_RECOG_OPERANDS];
int goal_alternative_matched[MAX_RECOG_OPERANDS];
char goal_alternative_win[MAX_RECOG_OPERANDS];
char goal_alternative_offmemok[MAX_RECOG_OPERANDS];
char goal_alternative_earlyclobber[MAX_RECOG_OPERANDS];
int goal_alternative_swapped;
int best;
int commutative;
int changed;
char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
rtx substed_operand[MAX_RECOG_OPERANDS];
rtx body = PATTERN (insn);
rtx set = single_set (insn);
int goal_earlyclobber, this_earlyclobber;
enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
int retval = 0;
static int last_output_reload_regno = -1;
this_insn = insn;
n_reloads = 0;
n_replacements = 0;
n_earlyclobbers = 0;
replace_reloads = replace;
hard_regs_live_known = live_known;
static_reload_reg_p = reload_reg_p;
if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CALL_INSN)
no_output_reloads = 1;
#ifdef HAVE_cc0
if (reg_referenced_p (cc0_rtx, PATTERN (insn)))
no_input_reloads = 1;
if (reg_set_p (cc0_rtx, PATTERN (insn)))
no_output_reloads = 1;
#endif
#ifdef SECONDARY_MEMORY_NEEDED
bzero ((char *) secondary_memlocs_elim, sizeof secondary_memlocs_elim);
#endif
if (GET_CODE (body) == SET
&& GET_CODE (SET_DEST (body)) == REG
&& REGNO (SET_DEST (body)) < FIRST_PSEUDO_REGISTER
&& GET_CODE (SET_SRC (body)) == REG
&& REGNO (SET_SRC (body)) < FIRST_PSEUDO_REGISTER
&& REGISTER_MOVE_COST (REGNO_REG_CLASS (REGNO (SET_SRC (body))),
REGNO_REG_CLASS (REGNO (SET_DEST (body)))) == 2)
return 0;
extract_insn (insn);
noperands = reload_n_operands = recog_n_operands;
n_alternatives = recog_n_alternatives;
if (noperands == 0 || n_alternatives == 0)
return 0;
insn_code_number = INSN_CODE (insn);
this_insn_is_asm = insn_code_number < 0;
bcopy ((char *) recog_operand_mode, (char *) operand_mode,
noperands * sizeof (enum machine_mode));
bcopy ((char *) recog_constraints, (char *) constraints,
noperands * sizeof (char *));
commutative = -1;
for (i = 0; i < noperands; i++)
{
register char *p;
register int c;
substed_operand[i] = recog_operand[i];
p = constraints[i];
modified[i] = RELOAD_READ;
while ((c = *p++))
{
if (c == '=')
modified[i] = RELOAD_WRITE;
else if (c == '+')
modified[i] = RELOAD_READ_WRITE;
else if (c == '%')
{
if (i == noperands - 1)
abort ();
commutative = i;
}
else if (c >= '0' && c <= '9')
{
c -= '0';
operands_match[c][i]
= operands_match_p (recog_operand[c], recog_operand[i]);
if (c == i)
abort ();
if (commutative >= 0)
{
if (c == commutative || c == commutative + 1)
{
int other = c + (c == commutative ? 1 : -1);
operands_match[other][i]
= operands_match_p (recog_operand[other], recog_operand[i]);
}
if (i == commutative || i == commutative + 1)
{
int other = i + (i == commutative ? 1 : -1);
operands_match[c][other]
= operands_match_p (recog_operand[c], recog_operand[other]);
}
}
}
}
}
for (i = 0; i < noperands; i++)
{
register RTX_CODE code = GET_CODE (recog_operand[i]);
address_reloaded[i] = 0;
operand_type[i] = (modified[i] == RELOAD_READ ? RELOAD_FOR_INPUT
: modified[i] == RELOAD_WRITE ? RELOAD_FOR_OUTPUT
: RELOAD_OTHER);
address_type[i]
= (modified[i] == RELOAD_READ ? RELOAD_FOR_INPUT_ADDRESS
: modified[i] == RELOAD_WRITE ? RELOAD_FOR_OUTPUT_ADDRESS
: RELOAD_OTHER);
if (*constraints[i] == 0)
;
else if (constraints[i][0] == 'p')
{
find_reloads_address (VOIDmode, NULL_PTR,
recog_operand[i], recog_operand_loc[i],
i, operand_type[i], ind_levels, insn);
if ((GET_RTX_CLASS (GET_CODE (*recog_operand_loc[i])) == 'o'
|| GET_CODE (*recog_operand_loc[i]) == SUBREG)
&& (GET_CODE (recog_operand[i]) == MULT
|| GET_CODE (recog_operand[i]) == PLUS))
{
INSN_CODE (insn) = -1;
retval = find_reloads (insn, replace, ind_levels, live_known,
reload_reg_p);
return retval;
}
substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
}
else if (code == MEM)
{
address_reloaded[i]
= 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, insn);
substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
}
else if (code == SUBREG)
{
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],
insn);
if (replace
&& 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] = op;
}
else if (code == PLUS || GET_RTX_CLASS (code) == '1')
substed_operand[i] = recog_operand[i]
= find_reloads_toplev (recog_operand[i], i, address_type[i],
ind_levels, 0, insn);
else if (code == REG)
{
register int regno = REGNO (recog_operand[i]);
if (reg_equiv_constant[regno] != 0
&& (set == 0 || &SET_DEST (set) != recog_operand_loc[i]))
{
if (operand_mode[i] == VOIDmode)
operand_mode[i] = GET_MODE (recog_operand[i]);
substed_operand[i] = recog_operand[i]
= reg_equiv_constant[regno];
}
if (reg_equiv_memory_loc[regno] != 0
&& (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
substed_operand[i] = recog_operand[i]
= find_reloads_toplev (recog_operand[i], i, address_type[i],
ind_levels, 0, insn);
}
code = GET_CODE (recog_operand[i]);
preferred_class[i]
= ((code == REG && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER)
? reg_preferred_class (REGNO (recog_operand[i])) : NO_REGS);
pref_or_nothing[i]
= (code == REG && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER
&& reg_alternate_class (REGNO (recog_operand[i])) == NO_REGS);
}
#ifdef HAVE_cc0
if (no_input_reloads)
for (i = 0; i < n_reloads; i++)
if (reload_in[i] != 0)
abort ();
#endif
if (set != 0 && noperands >= 2 && recog_operand[0] == SET_DEST (set)
&& recog_operand[1] == SET_SRC (set))
{
preferred_class[0] = preferred_class[1]
= reg_class_subunion[(int) preferred_class[0]][(int) preferred_class[1]];
pref_or_nothing[0] |= pref_or_nothing[1];
pref_or_nothing[1] |= pref_or_nothing[0];
}
best = MAX_RECOG_OPERANDS * 2 + 600;
swapped = 0;
goal_alternative_swapped = 0;
try_swapped:
for (this_alternative_number = 0;
this_alternative_number < n_alternatives;
this_alternative_number++)
{
int losers = 0;
int bad = 0;
int reject = 0;
this_earlyclobber = 0;
for (i = 0; i < noperands; i++)
{
register char *p = constraints[i];
register int win = 0;
int badop = 1;
int winreg = 0;
int c;
register rtx operand = recog_operand[i];
int offset = 0;
int force_reload = 0;
int offmemok = 0;
int constmemok = 0;
int earlyclobber = 0;
if (GET_RTX_CLASS (GET_CODE (operand)) == '1' && *p != 0)
operand = XEXP (operand, 0);
while (GET_CODE (operand) == SUBREG)
{
offset += SUBREG_WORD (operand);
operand = SUBREG_REG (operand);
if (CONSTANT_P (operand)
|| GET_CODE (operand) == PLUS
|| ((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])
> 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
)
#endif
)
|| (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 (GET_MODE (operand))
/ UNITS_PER_WORD)
!= HARD_REGNO_NREGS (REGNO (operand),
GET_MODE (operand))))
|| ! HARD_REGNO_MODE_OK (REGNO (operand) + offset,
operand_mode[i]))))
force_reload = 1;
}
this_alternative[i] = (int) NO_REGS;
this_alternative_win[i] = 0;
this_alternative_offmemok[i] = 0;
this_alternative_earlyclobber[i] = 0;
this_alternative_matches[i] = -1;
if (*p == 0 || *p == ',')
win = 1, badop = 0;
while (*p && (c = *p++) != ',')
switch (c)
{
case '=':
case '+':
case '*':
break;
case '%':
if (i != noperands - 1)
commutative = i;
break;
case '?':
reject += 6;
break;
case '!':
reject = 600;
break;
case '#':
while (*p && *p != ',') p++;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
c -= '0';
this_alternative_matches[i] = c;
if ((swapped && (c != commutative || i != commutative + 1))
? (operands_match
[(c == commutative || c == commutative + 1)
? 2*commutative + 1 - c : c]
[(i == commutative || i == commutative + 1)
? 2*commutative + 1 - i : i])
: operands_match[c][i])
{
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
{
rtx value;
if (this_alternative_win[c])
losers++;
this_alternative_win[c] = 0;
if (this_alternative[c] == (int) NO_REGS)
bad = 1;
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,
this_alternative_earlyclobber[c]);
if (value != 0)
losers--;
}
badop = 0;
this_alternative[i] = this_alternative[c];
if (! win || force_reload)
for (j = 0; j < i; j++)
if (this_alternative_matches[j]
== this_alternative_matches[i])
badop = 1;
break;
case 'p':
this_alternative[i] = (int) BASE_REG_CLASS;
win = 1;
break;
case 'm':
if (force_reload)
break;
if (GET_CODE (operand) == MEM
|| (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (operand)] < 0))
win = 1;
if (CONSTANT_P (operand)
&& GET_CODE (operand) != HIGH)
badop = 0;
constmemok = 1;
break;
case '<':
if (GET_CODE (operand) == MEM
&& ! address_reloaded[i]
&& (GET_CODE (XEXP (operand, 0)) == PRE_DEC
|| GET_CODE (XEXP (operand, 0)) == POST_DEC))
win = 1;
break;
case '>':
if (GET_CODE (operand) == MEM
&& ! address_reloaded[i]
&& (GET_CODE (XEXP (operand, 0)) == PRE_INC
|| GET_CODE (XEXP (operand, 0)) == POST_INC))
win = 1;
break;
case 'V':
if (force_reload)
break;
if (GET_CODE (operand) == MEM
&& ! (ind_levels ? offsettable_memref_p (operand)
: offsettable_nonstrict_memref_p (operand))
&& !(GET_CODE (XEXP (operand, 0)) == REG
&& (ind_levels == 0
|| reg_equiv_address[REGNO (XEXP (operand, 0))] != 0)))
win = 1;
break;
case 'o':
if (force_reload)
break;
if ((GET_CODE (operand) == MEM
&& ((ind_levels ? offsettable_memref_p (operand)
: offsettable_nonstrict_memref_p (operand))
|| address_reloaded[i]))
|| (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (operand)] < 0
&& ((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) != HIGH)
|| GET_CODE (operand) == MEM)
badop = 0;
constmemok = 1;
offmemok = 1;
break;
case '&':
earlyclobber = 1, this_earlyclobber = 1;
break;
case 'E':
#ifndef REAL_ARITHMETIC
if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
|| HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
&& GET_MODE (operand) != VOIDmode && ! flag_pretend_float)
break;
#endif
if (GET_CODE (operand) == CONST_DOUBLE)
win = 1;
break;
case 'F':
if (GET_CODE (operand) == CONST_DOUBLE)
win = 1;
break;
case 'G':
case 'H':
if (GET_CODE (operand) == CONST_DOUBLE
&& CONST_DOUBLE_OK_FOR_LETTER_P (operand, c))
win = 1;
break;
case 's':
if (GET_CODE (operand) == CONST_INT
|| (GET_CODE (operand) == CONST_DOUBLE
&& GET_MODE (operand) == VOIDmode))
break;
case 'i':
if (CONSTANT_P (operand)
#ifdef LEGITIMATE_PIC_OPERAND_P
&& (! flag_pic || LEGITIMATE_PIC_OPERAND_P (operand))
#endif
)
win = 1;
break;
case 'n':
if (GET_CODE (operand) == CONST_INT
|| (GET_CODE (operand) == CONST_DOUBLE
&& GET_MODE (operand) == VOIDmode))
win = 1;
break;
#ifdef EXTRA_CONSTANT_CONSTRAINTS
case 'A':
case 'B':
case 'C':
case 'D':
#endif
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
if (GET_CODE (operand) == CONST_INT
&& CONST_OK_FOR_LETTER_P (INTVAL (operand), c))
win = 1;
break;
case 'X':
win = 1;
break;
case 'g':
if (! force_reload
&& GET_CODE (operand) != PLUS
&& GET_CODE (operand) != SCRATCH
#ifdef LEGITIMATE_PIC_OPERAND_P
&& (! CONSTANT_P (operand)
|| ! flag_pic
|| LEGITIMATE_PIC_OPERAND_P (operand))
#endif
&& (GENERAL_REGS == ALL_REGS
|| GET_CODE (operand) != REG
|| (REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (operand)] < 0)))
win = 1;
case 'r':
this_alternative[i]
= (int) reg_class_subunion[this_alternative[i]][(int) GENERAL_REGS];
goto reg;
#ifdef EXTRA_CONSTRAINT
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
if (EXTRA_CONSTRAINT (operand, c))
win = 1;
break;
#endif
default:
this_alternative[i]
= (int) reg_class_subunion[this_alternative[i]][(int) REG_CLASS_FROM_LETTER (c)];
reg:
if (GET_MODE (operand) == BLKmode)
break;
winreg = 1;
if (GET_CODE (operand) == REG
&& reg_fits_class_p (operand, this_alternative[i],
offset, GET_MODE (recog_operand[i])))
win = 1;
break;
}
constraints[i] = p;
if (winreg && this_alternative[i] != (int) NO_REGS)
badop = 0;
this_alternative_earlyclobber[i] = earlyclobber;
if (win && ! force_reload)
this_alternative_win[i] = 1;
else
{
int const_to_mem = 0;
this_alternative_offmemok[i] = offmemok;
losers++;
if (badop)
bad = 1;
if (GET_CODE (operand) == REG
&& this_alternative[i] == (int) NO_REGS
&& this_alternative_matches[i] < 0)
bad = 1;
#if 0
if (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& REGNO (operand) == last_output_reload_regno)
reject--;
#endif
if (CONSTANT_P (operand)
&& GET_CODE (operand) != HIGH
&& ((PREFERRED_RELOAD_CLASS (operand,
(enum reg_class) this_alternative[i])
== NO_REGS)
|| no_input_reloads)
&& operand_mode[i] != VOIDmode)
{
const_to_mem = 1;
if (this_alternative[i] != (int) NO_REGS)
losers++;
}
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;
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;
if (! (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER)
&& GET_CODE (operand) != SCRATCH
&& ! (const_to_mem && constmemok))
reject += 2;
if (operand_type[i] != RELOAD_FOR_INPUT
&& GET_CODE (operand) != SCRATCH)
reject++;
}
if (! win && this_alternative[i] != (int) NO_REGS
&& GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
&& reg_class_size[(int) preferred_class[i]] > 1)
{
if (! reg_class_subset_p (this_alternative[i],
preferred_class[i]))
{
if (reg_class_subset_p (preferred_class[i],
this_alternative[i]))
this_alternative[i] = (int) preferred_class[i];
else
reject += (2 + 2 * pref_or_nothing[i]);
}
}
}
for (i = 0; i < noperands; i++)
if (this_alternative_earlyclobber[i]
&& this_alternative_win[i])
{
struct decomposition early_data;
early_data = decompose (recog_operand[i]);
if (modified[i] == RELOAD_READ)
abort ();
if (this_alternative[i] == NO_REGS)
{
this_alternative_earlyclobber[i] = 0;
if (this_insn_is_asm)
error_for_asm (this_insn,
"`&' constraint used with no register class");
else
abort ();
}
for (j = 0; j < noperands; j++)
if ((GET_CODE (recog_operand[j]) == MEM
|| modified[j] != RELOAD_WRITE)
&& j != i
&& *recog_constraints[j] != 0
&& ! (this_alternative_matches[j] == i
&& rtx_equal_p (recog_operand[i], recog_operand[j]))
&& !immune_p (recog_operand[j], recog_operand[i], early_data))
{
if (reg_class_size[this_alternative[i]] == 1
&& (GET_CODE (recog_operand[j]) == REG
|| GET_CODE (recog_operand[j]) == SUBREG))
{
losers++;
this_alternative_win[j] = 0;
}
else
break;
}
if (j != noperands)
{
losers++;
this_alternative_win[i] = 0;
for (j = 0; j < noperands; j++)
if (this_alternative_matches[j] == i
&& this_alternative_win[j])
{
this_alternative_win[j] = 0;
losers++;
}
}
}
if (losers == 0)
{
if (commutative >= 0)
{
recog_operand[commutative] = substed_operand[commutative];
recog_operand[commutative + 1]
= substed_operand[commutative + 1];
}
for (i = 0; i < noperands; i++)
{
goal_alternative_win[i] = 1;
goal_alternative[i] = this_alternative[i];
goal_alternative_offmemok[i] = this_alternative_offmemok[i];
goal_alternative_matches[i] = this_alternative_matches[i];
goal_alternative_earlyclobber[i]
= this_alternative_earlyclobber[i];
}
goal_alternative_number = this_alternative_number;
goal_alternative_swapped = swapped;
goal_earlyclobber = this_earlyclobber;
goto finish;
}
losers = losers * 6 + reject;
if (! bad && best > losers)
{
for (i = 0; i < noperands; i++)
{
goal_alternative[i] = this_alternative[i];
goal_alternative_win[i] = this_alternative_win[i];
goal_alternative_offmemok[i] = this_alternative_offmemok[i];
goal_alternative_matches[i] = this_alternative_matches[i];
goal_alternative_earlyclobber[i]
= this_alternative_earlyclobber[i];
}
goal_alternative_swapped = swapped;
best = losers;
goal_alternative_number = this_alternative_number;
goal_earlyclobber = this_earlyclobber;
}
}
if (commutative >= 0)
{
swapped = !swapped;
if (swapped)
{
register enum reg_class tclass;
register int t;
recog_operand[commutative] = substed_operand[commutative + 1];
recog_operand[commutative + 1] = substed_operand[commutative];
tclass = preferred_class[commutative];
preferred_class[commutative] = preferred_class[commutative + 1];
preferred_class[commutative + 1] = tclass;
t = pref_or_nothing[commutative];
pref_or_nothing[commutative] = pref_or_nothing[commutative + 1];
pref_or_nothing[commutative + 1] = t;
bcopy ((char *) recog_constraints, (char *) constraints,
noperands * sizeof (char *));
goto try_swapped;
}
else
{
recog_operand[commutative] = substed_operand[commutative];
recog_operand[commutative + 1] = substed_operand[commutative + 1];
}
}
if (best == MAX_RECOG_OPERANDS * 2 + 600)
{
if (insn_code_number >= 0)
fatal_insn ("Unable to generate reloads for:", insn);
error_for_asm (insn, "inconsistent operand constraints in an `asm'");
PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
n_reloads = 0;
return 0;
}
finish:
for (i = 0; i < noperands; i++)
goal_alternative_matched[i] = -1;
for (i = 0; i < noperands; i++)
if (! goal_alternative_win[i]
&& goal_alternative_matches[i] >= 0)
goal_alternative_matched[goal_alternative_matches[i]] = i;
if (goal_alternative_swapped)
{
register rtx tem;
tem = substed_operand[commutative];
substed_operand[commutative] = substed_operand[commutative + 1];
substed_operand[commutative + 1] = tem;
tem = recog_operand[commutative];
recog_operand[commutative] = recog_operand[commutative + 1];
recog_operand[commutative + 1] = tem;
tem = *recog_operand_loc[commutative];
*recog_operand_loc[commutative] = *recog_operand_loc[commutative+1];
*recog_operand_loc[commutative+1] = tem;
for (i = 0; i < n_reloads; i++)
{
if (reload_opnum[i] == commutative)
reload_opnum[i] = commutative + 1;
else if (reload_opnum[i] == commutative + 1)
reload_opnum[i] = commutative;
}
}
for (i = 0; i < noperands; i++)
{
operand_reloadnum[i] = -1;
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);
}
for (i = 0; i < noperands; i++)
if (! goal_alternative_win[i]
&& CONSTANT_P (recog_operand[i])
&& GET_CODE (recog_operand[i]) != HIGH
&& ((PREFERRED_RELOAD_CLASS (recog_operand[i],
(enum reg_class) goal_alternative[i])
== NO_REGS)
|| no_input_reloads)
&& operand_mode[i] != VOIDmode)
{
substed_operand[i] = recog_operand[i]
= find_reloads_toplev (force_const_mem (operand_mode[i],
recog_operand[i]),
i, address_type[i], ind_levels, 0, insn);
if (alternative_allows_memconst (recog_constraints[i],
goal_alternative_number))
goal_alternative_win[i] = 1;
}
if (goal_earlyclobber)
for (i = 0; i < noperands; i++)
if (goal_alternative_earlyclobber[i])
reload_earlyclobbers[n_earlyclobbers++] = recog_operand[i];
last_output_reload_regno = -1;
for (i = 0; i < noperands; i++)
if (! goal_alternative_win[i])
{
if (goal_alternative_matches[i] >= 0)
;
else if (goal_alternative_matched[i] == -1
&& goal_alternative_offmemok[i]
&& GET_CODE (recog_operand[i]) == MEM)
{
operand_reloadnum[i]
= push_reload (XEXP (recog_operand[i], 0), NULL_RTX,
&XEXP (recog_operand[i], 0), NULL_PTR,
BASE_REG_CLASS, GET_MODE (XEXP (recog_operand[i], 0)),
VOIDmode, 0, 0, i, RELOAD_FOR_INPUT);
reload_inc[operand_reloadnum[i]]
= GET_MODE_SIZE (GET_MODE (recog_operand[i]));
#ifdef MACHO_PIC
if (operand_type[i] == RELOAD_FOR_OUTPUT)
#else
if (modified[i] == RELOAD_WRITE)
#endif
{
for (j = 0; j < n_reloads; j++)
{
if (reload_opnum[j] == i)
{
if (reload_when_needed[j] == RELOAD_FOR_OUTPUT_ADDRESS)
reload_when_needed[j] = RELOAD_FOR_INPUT_ADDRESS;
else if (reload_when_needed[j]
== RELOAD_FOR_OUTADDR_ADDRESS)
reload_when_needed[j] = RELOAD_FOR_INPADDR_ADDRESS;
}
}
}
}
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]);
if (modified[i] != RELOAD_READ
&& GET_CODE (recog_operand[i]) == REG)
last_output_reload_regno = REGNO (recog_operand[i]);
}
else if (modified[i] == RELOAD_READ
&& modified[goal_alternative_matched[i]] == RELOAD_WRITE)
{
operand_reloadnum[i]
= push_reload (recog_operand[i],
recog_operand[goal_alternative_matched[i]],
recog_operand_loc[i],
recog_operand_loc[goal_alternative_matched[i]],
(enum reg_class) goal_alternative[i],
operand_mode[i],
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_reloadnum[goal_alternative_matched[i]]
= push_reload (recog_operand[goal_alternative_matched[i]],
recog_operand[i],
recog_operand_loc[goal_alternative_matched[i]],
recog_operand_loc[i],
(enum reg_class) goal_alternative[i],
operand_mode[goal_alternative_matched[i]],
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 ();
else
{
error_for_asm (insn, "inconsistent operand constraints in an `asm'");
PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
n_reloads = 0;
return 0;
}
}
else if (goal_alternative_matched[i] < 0
&& goal_alternative_matches[i] < 0
&& optimize)
{
rtx operand = recog_operand[i];
while (GET_CODE (operand) == SUBREG)
operand = XEXP (operand, 0);
if ((GET_CODE (operand) == MEM
|| (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER))
&& ((enum reg_class) goal_alternative[i] != NO_REGS
|| modified[i] == RELOAD_WRITE)
&& ! no_input_reloads
&& (modified[i] == RELOAD_READ
|| (! no_output_reloads && ! this_insn_is_asm)))
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]),
1, i, operand_type[i]);
else if (replace
&& (GET_CODE (operand) == MEM
|| (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber [REGNO (operand)] < 0)))
{
operand = *recog_operand_loc[i];
while (GET_CODE (operand) == SUBREG)
operand = XEXP (operand, 0);
if (GET_CODE (operand) == REG)
{
if (modified[i] != RELOAD_WRITE)
emit_insn_before (gen_rtx_USE (VOIDmode, operand), insn);
if (modified[i] != RELOAD_READ)
emit_insn_after (gen_rtx_CLOBBER (VOIDmode, operand), insn);
}
}
}
else if (goal_alternative_matches[i] >= 0
&& goal_alternative_win[goal_alternative_matches[i]]
&& modified[i] == RELOAD_READ
&& modified[goal_alternative_matches[i]] == RELOAD_WRITE
&& ! no_input_reloads && ! no_output_reloads
&& optimize)
{
rtx operand = recog_operand[i];
while (GET_CODE (operand) == SUBREG)
operand = XEXP (operand, 0);
if ((GET_CODE (operand) == MEM
|| (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER))
&& ((enum reg_class) goal_alternative[goal_alternative_matches[i]]
!= NO_REGS))
operand_reloadnum[i] = operand_reloadnum[goal_alternative_matches[i]]
= push_reload (recog_operand[goal_alternative_matches[i]],
recog_operand[i],
recog_operand_loc[goal_alternative_matches[i]],
recog_operand_loc[i],
(enum reg_class) goal_alternative[goal_alternative_matches[i]],
operand_mode[goal_alternative_matches[i]],
operand_mode[i],
0, 1, goal_alternative_matches[i], RELOAD_OTHER);
}
for (i = 0; i < noperands; i++)
{
if (replace)
{
rtx substitution = substed_operand[i];
*recog_operand_loc[i] = substitution;
if (GET_CODE (insn) != JUMP_INSN
&& GET_CODE (substitution) == LABEL_REF
&& !find_reg_note (insn, REG_LABEL, XEXP (substitution, 0)))
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL,
XEXP (substitution, 0),
REG_NOTES (insn));
}
else
retval |= (substed_operand[i] != *recog_operand_loc[i]);
}
if (insn_code_number >= 0 && replace)
for (i = insn_n_dups[insn_code_number] - 1; i >= 0; i--)
{
int opno = recog_dup_num[i];
*recog_dup_loc[i] = *recog_operand_loc[opno];
if (operand_reloadnum[opno] >= 0)
push_replacement (recog_dup_loc[i], operand_reloadnum[opno],
insn_operand_mode[insn_code_number][opno]);
}
#if 0
for (i = 0; i < n_reloads; i++)
if (reload_reg_rtx[i] == 0
&& reload_in[i] != 0
&& GET_CODE (reload_in[i]) == REG
&& reload_out[i] == 0)
{
reload_reg_rtx[i]
= find_equiv_reg (reload_in[i], insn, reload_reg_class[i], -1,
static_reload_reg_p, 0, reload_inmode[i]);
if (reload_reg_rtx[i])
reload_in[i] = reload_reg_rtx[i];
}
#endif
if (!goal_earlyclobber)
combine_reloads ();
for (i = 0; i < n_reloads; i++)
{
int k;
for (j = i + 1; j < n_reloads; j++)
if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
|| reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS
|| reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
|| reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
&& (reload_when_needed[j] == RELOAD_FOR_INPUT_ADDRESS
|| reload_when_needed[j] == RELOAD_FOR_OUTPUT_ADDRESS
|| reload_when_needed[j] == RELOAD_FOR_INPADDR_ADDRESS
|| reload_when_needed[j] == RELOAD_FOR_OUTADDR_ADDRESS)
&& rtx_equal_p (reload_in[i], reload_in[j])
&& (operand_reloadnum[reload_opnum[i]] < 0
|| reload_optional[operand_reloadnum[reload_opnum[i]]])
&& (operand_reloadnum[reload_opnum[j]] < 0
|| reload_optional[operand_reloadnum[reload_opnum[j]]])
&& (goal_alternative_matches[reload_opnum[i]] == reload_opnum[j]
|| (goal_alternative_matches[reload_opnum[j]]
== reload_opnum[i])))
{
for (k = 0; k < n_replacements; k++)
if (replacements[k].what == j)
replacements[k].what = i;
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_in[j] = 0;
}
}
for (i = 0; i < n_reloads; i++)
{
if (reload_secondary_p[i]
&& reload_when_needed[i] == operand_type[reload_opnum[i]])
reload_when_needed[i] = address_type[reload_opnum[i]];
if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
|| reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS
|| reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
|| reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
&& (operand_reloadnum[reload_opnum[i]] < 0
|| reload_optional[operand_reloadnum[reload_opnum[i]]]))
{
if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
|| reload_when_needed[i] == RELOAD_FOR_INPADDR_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 (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_when_needed[i] == RELOAD_FOR_OUTADDR_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 (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;
}
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;
}
if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
|| reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS)
&& operand_reloadnum[reload_opnum[i]] >= 0
&& (reload_when_needed[operand_reloadnum[reload_opnum[i]]]
== RELOAD_OTHER))
reload_when_needed[i] = RELOAD_FOR_OTHER_ADDRESS;
if (goal_alternative_matches[reload_opnum[i]] >= 0)
reload_opnum[i] = goal_alternative_matches[reload_opnum[i]];
}
{
int first_op_addr_num = -2;
int first_inpaddr_num[MAX_RECOG_OPERANDS];
int first_outpaddr_num[MAX_RECOG_OPERANDS];
int need_change= 0;
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 >= 0)
{
first_op_addr_num = i;
need_change = 1;
}
break;
case RELOAD_FOR_INPUT_ADDRESS:
if (++first_inpaddr_num[reload_opnum[i]] >= 0)
{
first_inpaddr_num[reload_opnum[i]] = i;
need_change = 1;
}
break;
case RELOAD_FOR_OUTPUT_ADDRESS:
if (++first_outpaddr_num[reload_opnum[i]] >= 0)
{
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 (first_num < 0)
continue;
else if (i > first_num)
reload_when_needed[i] = type;
else
{
for (j = n_reloads - 1; j > first_num; j--)
{
if (reload_when_needed[j] == type
&& (reload_secondary_p[i]
? reload_secondary_in_reload[j] == i
: reg_mentioned_p (reload_in[i], reload_in[j])))
{
reload_when_needed[i] = type;
break;
}
}
}
}
}
}
for (i = 0; i < n_reloads; i++)
if (reload_in[i] != 0 && reload_out[i] == 0
&& (reload_when_needed[i] == RELOAD_FOR_OPERAND_ADDRESS
|| reload_when_needed[i] == RELOAD_FOR_OPADDR_ADDR
|| reload_when_needed[i] == RELOAD_FOR_OTHER_ADDRESS))
for (j = 0; j < n_reloads; j++)
if (i != j && reload_in[j] != 0 && reload_out[j] == 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_reg_rtx[i] == reload_reg_rtx[j])
{
reload_opnum[i] = MIN (reload_opnum[i], reload_opnum[j]);
transfer_replacements (i, j);
reload_in[j] = 0;
}
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
int noperands;
int insn_code_number;
int goal_earlyclobber = 0;
register int i;
rtx body = PATTERN (insn);
int retval = 0;
n_reloads = 0;
n_replacements = 0;
n_earlyclobbers = 0;
replace_reloads = replace;
this_insn = insn;
extract_insn (insn);
noperands = reload_n_operands = recog_n_operands;
if (noperands == 0)
return;
for (i = 0; i < noperands; i++)
{
register RTX_CODE code = GET_CODE (recog_operand[i]);
int is_set_dest = GET_CODE (body) == SET && (i == 0);
if (insn_code_number >= 0)
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, insn);
if (code == MEM)
find_reloads_address (GET_MODE (recog_operand[i]),
recog_operand_loc[i],
XEXP (recog_operand[i], 0),
&XEXP (recog_operand[i], 0),
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,
ind_levels, is_set_dest);
if (code == REG)
{
register int regno = REGNO (recog_operand[i]);
if (reg_equiv_constant[regno] != 0 && !is_set_dest)
recog_operand[i] = *recog_operand_loc[i]
= reg_equiv_constant[regno];
#if 0
if (reg_equiv_mem[regno] != 0)
recog_operand[i] = *recog_operand_loc[i]
= reg_equiv_mem[regno];
#endif
}
}
if (!goal_earlyclobber)
combine_reloads ();
#endif
return retval;
}
static int
alternative_allows_memconst (constraint, altnum)
const char *constraint;
int altnum;
{
register int c;
while (altnum > 0)
{
while (*constraint++ != ',');
altnum--;
}
while ((c = *constraint++) && c != ',' && c != '#')
if (c == 'm' || c == 'o')
return 1;
return 0;
}
static rtx
find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn)
rtx x;
int opnum;
enum reload_type type;
int ind_levels;
int is_set_dest;
rtx insn;
{
register RTX_CODE code = GET_CODE (x);
register char *fmt = GET_RTX_FORMAT (code);
register int i;
int copied;
if (code == REG)
{
register int regno = REGNO (x);
if (reg_equiv_constant[regno] != 0 && !is_set_dest)
x = reg_equiv_constant[regno];
#if 0
else if (reg_equiv_mem[regno] != 0)
x = reg_equiv_mem[regno];
#endif
else if (reg_equiv_memory_loc[regno]
&& (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
{
rtx mem = make_memloc (x, regno);
if (reg_equiv_address[regno]
|| ! rtx_equal_p (mem, reg_equiv_mem[regno]))
{
if (replace_reloads && recog_operand[opnum] != x)
emit_insn_before (gen_rtx_USE (VOIDmode, x), insn);
x = mem;
find_reloads_address (GET_MODE (x), &x, XEXP (x, 0), &XEXP (x, 0),
opnum, type, ind_levels, insn);
}
}
return x;
}
if (code == MEM)
{
rtx tem = x;
find_reloads_address (GET_MODE (x), &tem, XEXP (x, 0), &XEXP (x, 0),
opnum, type, ind_levels, insn);
return tem;
}
if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG)
{
register int regno = REGNO (SUBREG_REG (x));
rtx tem;
if (subreg_lowpart_p (x)
&& regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0
&& (tem = gen_lowpart_common (GET_MODE (x),
reg_equiv_constant[regno])) != 0)
return tem;
if (GET_MODE_BITSIZE (GET_MODE (x)) == BITS_PER_WORD
&& regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0
&& (tem = operand_subword (reg_equiv_constant[regno],
SUBREG_WORD (x), 0,
GET_MODE (SUBREG_REG (x)))) != 0)
{
tem = gen_lowpart_common (GET_MODE (x), tem);
if (!tem)
abort ();
return tem;
}
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);
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
&& GET_MODE (reg_equiv_constant[regno]) == VOIDmode)
abort ();
else if (regno >= FIRST_PSEUDO_REGISTER
#ifdef LOAD_EXTEND_OP
&& (GET_MODE_SIZE (GET_MODE (x))
<= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
#endif
&& (reg_equiv_address[regno] != 0
|| (reg_equiv_mem[regno] != 0
&& (! strict_memory_address_p (GET_MODE (x),
XEXP (reg_equiv_mem[regno], 0))
|| ! offsettable_memref_p (reg_equiv_mem[regno])
|| num_not_at_initial_offset))))
x = find_reloads_subreg_address (x, 1, opnum, type, ind_levels,
insn);
}
for (copied = 0, i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
rtx new_part = find_reloads_toplev (XEXP (x, i), opnum, type,
ind_levels, is_set_dest, insn);
if (new_part != XEXP (x, i) && ! CONSTANT_P (new_part) && ! copied)
{
x = shallow_copy_rtx (x);
copied = 1;
}
XEXP (x, i) = new_part;
}
}
return x;
}
static rtx
make_memloc (ad, regno)
rtx ad;
int regno;
{
rtx tem
= XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0, NULL_RTX), 0);
#if 0
for (i = 0; i < n_memlocs; i++)
if (rtx_equal_p (tem, XEXP (memlocs[i], 0)))
return memlocs[i];
#endif
if (rtx_varies_p (tem))
tem = copy_rtx (tem);
tem = gen_rtx_MEM (GET_MODE (ad), tem);
RTX_UNCHANGING_P (tem) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
return tem;
}
static int
find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
enum machine_mode mode;
rtx *memrefloc;
rtx ad;
rtx *loc;
int opnum;
enum reload_type type;
int ind_levels;
rtx insn;
{
register int regno;
int removed_and = 0;
rtx tem;
if (GET_CODE (ad) == REG)
{
regno = REGNO (ad);
if (reg_equiv_constant[regno] != 0
&& strict_memory_address_p (mode, reg_equiv_constant[regno]))
{
*loc = ad = reg_equiv_constant[regno];
return 0;
}
tem = reg_equiv_memory_loc[regno];
if (tem != 0)
{
if (reg_equiv_address[regno] != 0 || num_not_at_initial_offset)
{
tem = make_memloc (ad, regno);
if (! strict_memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
{
find_reloads_address (GET_MODE (tem), NULL_PTR, XEXP (tem, 0),
&XEXP (tem, 0), opnum, ADDR_TYPE (type),
ind_levels, insn);
}
if (ind_levels > 0
&& strict_memory_address_p (mode, tem)
&& (GET_CODE (XEXP (tem, 0)) == REG
|| (GET_CODE (XEXP (tem, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (tem, 0), 0)) == REG
&& CONSTANT_P (XEXP (XEXP (tem, 0), 1)))))
{
if (replace_reloads
&& num_not_at_initial_offset
&& ! rtx_equal_p (tem, reg_equiv_mem[regno]))
{
*loc = tem;
emit_insn_before (gen_rtx_USE (VOIDmode, ad), insn);
}
return 0;
}
ad = tem;
}
}
else if (regno < FIRST_PSEUDO_REGISTER
&& REGNO_MODE_OK_FOR_BASE_P (regno, mode)
&& ! regno_clobbered_p (regno, this_insn))
return 0;
push_reload (ad, NULL_RTX, loc, NULL_PTR, BASE_REG_CLASS,
GET_MODE (ad), VOIDmode, 0, 0, opnum, type);
return 1;
}
if (strict_memory_address_p (mode, ad))
{
if (GET_CODE (ad) == PLUS
&& GET_CODE (XEXP (ad, 1)) == CONST_INT
&& GET_CODE (XEXP (ad, 0)) == REG
&& reg_equiv_constant[REGNO (XEXP (ad, 0))] == 0)
return 0;
#ifdef MACHO_PIC
if (GET_CODE (ad) == PLUS
&& GET_CODE (XEXP (ad, 1)) == CONST
&& GET_CODE (XEXP (XEXP (ad, 1), 0)) == MINUS
&& GET_CODE (XEXP (ad, 0)) == REG
&& reg_equiv_constant[REGNO (XEXP (ad, 0))] == 0)
return 0;
#endif
subst_reg_equivs_changed = 0;
*loc = subst_reg_equivs (ad, insn);
if (! subst_reg_equivs_changed)
return 0;
if (strict_memory_address_p (mode, ad))
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
if (GET_CODE (ad) == AND)
{
removed_and = 1;
loc = &XEXP (ad, 0);
ad = *loc;
}
if (GET_CODE (ad) == MEM)
{
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, insn);
if (tem != ad && memrefloc)
{
*memrefloc = copy_rtx (*memrefloc);
copy_replacements (tem, XEXP (*memrefloc, 0));
loc = &XEXP (*memrefloc, 0);
if (removed_and)
loc = &XEXP (*loc, 0);
}
if (ind_levels == 0
|| (GET_CODE (XEXP (tem, 0)) == SYMBOL_REF && ! indirect_symref_ok)
|| GET_CODE (XEXP (tem, 0)) == MEM
|| ! (GET_CODE (XEXP (tem, 0)) == REG
|| (GET_CODE (XEXP (tem, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (tem, 0), 0)) == REG
&& GET_CODE (XEXP (XEXP (tem, 0), 1)) == CONST_INT)))
{
push_reload (tem, NULL_RTX, loc, NULL_PTR,
BASE_REG_CLASS, GET_MODE (tem),
VOIDmode, 0,
0, opnum, type);
return ! removed_and;
}
else
return 0;
}
else if (GET_CODE (ad) == PLUS
&& GET_CODE (XEXP (ad, 0)) == REG
&& REGNO (XEXP (ad, 0)) < FIRST_PSEUDO_REGISTER
&& REG_MODE_OK_FOR_BASE_P (XEXP (ad, 0), mode)
&& GET_CODE (XEXP (ad, 1)) == CONST_INT)
{
if (memrefloc)
{
*memrefloc = copy_rtx (*memrefloc);
loc = &XEXP (*memrefloc, 0);
if (removed_and)
loc = &XEXP (*loc, 0);
}
if (double_reg_address_ok)
{
*loc = ad = copy_rtx (ad);
find_reloads_address_part (XEXP (ad, 1), &XEXP (ad, 1),
INDEX_REG_CLASS, GET_MODE (ad), opnum,
type, ind_levels);
return 0;
}
else
{
find_reloads_address_part (ad, loc, BASE_REG_CLASS,
Pmode, opnum, type, ind_levels);
}
return ! removed_and;
}
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
|| 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))),
XEXP (XEXP (ad, 0), 1));
find_reloads_address_part (XEXP (ad, 0), &XEXP (ad, 0), 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, insn);
return 0;
}
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
|| 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))));
find_reloads_address_part (XEXP (ad, 1), &XEXP (ad, 1), 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, insn);
return 0;
}
tem = ad;
if (GET_CODE (ad) == PLUS)
tem = subst_indexed_address (ad);
if (tem != ad && strict_memory_address_p (mode, tem))
{
subst_reg_equivs_changed = 0;
tem = subst_reg_equivs (tem, insn);
if (! subst_reg_equivs_changed || strict_memory_address_p (mode, tem))
{
*loc = tem;
return 0;
}
}
if (CONSTANT_P (ad) && ! strict_memory_address_p (mode, ad))
{
if (memrefloc && GET_CODE (ad) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (ad))
{
*memrefloc = copy_rtx (*memrefloc);
loc = &XEXP (*memrefloc, 0);
if (removed_and)
loc = &XEXP (*loc, 0);
}
find_reloads_address_part (ad, loc, BASE_REG_CLASS, Pmode, opnum, type,
ind_levels);
return ! removed_and;
}
return find_reloads_address_1 (mode, ad, 0, loc, opnum, type, ind_levels,
insn);
}
static rtx
subst_reg_equivs (ad, insn)
rtx ad;
rtx insn;
{
register RTX_CODE code = GET_CODE (ad);
register int i;
register char *fmt;
switch (code)
{
case HIGH:
case CONST_INT:
case CONST:
case CONST_DOUBLE:
case SYMBOL_REF:
case LABEL_REF:
case PC:
case CC0:
return ad;
case REG:
{
register int regno = REGNO (ad);
if (reg_equiv_constant[regno] != 0)
{
subst_reg_equivs_changed = 1;
return reg_equiv_constant[regno];
}
if (reg_equiv_memory_loc[regno] && num_not_at_initial_offset)
{
rtx mem = make_memloc (ad, regno);
if (! rtx_equal_p (mem, reg_equiv_mem[regno]))
{
subst_reg_equivs_changed = 1;
emit_insn_before (gen_rtx_USE (VOIDmode, ad), insn);
return mem;
}
}
}
return ad;
case PLUS:
if (XEXP (ad, 0) == frame_pointer_rtx
&& GET_CODE (XEXP (ad, 1)) == CONST_INT)
return ad;
break;
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
XEXP (ad, i) = subst_reg_equivs (XEXP (ad, i), insn);
return ad;
}
rtx
form_sum (x, y)
rtx x, y;
{
rtx tem;
enum machine_mode mode = GET_MODE (x);
if (mode == VOIDmode)
mode = GET_MODE (y);
if (mode == VOIDmode)
mode = Pmode;
if (GET_CODE (x) == CONST_INT)
return plus_constant (y, INTVAL (x));
else if (GET_CODE (y) == CONST_INT)
return plus_constant (x, INTVAL (y));
else if (CONSTANT_P (x))
tem = x, x = y, y = tem;
if (GET_CODE (x) == PLUS && CONSTANT_P (XEXP (x, 1)))
return form_sum (XEXP (x, 0), form_sum (XEXP (x, 1), y));
if (GET_CODE (y) == PLUS && CONSTANT_P (XEXP (y, 1)))
return form_sum (form_sum (x, XEXP (y, 0)), XEXP (y, 1));
if (CONSTANT_P (x) && CONSTANT_P (y))
{
if (GET_CODE (x) == CONST)
x = XEXP (x, 0);
if (GET_CODE (y) == CONST)
y = XEXP (y, 0);
return gen_rtx_CONST (VOIDmode, gen_rtx_PLUS (mode, x, y));
}
return gen_rtx_PLUS (mode, x, y);
}
static rtx
subst_indexed_address (addr)
rtx addr;
{
rtx op0 = 0, op1 = 0, op2 = 0;
rtx tem;
int regno;
if (GET_CODE (addr) == PLUS)
{
op0 = XEXP (addr, 0), op1 = XEXP (addr, 1), op2 = 0;
if (GET_CODE (op0) == REG
&& (regno = REGNO (op0)) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0)
op0 = reg_equiv_constant[regno];
else if (GET_CODE (op1) == REG
&& (regno = REGNO (op1)) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0)
op1 = reg_equiv_constant[regno];
else if (GET_CODE (op0) == PLUS
&& (tem = subst_indexed_address (op0)) != op0)
op0 = tem;
else if (GET_CODE (op1) == PLUS
&& (tem = subst_indexed_address (op1)) != op1)
op1 = tem;
else
return addr;
if (GET_CODE (op1) == PLUS)
op2 = XEXP (op1, 1), op1 = XEXP (op1, 0);
else if (GET_CODE (op0) == PLUS)
op2 = op1, op1 = XEXP (op0, 1), op0 = XEXP (op0, 0);
if (op2 != 0)
op1 = form_sum (op1, op2);
if (op1 != 0)
op0 = form_sum (op0, op1);
return op0;
}
return addr;
}
static int
find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
enum machine_mode mode;
rtx x;
int context;
rtx *loc;
int opnum;
enum reload_type type;
int ind_levels;
rtx insn;
{
register RTX_CODE code = GET_CODE (x);
switch (code)
{
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 (code0 == REG && REGNO (op0) < FIRST_PSEUDO_REGISTER)
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));
}
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, insn);
find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
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, insn);
find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum,
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, 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, insn);
else if (code0 == REG && code1 == REG)
{
if (REG_OK_FOR_INDEX_P (op0)
&& REG_MODE_OK_FOR_BASE_P (op1, mode))
return 0;
else if (REG_OK_FOR_INDEX_P (op1)
&& REG_MODE_OK_FOR_BASE_P (op0, mode))
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, 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, insn);
else if (REG_OK_FOR_INDEX_P (op1))
find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
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, insn);
else
{
find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
type, ind_levels, insn);
find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
type, ind_levels, insn);
}
}
else if (code0 == REG)
{
find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
type, ind_levels, insn);
find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
type, ind_levels, insn);
}
else if (code1 == REG)
{
find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum,
type, ind_levels, insn);
find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
type, ind_levels, insn);
}
}
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));
int value = 0;
rtx x_orig = x;
if (regno >= FIRST_PSEUDO_REGISTER
&& reg_equiv_constant[regno] != 0)
abort ();
if (reg_equiv_memory_loc[regno] != 0
&& (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
{
rtx tem = make_memloc (XEXP (x, 0), regno);
if (reg_equiv_address[regno]
|| ! rtx_equal_p (tem, reg_equiv_mem[regno]))
{
find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
&XEXP (tem, 0), opnum, type,
ind_levels, insn);
x = gen_rtx_fmt_e (GET_CODE (x), GET_MODE (x), tem);
}
}
if (reg_renumber[regno] >= 0)
regno = reg_renumber[regno];
if ((regno >= FIRST_PSEUDO_REGISTER
|| !(context ? REGNO_OK_FOR_INDEX_P (regno)
: REGNO_MODE_OK_FOR_BASE_P (regno, mode))))
{
#ifdef AUTO_INC_DEC
register rtx link;
#endif
int reloadnum;
rtx equiv = (GET_CODE (XEXP (x, 0)) == MEM
? XEXP (x, 0)
: reg_equiv_mem[regno]);
int icode = (int) add_optab->handlers[(int) Pmode].insn_code;
if (insn && GET_CODE (insn) == INSN && equiv
&& memory_operand (equiv, GET_MODE (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 ? INDEX_REG_CLASS : BASE_REG_CLASS),
GET_MODE (x), GET_MODE (x), 0, 0,
opnum, RELOAD_OTHER);
if (&XEXP (x_orig, 0) != loc)
push_replacement (&XEXP (x_orig, 0), reloadnum, VOIDmode);
}
else
{
reloadnum
= push_reload (x, NULL_RTX, loc, NULL_PTR,
(context ? INDEX_REG_CLASS : 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
for (link = REG_NOTES (this_insn);
link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_INC
&& REGNO (XEXP (link, 0)) == REGNO (XEXP (x_orig, 0)))
push_replacement (&XEXP (link, 0), reloadnum, VOIDmode);
#endif
}
return value;
}
else if (GET_CODE (XEXP (x, 0)) == MEM)
{
rtx tem ATTRIBUTE_UNUSED = XEXP (x, 0);
register rtx link;
int reloadnum;
find_reloads_address (GET_MODE (x), &XEXP (x, 0),
XEXP (XEXP (x, 0), 0), &XEXP (XEXP (x, 0), 0),
opnum, type, ind_levels, insn);
reloadnum = push_reload (x, NULL_RTX, loc, NULL_PTR,
(context ? INDEX_REG_CLASS : BASE_REG_CLASS),
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
reload_inc[reloadnum]
= find_inc_amount (PATTERN (this_insn), XEXP (x, 0));
link = FIND_REG_INC_NOTE (this_insn, tem);
if (link != 0)
push_replacement (&XEXP (link, 0), reloadnum, VOIDmode);
return 1;
}
return 0;
case MEM:
find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0),
opnum, ADDR_TYPE (type), ind_levels, insn);
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;
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
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_memory_loc[regno]
&& (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
{
rtx tem = make_memloc (x, regno);
if (reg_equiv_address[regno] != 0
|| ! rtx_equal_p (tem, reg_equiv_mem[regno]))
{
x = tem;
find_reloads_address (GET_MODE (x), &x, XEXP (x, 0),
&XEXP (x, 0), opnum, ADDR_TYPE (type),
ind_levels, insn);
}
}
if (reg_renumber[regno] >= 0)
regno = reg_renumber[regno];
if ((regno >= FIRST_PSEUDO_REGISTER
|| !(context ? REGNO_OK_FOR_INDEX_P (regno)
: REGNO_MODE_OK_FOR_BASE_P (regno, mode))))
{
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 (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 (GET_CODE (SUBREG_REG (x)) == REG)
{
if (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
{
int regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
if (! (context ? REGNO_OK_FOR_INDEX_P (regno)
: REGNO_MODE_OK_FOR_BASE_P (regno, mode)))
{
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
{
enum reg_class class = (context ? INDEX_REG_CLASS
: BASE_REG_CLASS);
if (CLASS_MAX_NREGS (class, GET_MODE (SUBREG_REG (x)))
> reg_class_size[class])
{
x = find_reloads_subreg_address (x, 0, opnum, type,
ind_levels, insn);
push_reload (x, NULL_RTX, loc, NULL_PTR, class,
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
return 1;
}
}
}
break;
default:
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 (mode, XEXP (x, i), context, &XEXP (x, i),
opnum, type, ind_levels, insn);
}
}
return 0;
}
static void
find_reloads_address_part (x, loc, class, mode, opnum, type, ind_levels)
rtx x;
rtx *loc;
enum reg_class class;
enum machine_mode mode;
int opnum;
enum reload_type type;
int ind_levels;
{
if (CONSTANT_P (x)
&& (! LEGITIMATE_CONSTANT_P (x)
|| PREFERRED_RELOAD_CLASS (x, class) == NO_REGS))
{
rtx tem;
if (GET_CODE (x) == CONST_INT)
tem = x = force_const_mem (mode, GEN_INT (INTVAL (x)));
else
tem = x = force_const_mem (mode, x);
find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
opnum, type, ind_levels, 0);
}
else if (GET_CODE (x) == PLUS
&& CONSTANT_P (XEXP (x, 1))
&& (! LEGITIMATE_CONSTANT_P (XEXP (x, 1))
|| PREFERRED_RELOAD_CLASS (XEXP (x, 1), class) == NO_REGS))
{
rtx tem;
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
tem = force_const_mem (GET_MODE (x), GEN_INT (INTVAL (XEXP (x, 1))));
else
tem = force_const_mem (GET_MODE (x), XEXP (x, 1));
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, 0);
}
push_reload (x, NULL_RTX, loc, NULL_PTR, class,
mode, VOIDmode, 0, 0, opnum, type);
}
static rtx
find_reloads_subreg_address (x, force_replace, opnum, type,
ind_levels, insn)
rtx x;
int force_replace;
int opnum;
enum reload_type type;
int ind_levels;
rtx insn;
{
int regno = REGNO (SUBREG_REG (x));
if (reg_equiv_memory_loc[regno])
{
if (! force_replace
&& (reg_equiv_address[regno]
|| ! offsettable_memref_p (reg_equiv_mem[regno])))
force_replace = 1;
if (force_replace || num_not_at_initial_offset)
{
rtx tem = make_memloc (SUBREG_REG (x), regno);
if (force_replace
|| ! rtx_equal_p (tem, reg_equiv_mem[regno]))
{
int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
if (BYTES_BIG_ENDIAN)
{
int size;
size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
offset += MIN (size, UNITS_PER_WORD);
size = GET_MODE_SIZE (GET_MODE (x));
offset -= MIN (size, UNITS_PER_WORD);
}
XEXP (tem, 0) = plus_constant (XEXP (tem, 0), offset);
PUT_MODE (tem, GET_MODE (x));
find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
&XEXP (tem, 0), opnum, ADDR_TYPE (type),
ind_levels, insn);
if (replace_reloads && recog_operand[opnum] != x)
emit_insn_before (gen_rtx_USE (VOIDmode, SUBREG_REG (x)), insn);
x = tem;
}
}
}
return x;
}
void
subst_reloads ()
{
register int i;
for (i = 0; i < n_replacements; i++)
{
register struct replacement *r = &replacements[i];
register rtx reloadreg = reload_reg_rtx[r->what];
if (reloadreg)
{
if (GET_MODE (reloadreg) != r->mode && r->mode != VOIDmode)
reloadreg = gen_rtx_REG (r->mode, REGNO (reloadreg));
if (r->subreg_loc != 0 && GET_CODE (reloadreg) == SUBREG)
{
if (GET_MODE (*r->subreg_loc)
== GET_MODE (SUBREG_REG (reloadreg)))
*r->subreg_loc = SUBREG_REG (reloadreg);
else
{
*r->where = SUBREG_REG (reloadreg);
SUBREG_WORD (*r->subreg_loc) += SUBREG_WORD (reloadreg);
}
}
else
*r->where = reloadreg;
}
else if (! reload_optional[r->what])
abort ();
}
}
void
copy_replacements (x, y)
rtx x;
rtx y;
{
int i, j;
enum rtx_code code = GET_CODE (x);
char *fmt = GET_RTX_FORMAT (code);
struct replacement *r;
if (code == SUBREG)
abort ();
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
for (j = 0; j < n_replacements; j++)
{
if (replacements[j].subreg_loc == &XEXP (x, i))
{
r = &replacements[n_replacements++];
r->where = replacements[j].where;
r->subreg_loc = &XEXP (y, i);
r->what = replacements[j].what;
r->mode = replacements[j].mode;
}
else if (replacements[j].where == &XEXP (x, i))
{
r = &replacements[n_replacements++];
r->where = &XEXP (y, i);
r->subreg_loc = 0;
r->what = replacements[j].what;
r->mode = replacements[j].mode;
}
}
}
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;
}
}
rtx
find_replacement (loc)
rtx *loc;
{
struct replacement *r;
for (r = &replacements[0]; r < &replacements[n_replacements]; r++)
{
rtx reloadreg = reload_reg_rtx[r->what];
if (reloadreg && r->where == loc)
{
if (r->mode != VOIDmode && GET_MODE (reloadreg) != r->mode)
reloadreg = gen_rtx_REG (r->mode, REGNO (reloadreg));
return reloadreg;
}
else if (reloadreg && r->subreg_loc == loc)
{
if (GET_CODE (reloadreg) == REG)
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));
}
}
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;
}
int
refers_to_regno_for_reload_p (regno, endregno, x, loc)
int regno, endregno;
rtx x;
rtx *loc;
{
register int i;
register RTX_CODE code;
register char *fmt;
if (x == 0)
return 0;
repeat:
code = GET_CODE (x);
switch (code)
{
case REG:
i = REGNO (x);
if (i >= FIRST_PSEUDO_REGISTER)
{
if (reg_equiv_memory_loc[i])
return refers_to_regno_for_reload_p (regno, endregno,
reg_equiv_memory_loc[i],
NULL_PTR);
if (reg_equiv_constant[i])
return 0;
#if defined(MACHO_PIC) && defined(I386) && !defined(FIXED_PIC_REG)
if (i == PIC_OFFSET_TABLE_REGNUM)
return 0;
#endif
abort ();
}
return (endregno > i
&& regno < i + (i < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (i, GET_MODE (x))
: 1));
case SUBREG:
if (GET_CODE (SUBREG_REG (x)) == REG
&& REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
{
int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
int inner_endregno
= inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
return endregno > inner_regno && regno < inner_endregno;
}
break;
case CLOBBER:
case SET:
if (&SET_DEST (x) != loc
&& ((GET_CODE (SET_DEST (x)) == SUBREG
&& loc != &SUBREG_REG (SET_DEST (x))
&& GET_CODE (SUBREG_REG (SET_DEST (x))) == REG
&& REGNO (SUBREG_REG (SET_DEST (x))) >= FIRST_PSEUDO_REGISTER
&& refers_to_regno_for_reload_p (regno, endregno,
SUBREG_REG (SET_DEST (x)),
loc))
|| ((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;
if (code == CLOBBER || loc == &SET_SRC (x))
return 0;
x = SET_SRC (x);
goto repeat;
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e' && loc != &XEXP (x, i))
{
if (i == 0)
{
x = XEXP (x, 0);
goto repeat;
}
else
if (refers_to_regno_for_reload_p (regno, endregno,
XEXP (x, i), loc))
return 1;
}
else if (fmt[i] == 'E')
{
register int j;
for (j = XVECLEN (x, i) - 1; j >=0; j--)
if (loc != &XVECEXP (x, i, j)
&& refers_to_regno_for_reload_p (regno, endregno,
XVECEXP (x, i, j), loc))
return 1;
}
}
return 0;
}
int
reg_overlap_mentioned_for_reload_p (x, in)
rtx x, in;
{
int regno, endregno;
if (GET_CODE (x) == STRICT_LOW_PART)
x = XEXP (x, 0);
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)
regno += SUBREG_WORD (x);
}
else if (GET_CODE (x) == REG)
{
regno = REGNO (x);
if (regno >= FIRST_PSEUDO_REGISTER)
{
if (reg_equiv_memory_loc[regno])
return refers_to_mem_for_reload_p (in);
else if (reg_equiv_constant[regno])
return 0;
#if defined(MACHO_PIC) && defined(I386) && !defined(FIXED_PIC_REG)
if (regno == PIC_OFFSET_TABLE_REGNUM)
return 0;
#endif
abort ();
}
}
else if (GET_CODE (x) == MEM)
return refers_to_mem_for_reload_p (in);
else if (GET_CODE (x) == SCRATCH || GET_CODE (x) == PC
|| GET_CODE (x) == CC0)
return reg_mentioned_p (x, in);
else
abort ();
endregno = regno + (regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
return refers_to_regno_for_reload_p (regno, endregno, in, NULL_PTR);
}
int
refers_to_mem_for_reload_p (x)
rtx x;
{
char *fmt;
int i;
if (GET_CODE (x) == MEM)
return 1;
if (GET_CODE (x) == REG)
return (REGNO (x) >= FIRST_PSEUDO_REGISTER
&& reg_equiv_memory_loc[REGNO (x)]);
fmt = GET_RTX_FORMAT (GET_CODE (x));
for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
if (fmt[i] == 'e'
&& (GET_CODE (XEXP (x, i)) == MEM
|| refers_to_mem_for_reload_p (XEXP (x, i))))
return 1;
return 0;
}
rtx
find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
register rtx goal;
rtx insn;
enum reg_class class;
register int other;
short *reload_reg_p;
int goalreg;
enum machine_mode mode;
{
register rtx p = insn;
rtx goaltry, valtry, value, where;
register rtx pat;
register int regno = -1;
int valueno;
int goal_mem = 0;
int goal_const = 0;
int goal_mem_addr_varies = 0;
int need_stable_sp = 0;
int nregs;
int valuenregs;
if (goal == 0)
regno = goalreg;
else if (GET_CODE (goal) == REG)
regno = REGNO (goal);
else if (GET_CODE (goal) == MEM)
{
enum rtx_code code = GET_CODE (XEXP (goal, 0));
if (MEM_VOLATILE_P (goal))
return 0;
if (flag_float_store && GET_MODE_CLASS (GET_MODE (goal)) == MODE_FLOAT)
return 0;
switch (code)
{
case POST_INC:
case PRE_INC:
case POST_DEC:
case PRE_DEC:
return 0;
default:
break;
}
goal_mem = 1;
}
else if (CONSTANT_P (goal))
goal_const = 1;
else if (GET_CODE (goal) == PLUS
&& 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;
#ifdef OVERLAPPING_REGNO_P
if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER
&& OVERLAPPING_REGNO_P (regno))
return 0;
#endif
while (1)
{
p = PREV_INSN (p);
if (p == 0 || GET_CODE (p) == CODE_LABEL)
return 0;
if (GET_CODE (p) == INSN
&& (! (reload_reg_p != 0
&& reload_reg_p != (short *) (HOST_WIDE_INT) 1)
|| INSN_UID (p) < reload_first_uid))
{
rtx tem;
pat = single_set (p);
if (pat != 0
&& ((regno >= 0
&& true_regnum (SET_SRC (pat)) == regno
&& (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0)
||
(regno >= 0
&& true_regnum (SET_DEST (pat)) == regno
&& (valueno = true_regnum (valtry = SET_SRC (pat))) >= 0)
||
(goal_const && rtx_equal_p (SET_SRC (pat), goal)
&& !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
&& rtx_renumbered_equal_p (goal, SET_SRC (pat)))
|| (goal_mem
&& (valueno = true_regnum (valtry = SET_SRC (pat))) >= 0
&& rtx_renumbered_equal_p (goal, SET_DEST (pat)))
|| (goal_const && (tem = find_reg_note (p, REG_EQUIV,
NULL_RTX))
&& rtx_equal_p (XEXP (tem, 0), goal)
&& (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0)
|| (goal_const && (tem = find_reg_note (p, REG_EQUIV,
NULL_RTX))
&& GET_CODE (SET_DEST (pat)) == REG
&& GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (XEXP (tem, 0))) == MODE_FLOAT
&& GET_CODE (goal) == CONST_INT
&& 0 != (goaltry = operand_subword (XEXP (tem, 0), 0, 0,
VOIDmode))
&& rtx_equal_p (goal, goaltry)
&& (valtry = operand_subword (SET_DEST (pat), 0, 0,
VOIDmode))
&& (valueno = true_regnum (valtry)) >= 0)
|| (goal_const && (tem = find_reg_note (p, REG_EQUIV,
NULL_RTX))
&& GET_CODE (SET_DEST (pat)) == REG
&& GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (XEXP (tem, 0))) == MODE_FLOAT
&& GET_CODE (goal) == CONST_INT
&& 0 != (goaltry = operand_subword (XEXP (tem, 0), 1, 0,
VOIDmode))
&& rtx_equal_p (goal, goaltry)
&& (valtry
= operand_subword (SET_DEST (pat), 1, 0, VOIDmode))
&& (valueno = true_regnum (valtry)) >= 0)))
if (other >= 0
? valueno == other
: ((unsigned) valueno < FIRST_PSEUDO_REGISTER
&& TEST_HARD_REG_BIT (reg_class_contents[(int) class],
valueno)))
{
value = valtry;
where = p;
break;
}
}
}
if (find_reg_note (where, REG_UNUSED, value))
return 0;
if (valueno == STACK_POINTER_REGNUM || regno == STACK_POINTER_REGNUM
|| (goal_mem && reg_overlap_mentioned_for_reload_p (stack_pointer_rtx,
goal)))
need_stable_sp = 1;
if (GET_MODE (value) != mode)
return 0;
if (goal_mem && value == SET_DEST (single_set (where))
&& refers_to_regno_for_reload_p (valueno,
(valueno
+ HARD_REGNO_NREGS (valueno, mode)),
goal, NULL_PTR))
return 0;
if (!goal_mem && !goal_const
&& regno + HARD_REGNO_NREGS (regno, mode) > valueno
&& regno < valueno + HARD_REGNO_NREGS (valueno, mode))
return 0;
if (reload_reg_p != 0 && reload_reg_p != (short *) (HOST_WIDE_INT) 1
&& reload_reg_p[valueno] >= 0)
return 0;
#ifdef OVERLAPPING_REGNO_P
if (OVERLAPPING_REGNO_P (valueno))
return 0;
#endif
nregs = HARD_REGNO_NREGS (regno, mode);
valuenregs = HARD_REGNO_NREGS (valueno, mode);
if (reload_reg_p != 0)
{
int i;
for (i = 0; i < n_reloads; i++)
if (reload_reg_rtx[i] != 0 && reload_in[i])
{
int regno1 = REGNO (reload_reg_rtx[i]);
int nregs1 = HARD_REGNO_NREGS (regno1,
GET_MODE (reload_reg_rtx[i]));
if (regno1 < valueno + valuenregs
&& regno1 + nregs1 > valueno)
return 0;
}
}
if (goal_mem)
goal_mem_addr_varies = !CONSTANT_ADDRESS_P (XEXP (goal, 0));
p = insn;
while (1)
{
p = PREV_INSN (p);
if (p == where)
return value;
if (GET_CODE (p) == CALL_INSN
&& ((regno >= 0 && regno < FIRST_PSEUDO_REGISTER
&& call_used_regs[regno])
||
(valueno >= 0 && valueno < FIRST_PSEUDO_REGISTER
&& call_used_regs[valueno])
||
goal_mem
|| need_stable_sp))
return 0;
#ifdef NON_SAVING_SETJMP
if (NON_SAVING_SETJMP && GET_CODE (p) == NOTE
&& NOTE_LINE_NUMBER (p) == NOTE_INSN_SETJMP)
return 0;
#endif
#ifdef INSN_CLOBBERS_REGNO_P
if ((valueno >= 0 && valueno < FIRST_PSEUDO_REGISTER
&& INSN_CLOBBERS_REGNO_P (p, valueno))
|| (regno >= 0 && regno < FIRST_PSEUDO_REGISTER
&& INSN_CLOBBERS_REGNO_P (p, regno)))
return 0;
#endif
if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
{
pat = PATTERN (p);
if (volatile_insn_p (pat))
return 0;
if (GET_CODE (pat) == SET || GET_CODE (pat) == CLOBBER)
{
register rtx dest = SET_DEST (pat);
while (GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == ZERO_EXTRACT
|| GET_CODE (dest) == SIGN_EXTRACT
|| GET_CODE (dest) == STRICT_LOW_PART)
dest = XEXP (dest, 0);
if (GET_CODE (dest) == REG)
{
register int xregno = REGNO (dest);
int xnregs;
if (REGNO (dest) < FIRST_PSEUDO_REGISTER)
xnregs = HARD_REGNO_NREGS (xregno, GET_MODE (dest));
else
xnregs = 1;
if (xregno < regno + nregs && xregno + xnregs > regno)
return 0;
if (xregno < valueno + valuenregs
&& xregno + xnregs > valueno)
return 0;
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)))
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;
}
else if (GET_CODE (pat) == PARALLEL)
{
register int i;
for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)
{
register rtx v1 = XVECEXP (pat, 0, i);
if (GET_CODE (v1) == SET || GET_CODE (v1) == CLOBBER)
{
register rtx dest = SET_DEST (v1);
while (GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == ZERO_EXTRACT
|| GET_CODE (dest) == SIGN_EXTRACT
|| GET_CODE (dest) == STRICT_LOW_PART)
dest = XEXP (dest, 0);
if (GET_CODE (dest) == REG)
{
register int xregno = REGNO (dest);
int xnregs;
if (REGNO (dest) < FIRST_PSEUDO_REGISTER)
xnregs = HARD_REGNO_NREGS (xregno, GET_MODE (dest));
else
xnregs = 1;
if (xregno < regno + nregs
&& xregno + xnregs > regno)
return 0;
if (xregno < valueno + valuenregs
&& xregno + xnregs > valueno)
return 0;
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)))
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;
}
}
}
if (GET_CODE (p) == CALL_INSN && CALL_INSN_FUNCTION_USAGE (p))
{
rtx link;
for (link = CALL_INSN_FUNCTION_USAGE (p); XEXP (link, 1) != 0;
link = XEXP (link, 1))
{
pat = XEXP (link, 0);
if (GET_CODE (pat) == CLOBBER)
{
register rtx dest = SET_DEST (pat);
while (GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == ZERO_EXTRACT
|| GET_CODE (dest) == SIGN_EXTRACT
|| GET_CODE (dest) == STRICT_LOW_PART)
dest = XEXP (dest, 0);
if (GET_CODE (dest) == REG)
{
register int xregno = REGNO (dest);
int xnregs;
if (REGNO (dest) < FIRST_PSEUDO_REGISTER)
xnregs = HARD_REGNO_NREGS (xregno, GET_MODE (dest));
else
xnregs = 1;
if (xregno < regno + nregs
&& xregno + xnregs > regno)
return 0;
if (xregno < valueno + valuenregs
&& xregno + xnregs > valueno)
return 0;
if (goal_mem_addr_varies
&& reg_overlap_mentioned_for_reload_p (dest,
goal))
return 0;
}
else if (goal_mem && GET_CODE (dest) == MEM
&& ! push_operand (dest, GET_MODE (dest)))
return 0;
else if (need_stable_sp
&& push_operand (dest, GET_MODE (dest)))
return 0;
}
}
}
#ifdef AUTO_INC_DEC
{
register rtx link;
for (link = REG_NOTES (p); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_INC
&& GET_CODE (XEXP (link, 0)) == REG)
{
register int incno = REGNO (XEXP (link, 0));
if (incno < regno + nregs && incno >= regno)
return 0;
if (incno < valueno + valuenregs && incno >= valueno)
return 0;
if (goal_mem_addr_varies
&& reg_overlap_mentioned_for_reload_p (XEXP (link, 0),
goal))
return 0;
}
}
#endif
}
}
}
static int
find_inc_amount (x, inced)
rtx x, inced;
{
register enum rtx_code code = GET_CODE (x);
register char *fmt;
register int i;
if (code == MEM)
{
register rtx addr = XEXP (x, 0);
if ((GET_CODE (addr) == PRE_DEC
|| GET_CODE (addr) == POST_DEC
|| GET_CODE (addr) == PRE_INC
|| GET_CODE (addr) == POST_INC)
&& XEXP (addr, 0) == inced)
return GET_MODE_SIZE (GET_MODE (x));
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
register int tem = find_inc_amount (XEXP (x, i), inced);
if (tem != 0)
return tem;
}
if (fmt[i] == 'E')
{
register int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
{
register int tem = find_inc_amount (XVECEXP (x, i, j), inced);
if (tem != 0)
return tem;
}
}
}
return 0;
}
int
regno_clobbered_p (regno, insn)
int regno;
rtx insn;
{
if (GET_CODE (PATTERN (insn)) == CLOBBER
&& GET_CODE (XEXP (PATTERN (insn), 0)) == REG)
return REGNO (XEXP (PATTERN (insn), 0)) == regno;
if (GET_CODE (PATTERN (insn)) == PARALLEL)
{
int i = XVECLEN (PATTERN (insn), 0) - 1;
for (; i >= 0; i--)
{
rtx elt = XVECEXP (PATTERN (insn), 0, i);
if (GET_CODE (elt) == CLOBBER && GET_CODE (XEXP (elt, 0)) == REG
&& REGNO (XEXP (elt, 0)) == regno)
return 1;
}
}
return 0;
}
static char *reload_when_needed_name[] =
{
"RELOAD_FOR_INPUT",
"RELOAD_FOR_OUTPUT",
"RELOAD_FOR_INSN",
"RELOAD_FOR_INPUT_ADDRESS",
"RELOAD_FOR_INPADDR_ADDRESS",
"RELOAD_FOR_OUTPUT_ADDRESS",
"RELOAD_FOR_OUTADDR_ADDRESS",
"RELOAD_FOR_OPERAND_ADDRESS",
"RELOAD_FOR_OPADDR_ADDR",
"RELOAD_OTHER",
"RELOAD_FOR_OTHER_ADDRESS"
};
static char *reg_class_names[] = REG_CLASS_NAMES;
void
debug_reload_to_stream (f)
FILE *f;
{
int r;
char *prefix;
if (! f)
f = stderr;
for (r = 0; r < n_reloads; r++)
{
fprintf (f, "Reload %d: ", r);
if (reload_in[r] != 0)
{
fprintf (f, "reload_in (%s) = ",
GET_MODE_NAME (reload_inmode[r]));
print_inline_rtx (f, reload_in[r], 24);
fprintf (f, "\n\t");
}
if (reload_out[r] != 0)
{
fprintf (f, "reload_out (%s) = ",
GET_MODE_NAME (reload_outmode[r]));
print_inline_rtx (f, reload_out[r], 24);
fprintf (f, "\n\t");
}
fprintf (f, "%s, ", reg_class_names[(int) reload_reg_class[r]]);
fprintf (f, "%s (opnum = %d)",
reload_when_needed_name[(int) reload_when_needed[r]],
reload_opnum[r]);
if (reload_optional[r])
fprintf (f, ", optional");
if (reload_nongroup[r])
fprintf (stderr, ", nongroup");
if (reload_inc[r] != 0)
fprintf (f, ", inc by %d", reload_inc[r]);
if (reload_nocombine[r])
fprintf (f, ", can't combine");
if (reload_secondary_p[r])
fprintf (f, ", secondary_reload_p");
if (reload_in_reg[r] != 0)
{
fprintf (f, "\n\treload_in_reg: ");
print_inline_rtx (f, reload_in_reg[r], 24);
}
if (reload_out_reg[r] != 0)
{
fprintf (f, "\n\treload_out_reg: ");
print_inline_rtx (f, reload_out_reg[r], 24);
}
if (reload_reg_rtx[r] != 0)
{
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 (f, "%ssecondary_in_reload = %d",
prefix, reload_secondary_in_reload[r]);
prefix = ", ";
}
if (reload_secondary_out_reload[r] != -1)
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, "%ssecondary_in_icode = %s", prefix,
insn_name[reload_secondary_in_icode[r]]);
prefix = ", ";
}
if (reload_secondary_out_icode[r] != CODE_FOR_nothing)
fprintf (stderr, "%ssecondary_out_icode = %s", prefix,
insn_name[reload_secondary_out_icode[r]]);
fprintf (f, "\n");
}
}
void
debug_reload ()
{
debug_reload_to_stream (stderr);
}