/* Search an insn for pseudo regs that must be in hard regs and are not.
- Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "rtl-error.h"
#include "tm_p.h"
#include "insn-config.h"
+#include "symtab.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "rtl.h"
+#include "flags.h"
+#include "alias.h"
+#include "tree.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
#include "expr.h"
+#include "insn-codes.h"
#include "optabs.h"
#include "recog.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "predict.h"
+#include "basic-block.h"
#include "df.h"
#include "reload.h"
#include "regs.h"
#include "addresses.h"
-#include "hard-reg-set.h"
-#include "flags.h"
-#include "output.h"
-#include "function.h"
#include "params.h"
#include "target.h"
#include "ira.h"
{
rtx *where; /* Location to store in */
int what; /* which reload this is for */
- enum machine_mode mode; /* mode it must have */
+ machine_mode mode; /* mode it must have */
};
static struct replacement replacements[MAX_RECOG_OPERANDS * ((MAX_REGS_PER_ADDRESS * 2) + 1)];
/* The instruction we are doing reloads for;
so we can test whether a register dies in it. */
-static rtx this_insn;
+static rtx_insn *this_insn;
/* Nonzero if this instruction is a user-specified asm with operands. */
static int this_insn_is_asm;
: (type)))
static int push_secondary_reload (int, rtx, int, int, enum reg_class,
- enum machine_mode, enum reload_type,
+ machine_mode, enum reload_type,
enum insn_code *, secondary_reload_info *);
-static enum reg_class find_valid_class (enum machine_mode, enum machine_mode,
+static enum reg_class find_valid_class (machine_mode, machine_mode,
int, unsigned int);
-static void push_replacement (rtx *, int, enum machine_mode);
+static void push_replacement (rtx *, int, machine_mode);
static void dup_replacements (rtx *, rtx *);
static void combine_reloads (void);
static int find_reusable_reload (rtx *, rtx, enum reg_class,
enum reload_type, int, int);
-static rtx find_dummy_reload (rtx, rtx, rtx *, rtx *, enum machine_mode,
- enum machine_mode, reg_class_t, int, int);
+static rtx find_dummy_reload (rtx, rtx, rtx *, rtx *, machine_mode,
+ machine_mode, reg_class_t, int, int);
static int hard_reg_set_here_p (unsigned int, unsigned int, rtx);
static struct decomposition decompose (rtx);
static int immune_p (rtx, rtx, struct decomposition);
static bool alternative_allows_const_pool_ref (rtx, const char *, int);
-static rtx find_reloads_toplev (rtx, int, enum reload_type, int, int, rtx,
- int *);
+static rtx find_reloads_toplev (rtx, int, enum reload_type, int, int,
+ rtx_insn *, int *);
static rtx make_memloc (rtx, int);
-static int maybe_memory_address_addr_space_p (enum machine_mode, rtx,
+static int maybe_memory_address_addr_space_p (machine_mode, rtx,
addr_space_t, rtx *);
-static int find_reloads_address (enum machine_mode, rtx *, rtx, rtx *,
- int, enum reload_type, int, rtx);
-static rtx subst_reg_equivs (rtx, rtx);
+static int find_reloads_address (machine_mode, rtx *, rtx, rtx *,
+ int, enum reload_type, int, rtx_insn *);
+static rtx subst_reg_equivs (rtx, rtx_insn *);
static rtx subst_indexed_address (rtx);
-static void update_auto_inc_notes (rtx, int, int);
-static int find_reloads_address_1 (enum machine_mode, addr_space_t, rtx, int,
+static void update_auto_inc_notes (rtx_insn *, int, int);
+static int find_reloads_address_1 (machine_mode, addr_space_t, rtx, int,
enum rtx_code, enum rtx_code, rtx *,
- int, enum reload_type,int, rtx);
+ int, enum reload_type,int, rtx_insn *);
static void find_reloads_address_part (rtx, rtx *, enum reg_class,
- enum machine_mode, int,
+ machine_mode, int,
enum reload_type, int);
-static rtx find_reloads_subreg_address (rtx, int, int, enum reload_type,
- int, rtx, int *);
+static rtx find_reloads_subreg_address (rtx, int, enum reload_type,
+ int, rtx_insn *, int *);
static void copy_replacements_1 (rtx *, rtx *, int);
static int find_inc_amount (rtx, rtx);
static int refers_to_mem_for_reload_p (rtx);
static int
push_secondary_reload (int in_p, rtx x, int opnum, int optional,
enum reg_class reload_class,
- enum machine_mode reload_mode, enum reload_type type,
+ machine_mode reload_mode, enum reload_type type,
enum insn_code *picode, secondary_reload_info *prev_sri)
{
enum reg_class rclass = NO_REGS;
enum reg_class scratch_class;
- enum machine_mode mode = reload_mode;
+ machine_mode mode = reload_mode;
enum insn_code icode = CODE_FOR_nothing;
enum insn_code t_icode = CODE_FOR_nothing;
enum reload_type secondary_type;
int s_reload, t_reload = -1;
const char *scratch_constraint;
- char letter;
secondary_reload_info sri;
if (type == RELOAD_FOR_INPUT_ADDRESS
scratch_constraint++;
if (*scratch_constraint == '&')
scratch_constraint++;
- letter = *scratch_constraint;
- scratch_class = (letter == 'r' ? GENERAL_REGS
- : REG_CLASS_FROM_CONSTRAINT ((unsigned char) letter,
- scratch_constraint));
+ scratch_class = (reg_class_for_constraint
+ (lookup_constraint (scratch_constraint)));
rclass = scratch_class;
mode = insn_data[(int) icode].operand[2].mode;
register and a scratch register is needed, we return the class of the
intermediate register. */
reg_class_t
-secondary_reload_class (bool in_p, reg_class_t rclass, enum machine_mode mode,
+secondary_reload_class (bool in_p, reg_class_t rclass, machine_mode mode,
rtx x)
{
enum insn_code icode;
scratch_reload_class (enum insn_code icode)
{
const char *scratch_constraint;
- char scratch_letter;
enum reg_class rclass;
gcc_assert (insn_data[(int) icode].n_operands == 3);
scratch_constraint++;
if (*scratch_constraint == '&')
scratch_constraint++;
- scratch_letter = *scratch_constraint;
- if (scratch_letter == 'r')
- return GENERAL_REGS;
- rclass = REG_CLASS_FROM_CONSTRAINT ((unsigned char) scratch_letter,
- scratch_constraint);
+ rclass = reg_class_for_constraint (lookup_constraint (scratch_constraint));
gcc_assert (rclass != NO_REGS);
return rclass;
}
call find_reloads_address on the location being returned. */
rtx
-get_secondary_mem (rtx x ATTRIBUTE_UNUSED, enum machine_mode mode,
+get_secondary_mem (rtx x ATTRIBUTE_UNUSED, machine_mode mode,
int opnum, enum reload_type type)
{
rtx loc;
into REGNO. Such a class must exist. */
static enum reg_class
-find_valid_class (enum machine_mode outer ATTRIBUTE_UNUSED,
- enum machine_mode inner ATTRIBUTE_UNUSED, int n,
+find_valid_class (machine_mode outer ATTRIBUTE_UNUSED,
+ machine_mode inner ATTRIBUTE_UNUSED, int n,
unsigned int dest_regno ATTRIBUTE_UNUSED)
{
int best_cost = -1;
if (HARD_REGNO_MODE_OK (regno, inner))
{
good = 1;
- if (! TEST_HARD_REG_BIT (reg_class_contents[rclass], regno + n)
- || ! HARD_REGNO_MODE_OK (regno + n, outer))
+ if (TEST_HARD_REG_BIT (reg_class_contents[rclass], regno + n)
+ && ! HARD_REGNO_MODE_OK (regno + n, outer))
bad = 1;
}
}
return best_class;
}
+
+/* We are trying to reload a subreg of something that is not a register.
+ Find the largest class which contains only registers valid in
+ mode MODE. OUTER is the mode of the subreg, DEST_CLASS the class in
+ which we would eventually like to obtain the object. */
+
+static enum reg_class
+find_valid_class_1 (machine_mode outer ATTRIBUTE_UNUSED,
+ machine_mode mode ATTRIBUTE_UNUSED,
+ enum reg_class dest_class ATTRIBUTE_UNUSED)
+{
+ int best_cost = -1;
+ int rclass;
+ int regno;
+ enum reg_class best_class = NO_REGS;
+ unsigned int best_size = 0;
+ int cost;
+
+ for (rclass = 1; rclass < N_REG_CLASSES; rclass++)
+ {
+ int bad = 0;
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER && !bad; regno++)
+ {
+ if (in_hard_reg_set_p (reg_class_contents[rclass], mode, regno)
+ && !HARD_REGNO_MODE_OK (regno, mode))
+ bad = 1;
+ }
+
+ if (bad)
+ continue;
+
+ cost = register_move_cost (outer, (enum reg_class) rclass, dest_class);
+
+ if ((reg_class_size[rclass] > best_size
+ && (best_cost < 0 || best_cost >= cost))
+ || best_cost > cost)
+ {
+ best_class = (enum reg_class) rclass;
+ best_size = reg_class_size[rclass];
+ best_cost = register_move_cost (outer, (enum reg_class) rclass,
+ dest_class);
+ }
+ }
+
+ gcc_assert (best_size != 0);
+
+#ifdef LIMIT_RELOAD_CLASS
+ best_class = LIMIT_RELOAD_CLASS (mode, best_class);
+#endif
+ return best_class;
+}
\f
/* Return the number of a previously made reload that can be combined with
a new one, or n_reloads if none of the existing reloads can be used.
the function is invoked for the output part of an enclosing reload. */
static bool
-reload_inner_reg_of_subreg (rtx x, enum machine_mode mode, bool output)
+reload_inner_reg_of_subreg (rtx x, machine_mode mode, bool output)
{
rtx inner;
patterns by register elimination and substituting pseudos without a home
by their function-invariant equivalences. */
static int
-can_reload_into (rtx in, int regno, enum machine_mode mode)
+can_reload_into (rtx in, int regno, machine_mode mode)
{
- rtx dst, test_insn;
+ rtx dst;
+ rtx_insn *test_insn;
int r = 0;
- struct recog_data save_recog_data;
+ struct recog_data_d save_recog_data;
/* For matching constraints, we often get notional input reloads where
we want to use the original register as the reload register. I.e.
/* If we can make a simple SET insn that does the job, everything should
be fine. */
dst = gen_rtx_REG (mode, regno);
- test_insn = make_insn_raw (gen_rtx_SET (VOIDmode, dst, in));
+ test_insn = make_insn_raw (gen_rtx_SET (dst, in));
save_recog_data = recog_data;
if (recog_memoized (test_insn) >= 0)
{
extract_insn (test_insn);
- r = constrain_operands (1);
+ r = constrain_operands (1, get_enabled_alternatives (test_insn));
}
recog_data = save_recog_data;
return r;
int
push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
- enum reg_class rclass, enum machine_mode inmode,
- enum machine_mode outmode, int strict_low, int optional,
+ enum reg_class rclass, machine_mode inmode,
+ machine_mode outmode, int strict_low, int optional,
int opnum, enum reload_type type)
{
int i;
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;
+ enum reg_class subreg_in_class ATTRIBUTE_UNUSED;
+ subreg_in_class = NO_REGS;
/* INMODE and/or OUTMODE could be VOIDmode if no mode
has been specified for the operand. In that case,
if (in != 0 && reload_inner_reg_of_subreg (in, inmode, false))
{
- enum reg_class in_class = rclass;
-
if (REG_P (SUBREG_REG (in)))
- in_class
+ subreg_in_class
= find_valid_class (inmode, GET_MODE (SUBREG_REG (in)),
subreg_regno_offset (REGNO (SUBREG_REG (in)),
GET_MODE (SUBREG_REG (in)),
SUBREG_BYTE (in),
GET_MODE (in)),
REGNO (SUBREG_REG (in)));
+ else if (GET_CODE (SUBREG_REG (in)) == SYMBOL_REF)
+ subreg_in_class = find_valid_class_1 (inmode,
+ GET_MODE (SUBREG_REG (in)),
+ rclass);
/* This relies on the fact that emit_reload_insns outputs the
instructions for input reloads of type RELOAD_OTHER in the same
RELOAD_OTHER, we are guaranteed that this inner reload will be
output before the outer reload. */
push_reload (SUBREG_REG (in), NULL_RTX, &SUBREG_REG (in), (rtx *) 0,
- in_class, VOIDmode, VOIDmode, 0, 0, opnum, type);
+ subreg_in_class, VOIDmode, VOIDmode, 0, 0, opnum, type);
dont_remove_subreg = 1;
}
is specified. */
if (this_insn_is_asm)
{
- enum machine_mode mode;
+ machine_mode mode;
if (GET_MODE_SIZE (inmode) > GET_MODE_SIZE (outmode))
mode = inmode;
else
So add an additional reload. */
#ifdef SECONDARY_MEMORY_NEEDED
- /* If a memory location is needed for the copy, make one. */
- if (in != 0
+ if (subreg_in_class == NO_REGS
+ && in != 0
&& (REG_P (in)
|| (GET_CODE (in) == SUBREG && REG_P (SUBREG_REG (in))))
- && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER
- && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (reg_or_subregno (in)),
- rclass, inmode))
+ && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER)
+ subreg_in_class = REGNO_REG_CLASS (reg_or_subregno (in));
+ /* If a memory location is needed for the copy, make one. */
+ if (subreg_in_class != NO_REGS
+ && SECONDARY_MEMORY_NEEDED (subreg_in_class, rclass, inmode))
get_secondary_mem (in, inmode, opnum, type);
#endif
{
rtx note;
int regno;
- enum machine_mode rel_mode = inmode;
+ machine_mode rel_mode = inmode;
if (out && GET_MODE_SIZE (outmode) > GET_MODE_SIZE (inmode))
rel_mode = outmode;
&& reg_mentioned_p (XEXP (note, 0), in)
/* Check that a former pseudo is valid; see find_dummy_reload. */
&& (ORIGINAL_REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
- || (! bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR),
+ || (! bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
ORIGINAL_REGNO (XEXP (note, 0)))
&& hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] == 1))
&& ! refers_to_regno_for_reload_p (regno,
end_hard_regno (rel_mode,
regno),
PATTERN (this_insn), inloc)
+ && ! find_reg_fusage (this_insn, USE, XEXP (note, 0))
/* If this is also an output reload, IN cannot be used as
the reload register if it is set in this insn unless IN
is also OUT. */
This is used in insn patterns that use match_dup. */
static void
-push_replacement (rtx *loc, int reloadnum, enum machine_mode mode)
+push_replacement (rtx *loc, int reloadnum, machine_mode mode)
{
if (replace_reloads)
{
&& !fixed_regs[regno]
/* Check that a former pseudo is valid; see find_dummy_reload. */
&& (ORIGINAL_REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
- || (!bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR),
+ || (!bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
ORIGINAL_REGNO (XEXP (note, 0)))
&& hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] == 1)))
{
static rtx
find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc,
- enum machine_mode inmode, enum machine_mode outmode,
+ machine_mode inmode, machine_mode outmode,
reg_class_t rclass, int for_real, int earlyclobber)
{
rtx in = real_in;
However, we only ignore IN in its role as this reload.
If the insn uses IN elsewhere and it contains OUT,
that counts. We can't be sure it's the "same" operand
- so it might not go through this reload. */
+ so it might not go through this reload.
+
+ We also need to avoid using OUT if it, or part of it, is a
+ fixed register. Modifying such registers, even transiently,
+ may have undefined effects on the machine, such as modifying
+ the stack pointer. */
saved_rtx = *inloc;
*inloc = const0_rtx;
for (i = 0; i < nwords; i++)
if (! TEST_HARD_REG_BIT (reg_class_contents[(int) rclass],
- regno + i))
+ regno + i)
+ || fixed_regs[regno + i])
break;
if (i == nwords)
can ignore the conflict). We must never introduce writes
to such hardregs, as they would clobber the other live
pseudo. See PR 20973. */
- || (!bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR),
+ || (!bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
ORIGINAL_REGNO (in))
/* Similarly, only do this if we can be sure that the death
note is still valid. global can assign some hardreg to
proper kind of hard reg. */
int
-strict_memory_address_addr_space_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+strict_memory_address_addr_space_p (machine_mode mode ATTRIBUTE_UNUSED,
rtx addr, addr_space_t as)
{
#ifdef GO_IF_LEGITIMATE_ADDRESS
switch (code)
{
- case CONST_INT:
- case CONST_DOUBLE:
- case CONST_FIXED:
+ CASE_CONST_UNIQUE:
return 0;
case LABEL_REF:
- return XEXP (x, 0) == XEXP (y, 0);
+ return LABEL_REF_LABEL (x) == LABEL_REF_LABEL (y);
case SYMBOL_REF:
return XSTR (x, 0) == XSTR (y, 0);
commutative operands, reg_equiv_address substitution, or whatever. */
int
-find_reloads (rtx insn, int replace, int ind_levels, int live_known,
+find_reloads (rtx_insn *insn, int replace, int ind_levels, int live_known,
short *reload_reg_p)
{
int insn_code_number;
rtx body = PATTERN (insn);
rtx set = single_set (insn);
int goal_earlyclobber = 0, this_earlyclobber;
- enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
+ machine_mode operand_mode[MAX_RECOG_OPERANDS];
int retval = 0;
this_insn = insn;
if (JUMP_P (insn) || CALL_P (insn))
no_output_reloads = 1;
-#ifdef HAVE_cc0
- if (reg_referenced_p (cc0_rtx, PATTERN (insn)))
+ if (HAVE_cc0 && reg_referenced_p (cc0_rtx, PATTERN (insn)))
no_input_reloads = 1;
- if (reg_set_p (cc0_rtx, PATTERN (insn)))
+ if (HAVE_cc0 && reg_set_p (cc0_rtx, PATTERN (insn)))
no_output_reloads = 1;
-#endif
#ifdef SECONDARY_MEMORY_NEEDED
/* The eliminated forms of any secondary memory locations are per-insn, so
this_insn_is_asm = insn_code_number < 0;
memcpy (operand_mode, recog_data.operand_mode,
- noperands * sizeof (enum machine_mode));
+ noperands * sizeof (machine_mode));
memcpy (constraints, recog_data.constraints,
noperands * sizeof (const char *));
if (*constraints[i] == 0)
/* Ignore things like match_operator operands. */
;
- else if (constraints[i][0] == 'p'
- || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i]))
+ else if (insn_extra_address_constraint
+ (lookup_constraint (constraints[i])))
{
address_operand_reloaded[i]
= find_reloads_address (recog_data.operand_mode[i], (rtx*) 0,
First loop over alternatives. */
+ alternative_mask enabled = get_enabled_alternatives (insn);
for (this_alternative_number = 0;
this_alternative_number < n_alternatives;
this_alternative_number++)
{
int swapped;
- if (!recog_data.alternative_enabled_p[this_alternative_number])
+ if (!TEST_BIT (enabled, this_alternative_number))
{
int i;
if (swapped)
{
- enum reg_class tclass;
- int t;
-
recog_data.operand[commutative] = substed_operand[commutative + 1];
recog_data.operand[commutative + 1] = substed_operand[commutative];
/* Swap the duplicates too. */
*recog_data.dup_loc[i]
= recog_data.operand[(int) recog_data.dup_num[i]];
- 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;
-
- t = address_reloaded[commutative];
- address_reloaded[commutative] = address_reloaded[commutative + 1];
- address_reloaded[commutative + 1] = t;
+ std::swap (preferred_class[commutative],
+ preferred_class[commutative + 1]);
+ std::swap (pref_or_nothing[commutative],
+ pref_or_nothing[commutative + 1]);
+ std::swap (address_reloaded[commutative],
+ address_reloaded[commutative + 1]);
}
this_earlyclobber = 0;
operand. */
int constmemok = 0;
int earlyclobber = 0;
+ enum constraint_num cn;
+ enum reg_class cl;
/* If the predicate accepts a unary operator, it means that
we need to reload the operand, but do not do this for
c = '\0';
break;
- case '=': case '+': case '*':
- break;
-
- case '%':
- /* We only support one commutative marker, the first
- one. We already set commutative above. */
- break;
-
case '?':
reject += 6;
break;
for (j = 0; j < i; j++)
if (this_alternative_matches[j]
== this_alternative_matches[i])
- badop = 1;
+ {
+ badop = 1;
+ break;
+ }
break;
case 'p':
earlyclobber = 1, this_earlyclobber = 1;
break;
- case 'E':
- case 'F':
- if (GET_CODE (operand) == CONST_DOUBLE
- || (GET_CODE (operand) == CONST_VECTOR
- && (GET_MODE_CLASS (GET_MODE (operand))
- == MODE_VECTOR_FLOAT)))
- win = 1;
- break;
-
- case 'G':
- case 'H':
- if (GET_CODE (operand) == CONST_DOUBLE
- && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (operand, c, p))
- win = 1;
- break;
-
- case 's':
- if (CONST_INT_P (operand)
- || (GET_CODE (operand) == CONST_DOUBLE
- && GET_MODE (operand) == VOIDmode))
- break;
- case 'i':
- if (CONSTANT_P (operand)
- && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (operand)))
- win = 1;
- break;
-
- case 'n':
- if (CONST_INT_P (operand)
- || (GET_CODE (operand) == CONST_DOUBLE
- && GET_MODE (operand) == VOIDmode))
- win = 1;
- break;
-
- case 'I':
- case 'J':
- case 'K':
- case 'L':
- case 'M':
- case 'N':
- case 'O':
- case 'P':
- if (CONST_INT_P (operand)
- && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operand), c, p))
- win = 1;
- break;
-
case 'X':
force_reload = 0;
win = 1;
|| (REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (operand)] < 0)))
win = 1;
- /* Drop through into 'r' case. */
-
- case 'r':
- this_alternative[i]
- = reg_class_subunion[this_alternative[i]][(int) GENERAL_REGS];
+ cl = GENERAL_REGS;
goto reg;
default:
- if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS)
+ cn = lookup_constraint (p);
+ switch (get_constraint_type (cn))
{
-#ifdef EXTRA_CONSTRAINT_STR
- if (EXTRA_MEMORY_CONSTRAINT (c, p))
- {
- if (force_reload)
- break;
- if (EXTRA_CONSTRAINT_STR (operand, c, p))
- win = 1;
- /* If the address was already reloaded,
- we win as well. */
- else if (MEM_P (operand)
- && address_reloaded[i] == 1)
- win = 1;
- /* Likewise if the address will be reloaded because
- reg_equiv_address is nonzero. For reg_equiv_mem
- we have to check. */
- else if (REG_P (operand)
- && REGNO (operand) >= FIRST_PSEUDO_REGISTER
- && reg_renumber[REGNO (operand)] < 0
- && ((reg_equiv_mem (REGNO (operand)) != 0
- && EXTRA_CONSTRAINT_STR (reg_equiv_mem (REGNO (operand)), c, p))
- || (reg_equiv_address (REGNO (operand)) != 0)))
- win = 1;
-
- /* If we didn't already win, we can reload
- constants via force_const_mem, and other
- MEMs by reloading the address like for 'o'. */
- if (CONST_POOL_OK_P (operand_mode[i], operand)
- || MEM_P (operand))
- badop = 0;
- constmemok = 1;
- offmemok = 1;
- break;
- }
- if (EXTRA_ADDRESS_CONSTRAINT (c, p))
- {
- if (EXTRA_CONSTRAINT_STR (operand, c, p))
- win = 1;
-
- /* If we didn't already win, we can reload
- the address into a base register. */
- this_alternative[i]
- = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
- ADDRESS, SCRATCH);
- badop = 0;
- break;
- }
+ case CT_REGISTER:
+ cl = reg_class_for_constraint (cn);
+ if (cl != NO_REGS)
+ goto reg;
+ break;
+
+ case CT_CONST_INT:
+ if (CONST_INT_P (operand)
+ && (insn_const_int_ok_for_constraint
+ (INTVAL (operand), cn)))
+ win = true;
+ break;
- if (EXTRA_CONSTRAINT_STR (operand, c, p))
+ case CT_MEMORY:
+ if (force_reload)
+ break;
+ if (constraint_satisfied_p (operand, cn))
+ win = 1;
+ /* If the address was already reloaded,
+ we win as well. */
+ else if (MEM_P (operand) && address_reloaded[i] == 1)
+ win = 1;
+ /* Likewise if the address will be reloaded because
+ reg_equiv_address is nonzero. For reg_equiv_mem
+ we have to check. */
+ else if (REG_P (operand)
+ && REGNO (operand) >= FIRST_PSEUDO_REGISTER
+ && reg_renumber[REGNO (operand)] < 0
+ && ((reg_equiv_mem (REGNO (operand)) != 0
+ && (constraint_satisfied_p
+ (reg_equiv_mem (REGNO (operand)),
+ cn)))
+ || (reg_equiv_address (REGNO (operand))
+ != 0)))
+ win = 1;
+
+ /* If we didn't already win, we can reload
+ constants via force_const_mem, and other
+ MEMs by reloading the address like for 'o'. */
+ if (CONST_POOL_OK_P (operand_mode[i], operand)
+ || MEM_P (operand))
+ badop = 0;
+ constmemok = 1;
+ offmemok = 1;
+ break;
+
+ case CT_ADDRESS:
+ if (constraint_satisfied_p (operand, cn))
+ win = 1;
+
+ /* If we didn't already win, we can reload
+ the address into a base register. */
+ this_alternative[i]
+ = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
+ ADDRESS, SCRATCH);
+ badop = 0;
+ break;
+
+ case CT_FIXED_FORM:
+ if (constraint_satisfied_p (operand, cn))
win = 1;
-#endif
break;
}
+ break;
- this_alternative[i]
- = (reg_class_subunion
- [this_alternative[i]]
- [(int) REG_CLASS_FROM_CONSTRAINT (c, p)]);
reg:
+ this_alternative[i]
+ = reg_class_subunion[this_alternative[i]][cl];
if (GET_MODE (operand) == BLKmode)
break;
winreg = 1;
if (swapped)
{
- enum reg_class tclass;
- int t;
-
/* If the commutative operands have been swapped, swap
them back in order to check the next alternative. */
recog_data.operand[commutative] = substed_operand[commutative];
= recog_data.operand[(int) recog_data.dup_num[i]];
/* Unswap the operand related information as well. */
- 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;
-
- t = address_reloaded[commutative];
- address_reloaded[commutative] = address_reloaded[commutative + 1];
- address_reloaded[commutative + 1] = t;
+ std::swap (preferred_class[commutative],
+ preferred_class[commutative + 1]);
+ std::swap (pref_or_nothing[commutative],
+ pref_or_nothing[commutative + 1]);
+ std::swap (address_reloaded[commutative],
+ address_reloaded[commutative + 1]);
}
}
}
if (goal_alternative_swapped)
{
- rtx tem;
-
- tem = substed_operand[commutative];
- substed_operand[commutative] = substed_operand[commutative + 1];
- substed_operand[commutative + 1] = tem;
- tem = recog_data.operand[commutative];
- recog_data.operand[commutative] = recog_data.operand[commutative + 1];
- recog_data.operand[commutative + 1] = tem;
- tem = *recog_data.operand_loc[commutative];
- *recog_data.operand_loc[commutative]
- = *recog_data.operand_loc[commutative + 1];
- *recog_data.operand_loc[commutative + 1] = tem;
+ std::swap (substed_operand[commutative],
+ substed_operand[commutative + 1]);
+ std::swap (recog_data.operand[commutative],
+ recog_data.operand[commutative + 1]);
+ std::swap (*recog_data.operand_loc[commutative],
+ *recog_data.operand_loc[commutative + 1]);
+
+ for (i = 0; i < recog_data.n_dups; i++)
+ if (recog_data.dup_num[i] == commutative
+ || recog_data.dup_num[i] == commutative + 1)
+ *recog_data.dup_loc[i]
+ = recog_data.operand[(int) recog_data.dup_num[i]];
for (i = 0; i < n_reloads; i++)
{
rtx op = recog_data.operand[i];
rtx subreg = NULL_RTX;
rtx plus = NULL_RTX;
- enum machine_mode mode = operand_mode[i];
+ machine_mode mode = operand_mode[i];
/* Reloads of SUBREGs of CONSTANT RTXs are handled later in
push_reload so we have to let them pass here. */
use the default address mode as mode of the reload register,
as would have been done by find_reloads_address. */
addr_space_t as = MEM_ADDR_SPACE (recog_data.operand[i]);
- enum machine_mode address_mode;
- address_mode = GET_MODE (XEXP (recog_data.operand[i], 0));
- if (address_mode == VOIDmode)
- address_mode = targetm.addr_space.address_mode (as);
+ machine_mode address_mode;
+ address_mode = get_address_mode (recog_data.operand[i]);
operand_reloadnum[i]
= push_reload (XEXP (recog_data.operand[i], 0), NULL_RTX,
&XEXP (recog_data.operand[i], 0), (rtx*) 0,
this instruction. */
if (GET_CODE (substitution) == LABEL_REF
&& !find_reg_note (insn, REG_LABEL_OPERAND,
- XEXP (substitution, 0))
+ LABEL_REF_LABEL (substitution))
/* For a JUMP_P, if it was a branch target it must have
already been recorded as such. */
&& (!JUMP_P (insn)
- || !label_is_jump_target_p (XEXP (substitution, 0),
+ || !label_is_jump_target_p (LABEL_REF_LABEL (substitution),
insn)))
{
- add_reg_note (insn, REG_LABEL_OPERAND, XEXP (substitution, 0));
- if (LABEL_P (XEXP (substitution, 0)))
- ++LABEL_NUSES (XEXP (substitution, 0));
+ add_reg_note (insn, REG_LABEL_OPERAND,
+ LABEL_REF_LABEL (substitution));
+ if (LABEL_P (LABEL_REF_LABEL (substitution)))
+ ++LABEL_NUSES (LABEL_REF_LABEL (substitution));
}
}
rld[j].in = 0;
}
-#ifdef HAVE_cc0
/* If we made any reloads for addresses, see if they violate a
"no input reloads" requirement for this insn. But loads that we
do after the insn (such as for output addresses) are fine. */
- if (no_input_reloads)
+ if (HAVE_cc0 && no_input_reloads)
for (i = 0; i < n_reloads; i++)
gcc_assert (rld[i].in == 0
|| rld[i].when_needed == RELOAD_FOR_OUTADDR_ADDRESS
|| rld[i].when_needed == RELOAD_FOR_OUTPUT_ADDRESS);
-#endif
/* Compute reload_mode and reload_nregs. */
for (i = 0; i < n_reloads; i++)
for (nri = 1; nri < nr; nri ++)
if (! TEST_HARD_REG_BIT (reg_class_contents[rld[i].rclass], regno + nri))
- ok = 0;
+ {
+ ok = 0;
+ break;
+ }
if (ok)
rld[i].reg_rtx = dest;
for (; (c = *constraint) && c != ',' && c != '#';
constraint += CONSTRAINT_LEN (c, constraint))
{
- if (c == TARGET_MEM_CONSTRAINT || c == 'o')
+ enum constraint_num cn = lookup_constraint (constraint);
+ if (insn_extra_memory_constraint (cn)
+ && (mem == NULL || constraint_satisfied_p (mem, cn)))
return true;
-#ifdef EXTRA_CONSTRAINT_STR
- if (EXTRA_MEMORY_CONSTRAINT (c, constraint)
- && (mem == NULL || EXTRA_CONSTRAINT_STR (mem, c, constraint)))
- return true;
-#endif
}
return false;
}
static rtx
find_reloads_toplev (rtx x, int opnum, enum reload_type type,
- int ind_levels, int is_set_dest, rtx insn,
+ int ind_levels, int is_set_dest, rtx_insn *insn,
int *address_reloaded)
{
RTX_CODE code = GET_CODE (x);
}
/* If the subreg contains a reg that will be converted to a mem,
- convert the subreg to a narrower memref now.
- Otherwise, we would get (subreg (mem ...) ...),
- which would force reload of the mem.
-
- We also need to do this if there is an equivalent MEM that is
- not offsettable. In that case, alter_subreg would produce an
- invalid address on big-endian machines.
-
- For machines that extend byte loads, we must not reload using
- a wider mode if we have a paradoxical SUBREG. find_reloads will
- force a reload in that case. So we should not do anything here. */
+ attempt to convert the whole subreg to a (narrower or wider)
+ memory reference instead. If this succeeds, we're done --
+ otherwise fall through to check whether the inner reg still
+ needs address reloads anyway. */
if (regno >= FIRST_PSEUDO_REGISTER
-#ifdef LOAD_EXTEND_OP
- && !paradoxical_subreg_p (x)
-#endif
- && (reg_equiv_address (regno) != 0
- || (reg_equiv_mem (regno) != 0
- && (! strict_memory_address_addr_space_p
- (GET_MODE (x), XEXP (reg_equiv_mem (regno), 0),
- MEM_ADDR_SPACE (reg_equiv_mem (regno)))
- || ! offsettable_memref_p (reg_equiv_mem (regno))
- || num_not_at_initial_offset))))
- x = find_reloads_subreg_address (x, 1, opnum, type, ind_levels,
- insn, address_reloaded);
+ && reg_equiv_memory_loc (regno) != 0)
+ {
+ tem = find_reloads_subreg_address (x, opnum, type, ind_levels,
+ insn, address_reloaded);
+ if (tem)
+ return tem;
+ }
}
for (copied = 0, i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
by PART into a register. */
static int
-maybe_memory_address_addr_space_p (enum machine_mode mode, rtx ad,
+maybe_memory_address_addr_space_p (machine_mode mode, rtx ad,
addr_space_t as, rtx *part)
{
int retv;
to a hard register, and frame pointer elimination. */
static int
-find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad,
+find_reloads_address (machine_mode mode, rtx *memrefloc, rtx ad,
rtx *loc, int opnum, enum reload_type type,
- int ind_levels, rtx insn)
+ int ind_levels, rtx_insn *insn)
{
addr_space_t as = memrefloc? MEM_ADDR_SPACE (*memrefloc)
: ADDR_SPACE_GENERIC;
#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
|| operand == hard_frame_pointer_rtx
#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
- || operand == arg_pointer_rtx
-#endif
+ || (FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+ && operand == arg_pointer_rtx)
|| operand == stack_pointer_rtx)
&& ! maybe_memory_address_addr_space_p
(mode, ad, as, &XEXP (XEXP (ad, 0), 1 - op_index)))
into a register. */
if (CONSTANT_P (ad) && ! strict_memory_address_addr_space_p (mode, ad, as))
{
- enum machine_mode address_mode = GET_MODE (ad);
+ machine_mode address_mode = GET_MODE (ad);
if (address_mode == VOIDmode)
address_mode = targetm.addr_space.address_mode (as);
front of it for pseudos that we have to replace with stack slots. */
static rtx
-subst_reg_equivs (rtx ad, rtx insn)
+subst_reg_equivs (rtx ad, rtx_insn *insn)
{
RTX_CODE code = GET_CODE (ad);
int i;
switch (code)
{
case HIGH:
- case CONST_INT:
case CONST:
- case CONST_DOUBLE:
- case CONST_FIXED:
- case CONST_VECTOR:
+ CASE_CONST_ANY:
case SYMBOL_REF:
case LABEL_REF:
case PC:
This routine assumes both inputs are already in canonical form. */
rtx
-form_sum (enum machine_mode mode, rtx x, rtx y)
+form_sum (machine_mode mode, rtx x, rtx y)
{
rtx tem;
RELOADNUM is the reload number. */
static void
-update_auto_inc_notes (rtx insn ATTRIBUTE_UNUSED, int regno ATTRIBUTE_UNUSED,
+update_auto_inc_notes (rtx_insn *insn ATTRIBUTE_UNUSED, int regno ATTRIBUTE_UNUSED,
int reloadnum ATTRIBUTE_UNUSED)
{
#ifdef AUTO_INC_DEC
handles those cases gracefully. */
static int
-find_reloads_address_1 (enum machine_mode mode, addr_space_t as,
+find_reloads_address_1 (machine_mode mode, addr_space_t as,
rtx x, int context,
enum rtx_code outer_code, enum rtx_code index_code,
rtx *loc, int opnum, enum reload_type type,
- int ind_levels, rtx insn)
+ int ind_levels, rtx_insn *insn)
{
#define REG_OK_FOR_CONTEXT(CONTEXT, REGNO, MODE, AS, OUTER, INDEX) \
((CONTEXT) == 0 \
enum reg_class context_reg_class;
RTX_CODE code = GET_CODE (x);
+ bool reloaded_inner_of_autoinc = false;
if (context == 1)
context_reg_class = INDEX_REG_CLASS;
find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
&XEXP (tem, 0), opnum, type,
ind_levels, insn);
+ reloaded_inner_of_autoinc = true;
if (!rtx_equal_p (tem, orig))
push_reg_equiv_alt_mem (regno, tem);
/* Put this inside a new increment-expression. */
enum insn_code icode = optab_handler (add_optab, GET_MODE (x));
if (insn && NONJUMP_INSN_P (insn) && equiv
&& memory_operand (equiv, GET_MODE (equiv))
-#ifdef HAVE_cc0
+#if HAVE_cc0
&& ! sets_cc0_p (PATTERN (insn))
#endif
&& ! (icode != CODE_FOR_nothing
&& insn_operand_matches (icode, 0, equiv)
- && insn_operand_matches (icode, 1, equiv)))
+ && insn_operand_matches (icode, 1, equiv))
+ /* Using RELOAD_OTHER means we emit this and the reload we
+ made earlier in the wrong order. */
+ && !reloaded_inner_of_autoinc)
{
/* We use the original pseudo for loc, so that
emit_reload_insns() knows which pseudo this
if (ira_reg_class_max_nregs [rclass][GET_MODE (SUBREG_REG (x))]
> reg_class_size[(int) rclass])
{
- x = find_reloads_subreg_address (x, 0, opnum,
- ADDR_TYPE (type),
- ind_levels, insn, NULL);
- push_reload (x, NULL_RTX, loc, (rtx*) 0, rclass,
- GET_MODE (x), VOIDmode, 0, 0, opnum, type);
- return 1;
+ /* If the inner register will be replaced by a memory
+ reference, we can do this only if we can replace the
+ whole subreg by a (narrower) memory reference. If
+ this is not possible, fall through and reload just
+ the inner register (including address reloads). */
+ if (reg_equiv_memory_loc (REGNO (SUBREG_REG (x))) != 0)
+ {
+ rtx tem = find_reloads_subreg_address (x, opnum,
+ ADDR_TYPE (type),
+ ind_levels, insn,
+ NULL);
+ if (tem)
+ {
+ push_reload (tem, NULL_RTX, loc, (rtx*) 0, rclass,
+ GET_MODE (tem), VOIDmode, 0, 0,
+ opnum, type);
+ return 1;
+ }
+ }
+ else
+ {
+ push_reload (x, NULL_RTX, loc, (rtx*) 0, rclass,
+ GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+ return 1;
+ }
}
}
}
static void
find_reloads_address_part (rtx x, rtx *loc, enum reg_class rclass,
- enum machine_mode mode, int opnum,
+ machine_mode mode, int opnum,
enum reload_type type, int ind_levels)
{
if (CONSTANT_P (x)
}
\f
/* X, a subreg of a pseudo, is a part of an address that needs to be
- reloaded.
-
- If the pseudo is equivalent to a memory location that cannot be directly
- addressed, make the necessary address reloads.
+ reloaded, and the pseusdo is equivalent to a memory location.
- If address reloads have been necessary, or if the address is changed
- by register elimination, return the rtx of the memory location;
- otherwise, return X.
-
- If FORCE_REPLACE is nonzero, unconditionally replace the subreg with the
- memory location.
+ Attempt to replace the whole subreg by a (possibly narrower or wider)
+ memory reference. If this is possible, return this new memory
+ reference, and push all required address reloads. Otherwise,
+ return NULL.
OPNUM and TYPE identify the purpose of the reload.
stack slots. */
static rtx
-find_reloads_subreg_address (rtx x, int force_replace, int opnum,
- enum reload_type type, int ind_levels, rtx insn,
+find_reloads_subreg_address (rtx x, int opnum, enum reload_type type,
+ int ind_levels, rtx_insn *insn,
int *address_reloaded)
{
+ machine_mode outer_mode = GET_MODE (x);
+ machine_mode inner_mode = GET_MODE (SUBREG_REG (x));
int regno = REGNO (SUBREG_REG (x));
int reloaded = 0;
+ rtx tem, orig;
+ int offset;
- if (reg_equiv_memory_loc (regno))
- {
- /* If the address is not directly addressable, or if the address is not
- offsettable, then it must be replaced. */
- 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);
+ gcc_assert (reg_equiv_memory_loc (regno) != 0);
- /* If the address changes because of register elimination, then
- it must be replaced. */
- if (force_replace
- || ! rtx_equal_p (tem, reg_equiv_mem (regno)))
- {
- unsigned outer_size = GET_MODE_SIZE (GET_MODE (x));
- unsigned inner_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
- int offset;
- rtx orig = tem;
-
- /* For big-endian paradoxical subregs, SUBREG_BYTE does not
- hold the correct (negative) byte offset. */
- if (BYTES_BIG_ENDIAN && outer_size > inner_size)
- offset = inner_size - outer_size;
- else
- offset = SUBREG_BYTE (x);
-
- XEXP (tem, 0) = plus_constant (GET_MODE (XEXP (tem, 0)),
- XEXP (tem, 0), offset);
- PUT_MODE (tem, GET_MODE (x));
- if (MEM_OFFSET_KNOWN_P (tem))
- set_mem_offset (tem, MEM_OFFSET (tem) + offset);
- if (MEM_SIZE_KNOWN_P (tem)
- && MEM_SIZE (tem) != (HOST_WIDE_INT) outer_size)
- set_mem_size (tem, outer_size);
-
- /* If this was a paradoxical subreg that we replaced, the
- resulting memory must be sufficiently aligned to allow
- us to widen the mode of the memory. */
- if (outer_size > inner_size)
- {
- rtx base;
+ /* We cannot replace the subreg with a modified memory reference if:
- base = XEXP (tem, 0);
- if (GET_CODE (base) == PLUS)
- {
- if (CONST_INT_P (XEXP (base, 1))
- && INTVAL (XEXP (base, 1)) % outer_size != 0)
- return x;
- base = XEXP (base, 0);
- }
- if (!REG_P (base)
- || (REGNO_POINTER_ALIGN (REGNO (base))
- < outer_size * BITS_PER_UNIT))
- return x;
- }
+ - we have a paradoxical subreg that implicitly acts as a zero or
+ sign extension operation due to LOAD_EXTEND_OP;
- reloaded = find_reloads_address (GET_MODE (tem), &tem,
- XEXP (tem, 0), &XEXP (tem, 0),
- opnum, type, ind_levels, insn);
- /* ??? Do we need to handle nonzero offsets somehow? */
- if (!offset && !rtx_equal_p (tem, orig))
- push_reg_equiv_alt_mem (regno, tem);
-
- /* For some processors an address may be valid in the
- original mode but not in a smaller mode. For
- example, ARM accepts a scaled index register in
- SImode but not in HImode. Note that this is only
- a problem if the address in reg_equiv_mem is already
- invalid in the new mode; other cases would be fixed
- by find_reloads_address as usual.
-
- ??? We attempt to handle such cases here by doing an
- additional reload of the full address after the
- usual processing by find_reloads_address. Note that
- this may not work in the general case, but it seems
- to cover the cases where this situation currently
- occurs. A more general fix might be to reload the
- *value* instead of the address, but this would not
- be expected by the callers of this routine as-is.
-
- If find_reloads_address already completed replaced
- the address, there is nothing further to do. */
- if (reloaded == 0
- && reg_equiv_mem (regno) != 0
- && !strict_memory_address_addr_space_p
- (GET_MODE (x), XEXP (reg_equiv_mem (regno), 0),
- MEM_ADDR_SPACE (reg_equiv_mem (regno))))
- {
- push_reload (XEXP (tem, 0), NULL_RTX, &XEXP (tem, 0), (rtx*) 0,
- base_reg_class (GET_MODE (tem),
- MEM_ADDR_SPACE (tem),
- MEM, SCRATCH),
- GET_MODE (XEXP (tem, 0)), VOIDmode, 0, 0,
- opnum, type);
- reloaded = 1;
- }
- /* If this is not a toplevel operand, find_reloads doesn't see
- this substitution. We have to emit a USE of the pseudo so
- that delete_output_reload can see it. */
- if (replace_reloads && recog_data.operand[opnum] != x)
- /* We mark the USE with QImode so that we recognize it
- as one that can be safely deleted at the end of
- reload. */
- PUT_MODE (emit_insn_before (gen_rtx_USE (VOIDmode,
- SUBREG_REG (x)),
- insn), QImode);
- x = tem;
- }
- }
+ - we have a subreg that is implicitly supposed to act on the full
+ register due to WORD_REGISTER_OPERATIONS (see also eliminate_regs);
+
+ - the address of the equivalent memory location is mode-dependent; or
+
+ - we have a paradoxical subreg and the resulting memory is not
+ sufficiently aligned to allow access in the wider mode.
+
+ In addition, we choose not to perform the replacement for *any*
+ paradoxical subreg, even if it were possible in principle. This
+ is to avoid generating wider memory references than necessary.
+
+ This corresponds to how previous versions of reload used to handle
+ paradoxical subregs where no address reload was required. */
+
+ if (paradoxical_subreg_p (x))
+ return NULL;
+
+#ifdef WORD_REGISTER_OPERATIONS
+ if (GET_MODE_SIZE (outer_mode) < GET_MODE_SIZE (inner_mode)
+ && ((GET_MODE_SIZE (outer_mode) - 1) / UNITS_PER_WORD
+ == (GET_MODE_SIZE (inner_mode) - 1) / UNITS_PER_WORD))
+ return NULL;
+#endif
+
+ /* Since we don't attempt to handle paradoxical subregs, we can just
+ call into simplify_subreg, which will handle all remaining checks
+ for us. */
+ orig = make_memloc (SUBREG_REG (x), regno);
+ offset = SUBREG_BYTE (x);
+ tem = simplify_subreg (outer_mode, orig, inner_mode, offset);
+ if (!tem || !MEM_P (tem))
+ return NULL;
+
+ /* Now push all required address reloads, if any. */
+ reloaded = find_reloads_address (GET_MODE (tem), &tem,
+ XEXP (tem, 0), &XEXP (tem, 0),
+ opnum, type, ind_levels, insn);
+ /* ??? Do we need to handle nonzero offsets somehow? */
+ if (!offset && !rtx_equal_p (tem, orig))
+ push_reg_equiv_alt_mem (regno, tem);
+
+ /* For some processors an address may be valid in the original mode but
+ not in a smaller mode. For example, ARM accepts a scaled index register
+ in SImode but not in HImode. Note that this is only a problem if the
+ address in reg_equiv_mem is already invalid in the new mode; other
+ cases would be fixed by find_reloads_address as usual.
+
+ ??? We attempt to handle such cases here by doing an additional reload
+ of the full address after the usual processing by find_reloads_address.
+ Note that this may not work in the general case, but it seems to cover
+ the cases where this situation currently occurs. A more general fix
+ might be to reload the *value* instead of the address, but this would
+ not be expected by the callers of this routine as-is.
+
+ If find_reloads_address already completed replaced the address, there
+ is nothing further to do. */
+ if (reloaded == 0
+ && reg_equiv_mem (regno) != 0
+ && !strict_memory_address_addr_space_p
+ (GET_MODE (x), XEXP (reg_equiv_mem (regno), 0),
+ MEM_ADDR_SPACE (reg_equiv_mem (regno))))
+ {
+ push_reload (XEXP (tem, 0), NULL_RTX, &XEXP (tem, 0), (rtx*) 0,
+ base_reg_class (GET_MODE (tem), MEM_ADDR_SPACE (tem),
+ MEM, SCRATCH),
+ GET_MODE (XEXP (tem, 0)), VOIDmode, 0, 0, opnum, type);
+ reloaded = 1;
}
+
+ /* If this is not a toplevel operand, find_reloads doesn't see this
+ substitution. We have to emit a USE of the pseudo so that
+ delete_output_reload can see it. */
+ if (replace_reloads && recog_data.operand[opnum] != x)
+ /* We mark the USE with QImode so that we recognize it as one that
+ can be safely deleted at the end of reload. */
+ PUT_MODE (emit_insn_before (gen_rtx_USE (VOIDmode, SUBREG_REG (x)), insn),
+ QImode);
+
if (address_reloaded)
*address_reloaded = reloaded;
- return x;
+ return tem;
}
\f
/* Substitute into the current INSN the registers into which we have reloaded
Return the rtx that X translates into; usually X, but modified. */
void
-subst_reloads (rtx insn)
+subst_reloads (rtx_insn *insn)
{
int i;
for (check_regno = 0; check_regno < max_regno; check_regno++)
{
#define CHECK_MODF(ARRAY) \
- gcc_assert (!VEC_index (reg_equivs_t, reg_equivs, check_regno).ARRAY \
+ gcc_assert (!(*reg_equivs)[check_regno].ARRAY \
|| !loc_mentioned_in_p (r->where, \
- VEC_index (reg_equivs_t, reg_equivs, check_regno).ARRAY))
+ (*reg_equivs)[check_regno].ARRAY))
- CHECK_MODF (equiv_constant);
- CHECK_MODF (equiv_memory_loc);
- CHECK_MODF (equiv_address);
- CHECK_MODF (equiv_mem);
+ CHECK_MODF (constant);
+ CHECK_MODF (memory_loc);
+ CHECK_MODF (address);
+ CHECK_MODF (mem);
#undef CHECK_MODF
}
#endif /* DEBUG_RELOAD */
return 0;
}
- endregno = END_HARD_REGNO (x);
+ endregno = END_REGNO (x);
return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0);
}
as if it were a constant except that sp is required to be unchanging. */
rtx
-find_equiv_reg (rtx goal, rtx insn, enum reg_class rclass, int other,
- short *reload_reg_p, int goalreg, enum machine_mode mode)
+find_equiv_reg (rtx goal, rtx_insn *insn, enum reg_class rclass, int other,
+ short *reload_reg_p, int goalreg, machine_mode mode)
{
- rtx p = insn;
- rtx goaltry, valtry, value, where;
+ rtx_insn *p = insn;
+ rtx goaltry, valtry, value;
+ rtx_insn *where;
rtx pat;
int regno = -1;
int valueno;
&& (valueno
= true_regnum (valtry = SET_DEST (pat))) >= 0)
|| (REG_P (SET_DEST (pat))
- && GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE
+ && CONST_DOUBLE_AS_FLOAT_P (XEXP (tem, 0))
&& SCALAR_FLOAT_MODE_P (GET_MODE (XEXP (tem, 0)))
&& CONST_INT_P (goal)
&& 0 != (goaltry
|| (goal_const && (tem = find_reg_note (p, REG_EQUIV,
NULL_RTX))
&& REG_P (SET_DEST (pat))
- && GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE
+ && CONST_DOUBLE_AS_FLOAT_P (XEXP (tem, 0))
&& SCALAR_FLOAT_MODE_P (GET_MODE (XEXP (tem, 0)))
&& CONST_INT_P (goal)
&& 0 != (goaltry = operand_subword (XEXP (tem, 0), 1, 0,
REG_INC. REGNO must refer to a hard register. */
int
-regno_clobbered_p (unsigned int regno, rtx insn, enum machine_mode mode,
+regno_clobbered_p (unsigned int regno, rtx_insn *insn, machine_mode mode,
int sets)
{
unsigned int nregs, endregno;
/* Find the low part, with mode MODE, of a hard regno RELOADREG. */
rtx
-reload_adjust_reg_for_mode (rtx reloadreg, enum machine_mode mode)
+reload_adjust_reg_for_mode (rtx reloadreg, machine_mode mode)
{
int regno;