/* 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"
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;
if (in != 0 && GET_CODE (in) == SUBREG
&& (subreg_lowpart_p (in) || strict_low)
#ifdef CANNOT_CHANGE_MODE_CLASS
- && !reg_classes_intersect_p
- (class, CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)),
- inmode))
+ && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)), inmode, class)
#endif
&& (CONSTANT_P (SUBREG_REG (in))
|| GET_CODE (SUBREG_REG (in)) == PLUS
if (out != 0 && GET_CODE (out) == SUBREG
&& (subreg_lowpart_p (out) || strict_low)
#ifdef CANNOT_CHANGE_MODE_CLASS
- && !reg_classes_intersect_p
- (class, CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)),
- outmode))
+ && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)), outmode, class)
#endif
&& (CONSTANT_P (SUBREG_REG (out))
|| strict_low
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
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
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
the address into a base register. */
this_alternative[i] = (int) MODE_BASE_REG_CLASS (VOIDmode);
badop = 0;
-
- /* Address constraints are reloaded in Pmode, no matter
- what mode is given in the machine description. */
- operand_mode[i] = Pmode;
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
}
/* 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;
}
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.
|| XEXP (XEXP (ad, 0), 0) == arg_pointer_rtx
#endif
|| XEXP (XEXP (ad, 0), 0) == stack_pointer_rtx)
- && ! memory_address_p (mode, ad))
+ && ! 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),
|| XEXP (XEXP (ad, 0), 1) == arg_pointer_rtx
#endif
|| XEXP (XEXP (ad, 0), 1) == stack_pointer_rtx)
- && ! memory_address_p (mode, ad))
+ && ! 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
}
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)))