/* 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 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h"
#include "tm_p.h"
#include "insn-config.h"
#endif
static enum reg_class find_valid_class PARAMS ((enum machine_mode, int,
unsigned int));
-static int reload_inner_reg_of_subreg PARAMS ((rtx, enum machine_mode));
+static int reload_inner_reg_of_subreg PARAMS ((rtx, enum machine_mode, int));
static void push_replacement PARAMS ((rtx *, int, enum machine_mode));
static void dup_replacements PARAMS ((rtx *, rtx *));
static void combine_reloads PARAMS ((void));
static rtx find_reloads_toplev PARAMS ((rtx, int, enum reload_type, int,
int, rtx, int *));
static rtx make_memloc PARAMS ((rtx, int));
+static int maybe_memory_address_p PARAMS ((enum machine_mode, rtx, rtx *));
static int find_reloads_address PARAMS ((enum machine_mode, rtx *, rtx, rtx *,
int, enum reload_type, int, rtx));
static rtx subst_reg_equivs PARAMS ((rtx, rtx));
insn_class = ALL_REGS;
else
{
- char insn_letter
- = insn_data[(int) icode].operand[!in_p].constraint[in_p];
+ const char *insn_constraint
+ = &insn_data[(int) icode].operand[!in_p].constraint[in_p];
+ char insn_letter = *insn_constraint;
insn_class
= (insn_letter == 'r' ? GENERAL_REGS
- : REG_CLASS_FROM_LETTER ((unsigned char) insn_letter));
+ : REG_CLASS_FROM_CONSTRAINT ((unsigned char) insn_letter,
+ insn_constraint));
if (insn_class == NO_REGS)
abort ();
mode = insn_data[(int) icode].operand[2].mode;
else
{
- char t_letter = insn_data[(int) icode].operand[2].constraint[2];
+ const char *t_constraint
+ = &insn_data[(int) icode].operand[2].constraint[2];
+ char t_letter = *t_constraint;
class = insn_class;
t_mode = insn_data[(int) icode].operand[2].mode;
t_class = (t_letter == 'r' ? GENERAL_REGS
- : REG_CLASS_FROM_LETTER ((unsigned char) t_letter));
+ : REG_CLASS_FROM_CONSTRAINT ((unsigned char) t_letter,
+ t_constraint));
t_icode = icode;
icode = CODE_FOR_nothing;
}
find_valid_class (m1, n, dest_regno)
enum machine_mode m1 ATTRIBUTE_UNUSED;
int n;
- unsigned int dest_regno;
+ unsigned int dest_regno ATTRIBUTE_UNUSED;
{
int best_cost = -1;
int class;
int regno;
enum reg_class best_class = NO_REGS;
- enum reg_class dest_class = REGNO_REG_CLASS (dest_regno);
+ enum reg_class dest_class ATTRIBUTE_UNUSED = REGNO_REG_CLASS (dest_regno);
unsigned int best_size = 0;
int cost;
SUBREG_REG expression. */
static int
-reload_inner_reg_of_subreg (x, mode)
+reload_inner_reg_of_subreg (x, mode, output)
rtx x;
enum machine_mode mode;
+ int output;
{
rtx inner;
word and the number of regs for INNER is not the same as the
number of words in INNER, then INNER will need reloading. */
return (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
+ && output
&& GET_MODE_SIZE (GET_MODE (inner)) > UNITS_PER_WORD
&& ((GET_MODE_SIZE (GET_MODE (inner)) / UNITS_PER_WORD)
!= (int) HARD_REGNO_NREGS (REGNO (inner), GET_MODE (inner))));
if (in != 0 && GET_CODE (in) == SUBREG
&& (subreg_lowpart_p (in) || strict_low)
-#ifdef CLASS_CANNOT_CHANGE_MODE
- && (class != CLASS_CANNOT_CHANGE_MODE
- || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)), inmode))
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)), inmode, class)
#endif
&& (CONSTANT_P (SUBREG_REG (in))
|| GET_CODE (SUBREG_REG (in)) == PLUS
SUBREG_REG (in))
== NO_REGS))
#endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
|| (GET_CODE (SUBREG_REG (in)) == REG
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
- && (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
- REGNO (SUBREG_REG (in))))
- && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)),
- inmode))
+ && REG_CANNOT_CHANGE_MODE_P
+ (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in)), inmode))
#endif
))
{
/* Similar issue for (SUBREG constant ...) if it was not handled by the
code above. This can happen if SUBREG_BYTE != 0. */
- if (in != 0 && reload_inner_reg_of_subreg (in, inmode))
+ if (in != 0 && reload_inner_reg_of_subreg (in, inmode, 0))
{
enum reg_class in_class = class;
and in that case the constraint should label it input-output.) */
if (out != 0 && GET_CODE (out) == SUBREG
&& (subreg_lowpart_p (out) || strict_low)
-#ifdef CLASS_CANNOT_CHANGE_MODE
- && (class != CLASS_CANNOT_CHANGE_MODE
- || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)),
- outmode))
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)), outmode, class)
#endif
&& (CONSTANT_P (SUBREG_REG (out))
|| strict_low
SUBREG_REG (out))
== NO_REGS))
#endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
|| (GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
- && (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
- REGNO (SUBREG_REG (out))))
- && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)),
- outmode))
+ && REG_CANNOT_CHANGE_MODE_P (REGNO (SUBREG_REG (out)),
+ GET_MODE (SUBREG_REG (out)),
+ outmode))
#endif
))
{
However, we must reload the inner reg *as well as* the subreg in
that case. In this case, the inner reg is an in-out reload. */
- if (out != 0 && reload_inner_reg_of_subreg (out, outmode))
+ if (out != 0 && reload_inner_reg_of_subreg (out, outmode, 1))
{
/* This relies on the fact that emit_reload_insns outputs the
instructions for output reloads of type RELOAD_OTHER in reverse
#ifdef SECONDARY_MEMORY_NEEDED
/* If a memory location is needed for the copy, make one. */
- if (in != 0 && GET_CODE (in) == REG
- && REGNO (in) < FIRST_PSEUDO_REGISTER
- && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)),
+ if (in != 0 && (GET_CODE (in) == REG || GET_CODE (in) == SUBREG)
+ && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER
+ && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (reg_or_subregno (in)),
class, inmode))
get_secondary_mem (in, inmode, opnum, type);
#endif
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)),
+ if (out != 0 && (GET_CODE (out) == REG || GET_CODE (out) == SUBREG)
+ && reg_or_subregno (out) < FIRST_PSEUDO_REGISTER
+ && SECONDARY_MEMORY_NEEDED (class,
+ REGNO_REG_CLASS (reg_or_subregno (out)),
outmode))
get_secondary_mem (out, outmode, opnum, type);
#endif
&& ! (GET_CODE (rld[i].in) == REG
&& reg_overlap_mentioned_for_reload_p (rld[i].in,
rld[output_reload].out))))
- && ! reload_inner_reg_of_subreg (rld[i].in, rld[i].inmode)
+ && ! reload_inner_reg_of_subreg (rld[i].in, rld[i].inmode,
+ rld[i].when_needed != RELOAD_FOR_INPUT)
&& (reg_class_size[(int) rld[i].class]
|| SMALL_REGISTER_CLASSES)
/* We will allow making things slightly worse by combining an
(reg:SI 1) will be considered the same register. */
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;
+ i += HARD_REGNO_NREGS (i, GET_MODE (x)) - 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;
+ j += HARD_REGNO_NREGS (j, GET_MODE (y)) - 1;
return i == j;
}
/* If two operands must match, because they are really a single
operand of an assembler insn, then two postincrements are invalid
because the assembler insn would increment only once.
- On the other hand, an postincrement matches ordinary indexing
+ On the other hand, a postincrement matches ordinary indexing
if the postincrement is the output operand. */
if (code == POST_DEC || code == POST_INC || code == POST_MODIFY)
return operands_match_p (XEXP (x, 0), y);
/* Two preincrements are invalid
because the assembler insn would increment only once.
- On the other hand, an preincrement matches ordinary indexing
+ On the other hand, a preincrement matches ordinary indexing
if the preincrement is the input operand.
In this case, return 2, since some callers need to do special
things when this happens. */
char pref_or_nothing[MAX_RECOG_OPERANDS];
/* Nonzero for a MEM operand whose entire address needs a reload. */
int address_reloaded[MAX_RECOG_OPERANDS];
+ /* Nonzero for an address operand that needs to be completely reloaded. */
+ int address_operand_reloaded[MAX_RECOG_OPERANDS];
/* Value of enum reload_type to use for operand. */
enum reload_type operand_type[MAX_RECOG_OPERANDS];
/* Value of enum reload_type to use within address of operand. */
/* Scan this operand's constraint to see if it is an output operand,
an in-out operand, is commutative, or should match another. */
- while ((c = *p++))
+ while ((c = *p))
{
+ p += CONSTRAINT_LEN (c, p);
if (c == '=')
modified[i] = RELOAD_WRITE;
else if (c == '+')
RTX_CODE code = GET_CODE (recog_data.operand[i]);
address_reloaded[i] = 0;
+ address_operand_reloaded[i] = 0;
operand_type[i] = (modified[i] == RELOAD_READ ? RELOAD_FOR_INPUT
: modified[i] == RELOAD_WRITE ? RELOAD_FOR_OUTPUT
: RELOAD_OTHER);
/* Ignore things like match_operator operands. */
;
else if (constraints[i][0] == 'p'
- || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0]))
+ || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i]))
{
- find_reloads_address (recog_data.operand_mode[i], (rtx*) 0,
- recog_data.operand[i],
- recog_data.operand_loc[i],
- i, operand_type[i], ind_levels, insn);
+ address_operand_reloaded[i]
+ = find_reloads_address (recog_data.operand_mode[i], (rtx*) 0,
+ recog_data.operand[i],
+ recog_data.operand_loc[i],
+ i, operand_type[i], ind_levels, insn);
/* If we now have a simple operand where we used to have a
PLUS or MULT, re-recognize and try again. */
recog_data.operand[i] = *recog_data.operand_loc[i];
substed_operand[i] = recog_data.operand[i];
+
+ /* Address operands are reloaded in their existing mode,
+ no matter what is specified in the machine description. */
+ operand_mode[i] = GET_MODE (recog_data.operand[i]);
}
else if (code == MEM)
{
for (i = 0; i < noperands; i++)
{
char *p = constraints[i];
+ char *end;
+ int len;
int win = 0;
int did_match = 0;
/* 0 => this operand can be reloaded somehow for this alternative. */
/* 0 => this operand can be reloaded if the alternative allows regs. */
int winreg = 0;
int c;
+ int m;
rtx operand = recog_data.operand[i];
int offset = 0;
/* Nonzero means this is a MEM that must be reloaded into a reg
if (GET_CODE (SUBREG_REG (operand)) == REG
&& REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER)
{
+ if (!subreg_offset_representable_p
+ (REGNO (SUBREG_REG (operand)),
+ GET_MODE (SUBREG_REG (operand)),
+ SUBREG_BYTE (operand),
+ GET_MODE (operand)))
+ force_reload = 1;
offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)),
GET_MODE (SUBREG_REG (operand)),
SUBREG_BYTE (operand),
by forcing the reload.
??? When is it right at this stage to have a subreg
- of a mem that is _not_ to be handled specialy? IMO
+ of a mem that is _not_ to be handled specially? IMO
those should have been reduced to just a mem. */
|| ((GET_CODE (operand) == MEM
|| (GET_CODE (operand)== REG
)
#endif
)
- /* This following hunk of code should no longer be
- needed at all with SUBREG_BYTE. If you need this
- code back, please explain to me why so I can
- fix the real problem. -DaveM */
-#if 0
- /* Subreg of a hard reg which can't handle the subreg's mode
- or which would handle that mode in the wrong number of
- registers for subregging to work. */
- || (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])))
-#endif
)
force_reload = 1;
}
or set WINREG if this operand could fit after reloads
provided the constraint allows some registers. */
- while (*p && (c = *p++) != ',')
- switch (c)
+ do
+ switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c)
{
+ case '\0':
+ len = 0;
+ break;
+ case ',':
+ c = '\0';
+ break;
+
case '=': case '+': case '*':
break;
case '#':
/* Ignore rest of this alternative as far as
reloading is concerned. */
- while (*p && *p != ',')
+ do
p++;
+ while (*p && *p != ',');
+ len = 0;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- c = strtoul (p - 1, &p, 10);
+ m = strtoul (p, &end, 10);
+ p = end;
+ len = 0;
- this_alternative_matches[i] = c;
+ this_alternative_matches[i] = m;
/* We are supposed to match a previous operand.
If we do, we win if that one did.
If we do not, count both of the operands as losers.
only a single reload insn will be needed to make
the two operands win. As a result, this alternative
may be rejected when it is actually desirable.) */
- if ((swapped && (c != commutative || i != commutative + 1))
+ if ((swapped && (m != commutative || i != commutative + 1))
/* If we are matching as if two operands were swapped,
also pretend that operands_match had been computed
with swapped.
don't exchange them, because operands_match is valid
only on one side of its diagonal. */
? (operands_match
- [(c == commutative || c == commutative + 1)
- ? 2 * commutative + 1 - c : c]
+ [(m == commutative || m == commutative + 1)
+ ? 2 * commutative + 1 - m : m]
[(i == commutative || i == commutative + 1)
? 2 * commutative + 1 - i : i])
- : operands_match[c][i])
+ : operands_match[m][i])
{
/* If we are matching a non-offsettable address where an
offsettable address was expected, then we must reject
this combination, because we can't reload it. */
- if (this_alternative_offmemok[c]
- && GET_CODE (recog_data.operand[c]) == MEM
- && this_alternative[c] == (int) NO_REGS
- && ! this_alternative_win[c])
+ if (this_alternative_offmemok[m]
+ && GET_CODE (recog_data.operand[m]) == MEM
+ && this_alternative[m] == (int) NO_REGS
+ && ! this_alternative_win[m])
bad = 1;
- did_match = this_alternative_win[c];
+ did_match = this_alternative_win[m];
}
else
{
rtx value;
/* Retroactively mark the operand we had to match
as a loser, if it wasn't already. */
- if (this_alternative_win[c])
+ if (this_alternative_win[m])
losers++;
- this_alternative_win[c] = 0;
- if (this_alternative[c] == (int) NO_REGS)
+ this_alternative_win[m] = 0;
+ if (this_alternative[m] == (int) NO_REGS)
bad = 1;
/* But count the pair only once in the total badness of
this alternative, if the pair can be a dummy reload. */
value
= find_dummy_reload (recog_data.operand[i],
- recog_data.operand[c],
+ recog_data.operand[m],
recog_data.operand_loc[i],
- recog_data.operand_loc[c],
- operand_mode[i], operand_mode[c],
- this_alternative[c], -1,
- this_alternative_earlyclobber[c]);
+ recog_data.operand_loc[m],
+ operand_mode[i], operand_mode[m],
+ this_alternative[m], -1,
+ this_alternative_earlyclobber[m]);
if (value != 0)
losers--;
/* This can be fixed with reloads if the operand
we are supposed to match can be fixed with reloads. */
badop = 0;
- this_alternative[i] = this_alternative[c];
+ this_alternative[i] = this_alternative[m];
/* If we have to reload this operand and some previous
operand also had to match the same thing as this
case 'G':
case 'H':
if (GET_CODE (operand) == CONST_DOUBLE
- && CONST_DOUBLE_OK_FOR_LETTER_P (operand, c))
+ && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (operand, c, p))
win = 1;
break;
case 'O':
case 'P':
if (GET_CODE (operand) == CONST_INT
- && CONST_OK_FOR_LETTER_P (INTVAL (operand), c))
+ && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operand), c, p))
win = 1;
break;
goto reg;
default:
- if (REG_CLASS_FROM_LETTER (c) == NO_REGS)
+ if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS)
{
-#ifdef EXTRA_CONSTRAINT
- if (EXTRA_MEMORY_CONSTRAINT (c))
+#ifdef EXTRA_CONSTRAINT_STR
+ if (EXTRA_MEMORY_CONSTRAINT (c, p))
{
if (force_reload)
break;
- if (EXTRA_CONSTRAINT (operand, c))
+ if (EXTRA_CONSTRAINT_STR (operand, c, p))
win = 1;
/* If the address was already reloaded,
we win as well. */
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (operand)] < 0
&& ((reg_equiv_mem[REGNO (operand)] != 0
- && EXTRA_CONSTRAINT (reg_equiv_mem[REGNO (operand)], c))
+ && EXTRA_CONSTRAINT_STR (reg_equiv_mem[REGNO (operand)], c, p))
|| (reg_equiv_address[REGNO (operand)] != 0)))
win = 1;
offmemok = 1;
break;
}
- if (EXTRA_ADDRESS_CONSTRAINT (c))
+ if (EXTRA_ADDRESS_CONSTRAINT (c, p))
{
- if (EXTRA_CONSTRAINT (operand, c))
+ if (EXTRA_CONSTRAINT_STR (operand, c, p))
win = 1;
/* If we didn't already win, we can reload
break;
}
- if (EXTRA_CONSTRAINT (operand, c))
+ if (EXTRA_CONSTRAINT_STR (operand, c, p))
win = 1;
#endif
break;
}
this_alternative[i]
- = (int) reg_class_subunion[this_alternative[i]][(int) REG_CLASS_FROM_LETTER (c)];
+ = (int) (reg_class_subunion
+ [this_alternative[i]]
+ [(int) REG_CLASS_FROM_CONSTRAINT (c, p)]);
reg:
if (GET_MODE (operand) == BLKmode)
break;
win = 1;
break;
}
+ while ((p += len), c);
constraints[i] = p;
}
else if (goal_alternative_matched[i] < 0
&& goal_alternative_matches[i] < 0
+ && !address_operand_reloaded[i]
&& optimize)
{
/* For each non-matching operand that's a MEM or a pseudo-register
if (regno < FIRST_PSEUDO_REGISTER
&& TEST_HARD_REG_BIT (reg_class_contents[rld[i].class], regno)
&& HARD_REGNO_MODE_OK (regno, rld[i].mode))
- rld[i].reg_rtx = dest;
+ {
+ int nr = HARD_REGNO_NREGS (regno, rld[i].mode);
+ int ok = 1, nri;
+
+ for (nri = 1; nri < nr; nri ++)
+ if (! TEST_HARD_REG_BIT (reg_class_contents[rld[i].class], regno + nri))
+ ok = 0;
+
+ if (ok)
+ rld[i].reg_rtx = dest;
+ }
}
return retval;
}
/* Scan the requested alternative for 'm' or 'o'.
If one of them is present, this alternative accepts memory constants. */
- while ((c = *constraint++) && c != ',' && c != '#')
- if (c == 'm' || c == 'o' || EXTRA_MEMORY_CONSTRAINT (c))
+ for (; (c = *constraint) && c != ',' && c != '#';
+ constraint += CONSTRAINT_LEN (c, constraint))
+ if (c == 'm' || c == 'o' || EXTRA_MEMORY_CONSTRAINT (c, constraint))
return 1;
return 0;
}
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
+ if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0)
{
tem =
return tem;
}
+/* Returns true if AD could be turned into a valid memory reference
+ to mode MODE by reloading the part pointed to by PART into a
+ register. */
+
+static int
+maybe_memory_address_p (mode, ad, part)
+ enum machine_mode mode;
+ rtx ad;
+ rtx *part;
+{
+ int retv;
+ rtx tem = *part;
+ rtx reg = gen_rtx_REG (GET_MODE (tem), max_reg_num ());
+
+ *part = reg;
+ retv = memory_address_p (mode, ad);
+ *part = tem;
+
+ return retv;
+}
+
/* Record all reloads needed for handling memory address AD
which appears in *LOC in a memory reference to mode MODE
which itself is found in location *MEMREFLOC.
that the index needs a reload and find_reloads_address_1 will take care
of it.
- If we decide to do something here, it must be that
- `double_reg_address_ok' is true and that this address rtl was made by
- eliminate_regs. We generate a reload of the fp/sp/ap + constant and
+ Handle all base registers here, not just fp/ap/sp, because on some
+ targets (namely Sparc) we can also get invalid addresses from preventive
+ subreg big-endian corrections made by find_reloads_toplev.
+
+ If we decide to do something, it must be that `double_reg_address_ok'
+ is true. We generate a reload of the base register + constant and
rework the sum so that the reload register will be added to the index.
This is safe because we know the address isn't shared.
- We check for fp/ap/sp as both the first and second operand of the
- innermost PLUS. */
+ We check for the base register as both the first and second operand of
+ the innermost PLUS. */
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))
+ && GET_CODE (XEXP (XEXP (ad, 0), 0)) == REG
+ && REGNO (XEXP (XEXP (ad, 0), 0)) < FIRST_PSEUDO_REGISTER
+ && REG_MODE_OK_FOR_BASE_P (XEXP (XEXP (ad, 0), 0), mode)
+ && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 1)))
{
*loc = ad = gen_rtx_PLUS (GET_MODE (ad),
plus_constant (XEXP (XEXP (ad, 0), 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))
+ && GET_CODE (XEXP (XEXP (ad, 0), 1)) == REG
+ && REGNO (XEXP (XEXP (ad, 0), 1)) < FIRST_PSEUDO_REGISTER
+ && REG_MODE_OK_FOR_BASE_P (XEXP (XEXP (ad, 0), 1), mode)
+ && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 0)))
{
*loc = ad = gen_rtx_PLUS (GET_MODE (ad),
XEXP (XEXP (ad, 0), 0),
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_INC
- && REGNO (XEXP (link, 0)) == regno)
+ && (int) REGNO (XEXP (link, 0)) == regno)
push_replacement (&XEXP (link, 0), reloadnum, VOIDmode);
#endif
}
SUBREG_BYTE (orig_op1),
GET_MODE (orig_op1))));
}
+ /* Plus in the index register may be created only as a result of
+ register remateralization for expresion like &localvar*4. Reload it.
+ It may be possible to combine the displacement on the outer level,
+ but it is probably not worthwhile to do so. */
+ if (context)
+ {
+ 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, (rtx*) 0,
+ (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)),
+ GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+ return 1;
+ }
if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
|| code0 == ZERO_EXTEND || code1 == MEM)
needless copies if SUBREG_REG is multi-word. */
if (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
{
- int regno = subreg_regno (x);
+ int regno ATTRIBUTE_UNUSED = subreg_regno (x);
if (! (context ? REGNO_OK_FOR_INDEX_P (regno)
: REGNO_MODE_OK_FOR_BASE_P (regno, mode)))
do the wrong thing if RELOADREG is multi-word. RELOADREG
will always be a REG here. */
if (GET_MODE (reloadreg) != r->mode && r->mode != VOIDmode)
- reloadreg = gen_rtx_REG (r->mode, REGNO (reloadreg));
+ reloadreg = reload_adjust_reg_for_mode (reloadreg, r->mode);
/* If we are putting this into a SUBREG and RELOADREG is a
SUBREG, we would be making nested SUBREGs, so we have to fix
}
}
-/* Change any replacements being done to *X to be done to *Y */
+/* Change any replacements being done to *X to be done to *Y. */
void
move_replacements (x, y)
return 0;
}
+/* Find the low part, with mode MODE, of a hard regno RELOADREG. */
+rtx
+reload_adjust_reg_for_mode (reloadreg, mode)
+ rtx reloadreg;
+ enum machine_mode mode;
+{
+ int regno;
+
+ if (GET_MODE (reloadreg) == mode)
+ return reloadreg;
+
+ regno = REGNO (reloadreg);
+
+ if (WORDS_BIG_ENDIAN)
+ regno += HARD_REGNO_NREGS (regno, GET_MODE (reloadreg))
+ - HARD_REGNO_NREGS (regno, mode);
+
+ return gen_rtx_REG (mode, regno);
+}
+
static const char *const reload_when_needed_name[] =
{
"RELOAD_FOR_INPUT",