Commit b5068425 by Andreas Krebbel Committed by Andreas Krebbel

reload.c (find_reloads): Change the loop nesting when trying an alternative with swapped operands.

2012-04-26  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	* reload.c (find_reloads): Change the loop nesting when trying an
	alternative with swapped operands.

From-SVN: r186861
parent 1d72e96f
2012-04-26 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
* reload.c (find_reloads): Change the loop nesting when trying an
alternative with swapped operands.
2012-04-26 Manuel López-Ibáñez <manu@gcc.gnu.org> 2012-04-26 Manuel López-Ibáñez <manu@gcc.gnu.org>
* tree-diagnostic.c (maybe_unwind_expanded_macro_loc): Fix * tree-diagnostic.c (maybe_unwind_expanded_macro_loc): Fix
......
...@@ -2592,7 +2592,6 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, ...@@ -2592,7 +2592,6 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
char this_alternative_offmemok[MAX_RECOG_OPERANDS]; char this_alternative_offmemok[MAX_RECOG_OPERANDS];
char this_alternative_earlyclobber[MAX_RECOG_OPERANDS]; char this_alternative_earlyclobber[MAX_RECOG_OPERANDS];
int this_alternative_matches[MAX_RECOG_OPERANDS]; int this_alternative_matches[MAX_RECOG_OPERANDS];
int swapped;
reg_class_t goal_alternative[MAX_RECOG_OPERANDS]; reg_class_t goal_alternative[MAX_RECOG_OPERANDS];
int this_alternative_number; int this_alternative_number;
int goal_alternative_number = 0; int goal_alternative_number = 0;
...@@ -2938,9 +2937,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, ...@@ -2938,9 +2937,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
best = MAX_RECOG_OPERANDS * 2 + 600; best = MAX_RECOG_OPERANDS * 2 + 600;
swapped = 0;
goal_alternative_swapped = 0; goal_alternative_swapped = 0;
try_swapped:
/* The constraints are made of several alternatives. /* The constraints are made of several alternatives.
Each operand's constraint looks like foo,bar,... with commas Each operand's constraint looks like foo,bar,... with commas
...@@ -2953,20 +2950,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, ...@@ -2953,20 +2950,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
this_alternative_number < n_alternatives; this_alternative_number < n_alternatives;
this_alternative_number++) this_alternative_number++)
{ {
/* Loop over operands for one constraint alternative. */ int swapped;
/* LOSERS counts those that don't fit this alternative
and would require loading. */
int losers = 0;
/* BAD is set to 1 if it some operand can't fit this alternative
even after reloading. */
int bad = 0;
/* REJECT is a count of how undesirable this alternative says it is
if any reloading is required. If the alternative matches exactly
then REJECT is ignored, but otherwise it gets this much
counted against it in addition to the reloading needed. Each
? counts three times here since we want the disparaging caused by
a bad register class to only count 1/3 as much. */
int reject = 0;
if (!recog_data.alternative_enabled_p[this_alternative_number]) if (!recog_data.alternative_enabled_p[this_alternative_number])
{ {
...@@ -2978,825 +2962,854 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, ...@@ -2978,825 +2962,854 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
continue; continue;
} }
this_earlyclobber = 0; /* If insn is commutative (it's safe to exchange a certain pair
of operands) then we need to try each alternative twice, the
for (i = 0; i < noperands; i++) second time matching those two operands as if we had
exchanged them. To do this, really exchange them in
operands. */
for (swapped = 0; swapped < (commutative >= 0 ? 2 : 1); swapped++)
{ {
const char *p = constraints[i]; /* Loop over operands for one constraint alternative. */
char *end; /* LOSERS counts those that don't fit this alternative
int len; and would require loading. */
int win = 0; int losers = 0;
int did_match = 0; /* BAD is set to 1 if it some operand can't fit this alternative
/* 0 => this operand can be reloaded somehow for this alternative. */ even after reloading. */
int badop = 1; int bad = 0;
/* 0 => this operand can be reloaded if the alternative allows regs. */ /* REJECT is a count of how undesirable this alternative says it is
int winreg = 0; if any reloading is required. If the alternative matches exactly
int c; then REJECT is ignored, but otherwise it gets this much
int m; counted against it in addition to the reloading needed. Each
rtx operand = recog_data.operand[i]; ? counts three times here since we want the disparaging caused by
int offset = 0; a bad register class to only count 1/3 as much. */
/* Nonzero means this is a MEM that must be reloaded into a reg int reject = 0;
regardless of what the constraint says. */
int force_reload = 0; if (swapped)
int offmemok = 0; {
/* Nonzero if a constant forced into memory would be OK for this enum reg_class tclass;
operand. */ int t;
int constmemok = 0;
int earlyclobber = 0; recog_data.operand[commutative] = substed_operand[commutative + 1];
recog_data.operand[commutative + 1] = substed_operand[commutative];
/* If the predicate accepts a unary operator, it means that /* Swap the duplicates too. */
we need to reload the operand, but do not do this for for (i = 0; i < recog_data.n_dups; i++)
match_operator and friends. */ if (recog_data.dup_num[i] == commutative
if (UNARY_P (operand) && *p != 0) || recog_data.dup_num[i] == commutative + 1)
operand = XEXP (operand, 0); *recog_data.dup_loc[i]
= recog_data.operand[(int) recog_data.dup_num[i]];
/* If the operand is a SUBREG, extract
the REG or MEM (or maybe even a constant) within. tclass = preferred_class[commutative];
(Constants can occur as a result of reg_equiv_constant.) */ preferred_class[commutative] = preferred_class[commutative + 1];
preferred_class[commutative + 1] = tclass;
while (GET_CODE (operand) == SUBREG)
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;
}
this_earlyclobber = 0;
for (i = 0; i < noperands; i++)
{ {
/* Offset only matters when operand is a REG and const char *p = constraints[i];
it is a hard reg. This is because it is passed char *end;
to reg_fits_class_p if it is a REG and all pseudos int len;
return 0 from that function. */ int win = 0;
if (REG_P (SUBREG_REG (operand)) int did_match = 0;
&& REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER) /* 0 => this operand can be reloaded somehow for this alternative. */
int badop = 1;
/* 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
regardless of what the constraint says. */
int force_reload = 0;
int offmemok = 0;
/* Nonzero if a constant forced into memory would be OK for this
operand. */
int constmemok = 0;
int earlyclobber = 0;
/* If the predicate accepts a unary operator, it means that
we need to reload the operand, but do not do this for
match_operator and friends. */
if (UNARY_P (operand) && *p != 0)
operand = XEXP (operand, 0);
/* If the operand is a SUBREG, extract
the REG or MEM (or maybe even a constant) within.
(Constants can occur as a result of reg_equiv_constant.) */
while (GET_CODE (operand) == SUBREG)
{ {
if (simplify_subreg_regno (REGNO (SUBREG_REG (operand)), /* Offset only matters when operand is a REG and
GET_MODE (SUBREG_REG (operand)), it is a hard reg. This is because it is passed
SUBREG_BYTE (operand), to reg_fits_class_p if it is a REG and all pseudos
GET_MODE (operand)) < 0) return 0 from that function. */
force_reload = 1; if (REG_P (SUBREG_REG (operand))
offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)), && REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER)
{
if (simplify_subreg_regno (REGNO (SUBREG_REG (operand)),
GET_MODE (SUBREG_REG (operand)), GET_MODE (SUBREG_REG (operand)),
SUBREG_BYTE (operand), SUBREG_BYTE (operand),
GET_MODE (operand)); GET_MODE (operand)) < 0)
} force_reload = 1;
operand = SUBREG_REG (operand); offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)),
/* Force reload if this is a constant or PLUS or if there may GET_MODE (SUBREG_REG (operand)),
be a problem accessing OPERAND in the outer mode. */ SUBREG_BYTE (operand),
if (CONSTANT_P (operand) GET_MODE (operand));
|| GET_CODE (operand) == PLUS }
/* We must force a reload of paradoxical SUBREGs operand = SUBREG_REG (operand);
of a MEM because the alignment of the inner value /* Force reload if this is a constant or PLUS or if there may
may not be enough to do the outer reference. On be a problem accessing OPERAND in the outer mode. */
big-endian machines, it may also reference outside if (CONSTANT_P (operand)
the object. || GET_CODE (operand) == PLUS
/* We must force a reload of paradoxical SUBREGs
On machines that extend byte operations and we have a of a MEM because the alignment of the inner value
SUBREG where both the inner and outer modes are no wider may not be enough to do the outer reference. On
than a word and the inner mode is narrower, is integral, big-endian machines, it may also reference outside
and gets extended when loaded from memory, combine.c has the object.
made assumptions about the behavior of the machine in such
register access. If the data is, in fact, in memory we On machines that extend byte operations and we have a
must always load using the size assumed to be in the SUBREG where both the inner and outer modes are no wider
register and let the insn do the different-sized than a word and the inner mode is narrower, is integral,
accesses. and gets extended when loaded from memory, combine.c has
made assumptions about the behavior of the machine in such
This is doubly true if WORD_REGISTER_OPERATIONS. In register access. If the data is, in fact, in memory we
this case eliminate_regs has left non-paradoxical must always load using the size assumed to be in the
subregs for push_reload to see. Make sure it does register and let the insn do the different-sized
by forcing the reload. accesses.
??? When is it right at this stage to have a subreg This is doubly true if WORD_REGISTER_OPERATIONS. In
of a mem that is _not_ to be handled specially? IMO this case eliminate_regs has left non-paradoxical
those should have been reduced to just a mem. */ subregs for push_reload to see. Make sure it does
|| ((MEM_P (operand) by forcing the reload.
|| (REG_P (operand)
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER)) ??? When is it right at this stage to have a subreg
of a mem that is _not_ to be handled specially? IMO
those should have been reduced to just a mem. */
|| ((MEM_P (operand)
|| (REG_P (operand)
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER))
#ifndef WORD_REGISTER_OPERATIONS #ifndef WORD_REGISTER_OPERATIONS
&& (((GET_MODE_BITSIZE (GET_MODE (operand)) && (((GET_MODE_BITSIZE (GET_MODE (operand))
< BIGGEST_ALIGNMENT) < BIGGEST_ALIGNMENT)
&& (GET_MODE_SIZE (operand_mode[i]) && (GET_MODE_SIZE (operand_mode[i])
> GET_MODE_SIZE (GET_MODE (operand)))) > GET_MODE_SIZE (GET_MODE (operand))))
|| BYTES_BIG_ENDIAN || BYTES_BIG_ENDIAN
#ifdef LOAD_EXTEND_OP #ifdef LOAD_EXTEND_OP
|| (GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD || (GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
&& (GET_MODE_SIZE (GET_MODE (operand)) && (GET_MODE_SIZE (GET_MODE (operand))
<= UNITS_PER_WORD) <= UNITS_PER_WORD)
&& (GET_MODE_SIZE (operand_mode[i]) && (GET_MODE_SIZE (operand_mode[i])
> GET_MODE_SIZE (GET_MODE (operand))) > GET_MODE_SIZE (GET_MODE (operand)))
&& INTEGRAL_MODE_P (GET_MODE (operand)) && INTEGRAL_MODE_P (GET_MODE (operand))
&& LOAD_EXTEND_OP (GET_MODE (operand)) != UNKNOWN) && LOAD_EXTEND_OP (GET_MODE (operand)) != UNKNOWN)
#endif #endif
) )
#endif #endif
)
) )
) force_reload = 1;
force_reload = 1; }
}
this_alternative[i] = NO_REGS; this_alternative[i] = NO_REGS;
this_alternative_win[i] = 0; this_alternative_win[i] = 0;
this_alternative_match_win[i] = 0; this_alternative_match_win[i] = 0;
this_alternative_offmemok[i] = 0; this_alternative_offmemok[i] = 0;
this_alternative_earlyclobber[i] = 0; this_alternative_earlyclobber[i] = 0;
this_alternative_matches[i] = -1; this_alternative_matches[i] = -1;
/* An empty constraint or empty alternative /* An empty constraint or empty alternative
allows anything which matched the pattern. */ allows anything which matched the pattern. */
if (*p == 0 || *p == ',') if (*p == 0 || *p == ',')
win = 1, badop = 0; win = 1, badop = 0;
/* Scan this alternative's specs for this operand; /* Scan this alternative's specs for this operand;
set WIN if the operand fits any letter in this alternative. set WIN if the operand fits any letter in this alternative.
Otherwise, clear BADOP if this operand could Otherwise, clear BADOP if this operand could
fit some letter after reloads, fit some letter after reloads,
or set WINREG if this operand could fit after reloads or set WINREG if this operand could fit after reloads
provided the constraint allows some registers. */ provided the constraint allows some registers. */
do do
switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c) switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c)
{ {
case '\0': case '\0':
len = 0; len = 0;
break; break;
case ',': case ',':
c = '\0'; c = '\0';
break; break;
case '=': case '+': case '*': case '=': case '+': case '*':
break; break;
case '%': case '%':
/* We only support one commutative marker, the first /* We only support one commutative marker, the first
one. We already set commutative above. */ one. We already set commutative above. */
break; break;
case '?': case '?':
reject += 6; reject += 6;
break; break;
case '!': case '!':
reject = 600; reject = 600;
break; break;
case '#': case '#':
/* Ignore rest of this alternative as far as /* Ignore rest of this alternative as far as
reloading is concerned. */ reloading is concerned. */
do do
p++; p++;
while (*p && *p != ','); while (*p && *p != ',');
len = 0; len = 0;
break; break;
case '0': case '1': case '2': case '3': case '4': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': case '5': case '6': case '7': case '8': case '9':
m = strtoul (p, &end, 10); m = strtoul (p, &end, 10);
p = end; p = end;
len = 0; len = 0;
this_alternative_matches[i] = m; this_alternative_matches[i] = m;
/* We are supposed to match a previous operand. /* We are supposed to match a previous operand.
If we do, we win if that one did. If we do, we win if that one did.
If we do not, count both of the operands as losers. If we do not, count both of the operands as losers.
(This is too conservative, since most of the time (This is too conservative, since most of the time
only a single reload insn will be needed to make only a single reload insn will be needed to make
the two operands win. As a result, this alternative the two operands win. As a result, this alternative
may be rejected when it is actually desirable.) */ may be rejected when it is actually desirable.) */
if ((swapped && (m != commutative || i != commutative + 1)) if ((swapped && (m != commutative || i != commutative + 1))
/* If we are matching as if two operands were swapped, /* If we are matching as if two operands were swapped,
also pretend that operands_match had been computed also pretend that operands_match had been computed
with swapped. with swapped.
But if I is the second of those and C is the first, But if I is the second of those and C is the first,
don't exchange them, because operands_match is valid don't exchange them, because operands_match is valid
only on one side of its diagonal. */ only on one side of its diagonal. */
? (operands_match ? (operands_match
[(m == commutative || m == commutative + 1) [(m == commutative || m == commutative + 1)
? 2 * commutative + 1 - m : m] ? 2 * commutative + 1 - m : m]
[(i == commutative || i == commutative + 1) [(i == commutative || i == commutative + 1)
? 2 * commutative + 1 - i : i]) ? 2 * commutative + 1 - i : i])
: operands_match[m][i]) : operands_match[m][i])
{ {
/* If we are matching a non-offsettable address where an /* If we are matching a non-offsettable address where an
offsettable address was expected, then we must reject offsettable address was expected, then we must reject
this combination, because we can't reload it. */ this combination, because we can't reload it. */
if (this_alternative_offmemok[m] if (this_alternative_offmemok[m]
&& MEM_P (recog_data.operand[m]) && MEM_P (recog_data.operand[m])
&& this_alternative[m] == NO_REGS && this_alternative[m] == NO_REGS
&& ! this_alternative_win[m]) && ! this_alternative_win[m])
bad = 1; bad = 1;
did_match = this_alternative_win[m]; did_match = this_alternative_win[m];
} }
else
{
/* Operands don't match. */
rtx value;
int loc1, loc2;
/* Retroactively mark the operand we had to match
as a loser, if it wasn't already. */
if (this_alternative_win[m])
losers++;
this_alternative_win[m] = 0;
if (this_alternative[m] == 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.
The pointers in operand_loc are not swapped; swap
them by hand if necessary. */
if (swapped && i == commutative)
loc1 = commutative + 1;
else if (swapped && i == commutative + 1)
loc1 = commutative;
else
loc1 = i;
if (swapped && m == commutative)
loc2 = commutative + 1;
else if (swapped && m == commutative + 1)
loc2 = commutative;
else else
loc2 = m; {
value /* Operands don't match. */
= find_dummy_reload (recog_data.operand[i], rtx value;
recog_data.operand[m], int loc1, loc2;
recog_data.operand_loc[loc1], /* Retroactively mark the operand we had to match
recog_data.operand_loc[loc2], as a loser, if it wasn't already. */
operand_mode[i], operand_mode[m], if (this_alternative_win[m])
this_alternative[m], -1, losers++;
this_alternative_earlyclobber[m]); this_alternative_win[m] = 0;
if (this_alternative[m] == NO_REGS)
if (value != 0) bad = 1;
losers--; /* But count the pair only once in the total badness of
} this alternative, if the pair can be a dummy reload.
/* This can be fixed with reloads if the operand The pointers in operand_loc are not swapped; swap
we are supposed to match can be fixed with reloads. */ them by hand if necessary. */
badop = 0; if (swapped && i == commutative)
this_alternative[i] = this_alternative[m]; loc1 = commutative + 1;
else if (swapped && i == commutative + 1)
/* If we have to reload this operand and some previous loc1 = commutative;
operand also had to match the same thing as this else
operand, we don't know how to do that. So reject this loc1 = i;
alternative. */ if (swapped && m == commutative)
if (! did_match || force_reload) loc2 = commutative + 1;
for (j = 0; j < i; j++) else if (swapped && m == commutative + 1)
if (this_alternative_matches[j] loc2 = commutative;
== this_alternative_matches[i]) else
badop = 1; loc2 = m;
break; value
= find_dummy_reload (recog_data.operand[i],
recog_data.operand[m],
recog_data.operand_loc[loc1],
recog_data.operand_loc[loc2],
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[m];
/* If we have to reload this operand and some previous
operand also had to match the same thing as this
operand, we don't know how to do that. So reject this
alternative. */
if (! did_match || force_reload)
for (j = 0; j < i; j++)
if (this_alternative_matches[j]
== this_alternative_matches[i])
badop = 1;
break;
case 'p': case 'p':
/* All necessary reloads for an address_operand /* All necessary reloads for an address_operand
were handled in find_reloads_address. */ were handled in find_reloads_address. */
this_alternative[i] this_alternative[i]
= base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
ADDRESS, SCRATCH); ADDRESS, SCRATCH);
win = 1; win = 1;
badop = 0; badop = 0;
break; break;
case TARGET_MEM_CONSTRAINT: case TARGET_MEM_CONSTRAINT:
if (force_reload) if (force_reload)
break; break;
if (MEM_P (operand) if (MEM_P (operand)
|| (REG_P (operand) || (REG_P (operand)
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER && REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (operand)] < 0)) && reg_renumber[REGNO (operand)] < 0))
win = 1; win = 1;
if (CONST_POOL_OK_P (operand_mode[i], operand)) if (CONST_POOL_OK_P (operand_mode[i], operand))
badop = 0; badop = 0;
constmemok = 1; constmemok = 1;
break; break;
case '<': case '<':
if (MEM_P (operand) if (MEM_P (operand)
&& ! address_reloaded[i] && ! address_reloaded[i]
&& (GET_CODE (XEXP (operand, 0)) == PRE_DEC && (GET_CODE (XEXP (operand, 0)) == PRE_DEC
|| GET_CODE (XEXP (operand, 0)) == POST_DEC)) || GET_CODE (XEXP (operand, 0)) == POST_DEC))
win = 1; win = 1;
break; break;
case '>': case '>':
if (MEM_P (operand) if (MEM_P (operand)
&& ! address_reloaded[i] && ! address_reloaded[i]
&& (GET_CODE (XEXP (operand, 0)) == PRE_INC && (GET_CODE (XEXP (operand, 0)) == PRE_INC
|| GET_CODE (XEXP (operand, 0)) == POST_INC)) || GET_CODE (XEXP (operand, 0)) == POST_INC))
win = 1; win = 1;
break; break;
/* Memory operand whose address is not offsettable. */ /* Memory operand whose address is not offsettable. */
case 'V': case 'V':
if (force_reload) if (force_reload)
break; break;
if (MEM_P (operand) if (MEM_P (operand)
&& ! (ind_levels ? offsettable_memref_p (operand) && ! (ind_levels ? offsettable_memref_p (operand)
: offsettable_nonstrict_memref_p (operand)) : offsettable_nonstrict_memref_p (operand))
/* Certain mem addresses will become offsettable /* Certain mem addresses will become offsettable
after they themselves are reloaded. This is important; after they themselves are reloaded. This is important;
we don't want our own handling of unoffsettables we don't want our own handling of unoffsettables
to override the handling of reg_equiv_address. */ to override the handling of reg_equiv_address. */
&& !(REG_P (XEXP (operand, 0)) && !(REG_P (XEXP (operand, 0))
&& (ind_levels == 0 && (ind_levels == 0
|| reg_equiv_address (REGNO (XEXP (operand, 0))) != 0))) || reg_equiv_address (REGNO (XEXP (operand, 0))) != 0)))
win = 1; win = 1;
break; break;
/* Memory operand whose address is offsettable. */ /* Memory operand whose address is offsettable. */
case 'o': case 'o':
if (force_reload) if (force_reload)
break; break;
if ((MEM_P (operand) if ((MEM_P (operand)
/* If IND_LEVELS, find_reloads_address won't reload a /* If IND_LEVELS, find_reloads_address won't reload a
pseudo that didn't get a hard reg, so we have to pseudo that didn't get a hard reg, so we have to
reject that case. */ reject that case. */
&& ((ind_levels ? offsettable_memref_p (operand) && ((ind_levels ? offsettable_memref_p (operand)
: offsettable_nonstrict_memref_p (operand)) : offsettable_nonstrict_memref_p (operand))
/* A reloaded address is offsettable because it is now /* A reloaded address is offsettable because it is now
just a simple register indirect. */ just a simple register indirect. */
|| address_reloaded[i] == 1)) || address_reloaded[i] == 1))
|| (REG_P (operand) || (REG_P (operand)
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER && REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (operand)] < 0 && reg_renumber[REGNO (operand)] < 0
/* If reg_equiv_address is nonzero, we will be /* If reg_equiv_address is nonzero, we will be
loading it into a register; hence it will be loading it into a register; hence it will be
offsettable, but we cannot say that reg_equiv_mem offsettable, but we cannot say that reg_equiv_mem
is offsettable without checking. */ is offsettable without checking. */
&& ((reg_equiv_mem (REGNO (operand)) != 0 && ((reg_equiv_mem (REGNO (operand)) != 0
&& offsettable_memref_p (reg_equiv_mem (REGNO (operand)))) && offsettable_memref_p (reg_equiv_mem (REGNO (operand))))
|| (reg_equiv_address (REGNO (operand)) != 0)))) || (reg_equiv_address (REGNO (operand)) != 0))))
win = 1; win = 1;
if (CONST_POOL_OK_P (operand_mode[i], operand) if (CONST_POOL_OK_P (operand_mode[i], operand)
|| MEM_P (operand)) || MEM_P (operand))
badop = 0; badop = 0;
constmemok = 1; constmemok = 1;
offmemok = 1; offmemok = 1;
break; break;
case '&': case '&':
/* Output operand that is stored before the need for the /* Output operand that is stored before the need for the
input operands (and their index registers) is over. */ input operands (and their index registers) is over. */
earlyclobber = 1, this_earlyclobber = 1; earlyclobber = 1, this_earlyclobber = 1;
break; break;
case 'E': case 'E':
case 'F': case 'F':
if (GET_CODE (operand) == CONST_DOUBLE if (GET_CODE (operand) == CONST_DOUBLE
|| (GET_CODE (operand) == CONST_VECTOR || (GET_CODE (operand) == CONST_VECTOR
&& (GET_MODE_CLASS (GET_MODE (operand)) && (GET_MODE_CLASS (GET_MODE (operand))
== MODE_VECTOR_FLOAT))) == MODE_VECTOR_FLOAT)))
win = 1; win = 1;
break; break;
case 'G': case 'G':
case 'H': case 'H':
if (GET_CODE (operand) == CONST_DOUBLE if (GET_CODE (operand) == CONST_DOUBLE
&& CONST_DOUBLE_OK_FOR_CONSTRAINT_P (operand, c, p)) && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (operand, c, p))
win = 1; win = 1;
break; break;
case 's': case 's':
if (CONST_INT_P (operand) if (CONST_INT_P (operand)
|| (GET_CODE (operand) == CONST_DOUBLE || (GET_CODE (operand) == CONST_DOUBLE
&& GET_MODE (operand) == VOIDmode)) && GET_MODE (operand) == VOIDmode))
break; break;
case 'i': case 'i':
if (CONSTANT_P (operand) if (CONSTANT_P (operand)
&& (! flag_pic || LEGITIMATE_PIC_OPERAND_P (operand))) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (operand)))
win = 1; win = 1;
break; break;
case 'n': case 'n':
if (CONST_INT_P (operand) if (CONST_INT_P (operand)
|| (GET_CODE (operand) == CONST_DOUBLE || (GET_CODE (operand) == CONST_DOUBLE
&& GET_MODE (operand) == VOIDmode)) && GET_MODE (operand) == VOIDmode))
win = 1; win = 1;
break; break;
case 'I': case 'I':
case 'J': case 'J':
case 'K': case 'K':
case 'L': case 'L':
case 'M': case 'M':
case 'N': case 'N':
case 'O': case 'O':
case 'P': case 'P':
if (CONST_INT_P (operand) if (CONST_INT_P (operand)
&& CONST_OK_FOR_CONSTRAINT_P (INTVAL (operand), c, p)) && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operand), c, p))
win = 1; win = 1;
break; break;
case 'X': case 'X':
force_reload = 0; force_reload = 0;
win = 1; win = 1;
break; break;
case 'g': case 'g':
if (! force_reload if (! force_reload
/* A PLUS is never a valid operand, but reload can make /* A PLUS is never a valid operand, but reload can make
it from a register when eliminating registers. */ it from a register when eliminating registers. */
&& GET_CODE (operand) != PLUS && GET_CODE (operand) != PLUS
/* A SCRATCH is not a valid operand. */ /* A SCRATCH is not a valid operand. */
&& GET_CODE (operand) != SCRATCH && GET_CODE (operand) != SCRATCH
&& (! CONSTANT_P (operand) && (! CONSTANT_P (operand)
|| ! flag_pic || ! flag_pic
|| LEGITIMATE_PIC_OPERAND_P (operand)) || LEGITIMATE_PIC_OPERAND_P (operand))
&& (GENERAL_REGS == ALL_REGS && (GENERAL_REGS == ALL_REGS
|| !REG_P (operand) || !REG_P (operand)
|| (REGNO (operand) >= FIRST_PSEUDO_REGISTER || (REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (operand)] < 0))) && reg_renumber[REGNO (operand)] < 0)))
win = 1; win = 1;
/* Drop through into 'r' case. */ /* Drop through into 'r' case. */
case 'r':
this_alternative[i]
= reg_class_subunion[this_alternative[i]][(int) GENERAL_REGS];
goto reg;
default: case 'r':
if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS) this_alternative[i]
{ = reg_class_subunion[this_alternative[i]][(int) GENERAL_REGS];
#ifdef EXTRA_CONSTRAINT_STR goto reg;
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 default:
constants via force_const_mem, and other if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS)
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)) #ifdef EXTRA_CONSTRAINT_STR
win = 1; if (EXTRA_MEMORY_CONSTRAINT (c, p))
{
/* If we didn't already win, we can reload if (force_reload)
the address into a base register. */ break;
this_alternative[i] if (EXTRA_CONSTRAINT_STR (operand, c, p))
= base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, win = 1;
ADDRESS, SCRATCH); /* If the address was already reloaded,
badop = 0; 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;
}
if (EXTRA_CONSTRAINT_STR (operand, c, p))
win = 1;
#endif
break; break;
} }
if (EXTRA_CONSTRAINT_STR (operand, c, p)) this_alternative[i]
= (reg_class_subunion
[this_alternative[i]]
[(int) REG_CLASS_FROM_CONSTRAINT (c, p)]);
reg:
if (GET_MODE (operand) == BLKmode)
break;
winreg = 1;
if (REG_P (operand)
&& reg_fits_class_p (operand, this_alternative[i],
offset, GET_MODE (recog_data.operand[i])))
win = 1; win = 1;
#endif
break; break;
} }
while ((p += len), c);
this_alternative[i] if (swapped == (commutative >= 0 ? 1 : 0))
= (reg_class_subunion constraints[i] = p;
[this_alternative[i]]
[(int) REG_CLASS_FROM_CONSTRAINT (c, p)]);
reg:
if (GET_MODE (operand) == BLKmode)
break;
winreg = 1;
if (REG_P (operand)
&& reg_fits_class_p (operand, this_alternative[i],
offset, GET_MODE (recog_data.operand[i])))
win = 1;
break;
}
while ((p += len), c);
constraints[i] = p;
/* If this operand could be handled with a reg,
and some reg is allowed, then this operand can be handled. */
if (winreg && this_alternative[i] != NO_REGS
&& (win || !class_only_fixed_regs[this_alternative[i]]))
badop = 0;
/* Record which operands fit this alternative. */
this_alternative_earlyclobber[i] = earlyclobber;
if (win && ! force_reload)
this_alternative_win[i] = 1;
else if (did_match && ! force_reload)
this_alternative_match_win[i] = 1;
else
{
int const_to_mem = 0;
this_alternative_offmemok[i] = offmemok;
losers++;
if (badop)
bad = 1;
/* Alternative loses if it has no regs for a reg operand. */
if (REG_P (operand)
&& this_alternative[i] == NO_REGS
&& this_alternative_matches[i] < 0)
bad = 1;
/* If this is a constant that is reloaded into the desired
class by copying it to memory first, count that as another
reload. This is consistent with other code and is
required to avoid choosing another alternative when
the constant is moved into memory by this function on
an early reload pass. Note that the test here is
precisely the same as in the code below that calls
force_const_mem. */
if (CONST_POOL_OK_P (operand_mode[i], operand)
&& ((targetm.preferred_reload_class (operand,
this_alternative[i])
== NO_REGS)
|| no_input_reloads))
{
const_to_mem = 1;
if (this_alternative[i] != NO_REGS)
losers++;
}
/* Alternative loses if it requires a type of reload not /* If this operand could be handled with a reg,
permitted for this insn. We can always reload SCRATCH and some reg is allowed, then this operand can be handled. */
and objects with a REG_UNUSED note. */ if (winreg && this_alternative[i] != NO_REGS
if (GET_CODE (operand) != SCRATCH && (win || !class_only_fixed_regs[this_alternative[i]]))
&& modified[i] != RELOAD_READ && no_output_reloads badop = 0;
&& ! find_reg_note (insn, REG_UNUSED, operand))
bad = 1; /* Record which operands fit this alternative. */
else if (modified[i] != RELOAD_WRITE && no_input_reloads this_alternative_earlyclobber[i] = earlyclobber;
&& ! const_to_mem) if (win && ! force_reload)
bad = 1; this_alternative_win[i] = 1;
else if (did_match && ! force_reload)
/* If we can't reload this value at all, reject this this_alternative_match_win[i] = 1;
alternative. Note that we could also lose due to else
LIMIT_RELOAD_CLASS, but we don't check that
here. */
if (! CONSTANT_P (operand) && this_alternative[i] != NO_REGS)
{ {
if (targetm.preferred_reload_class (operand, this_alternative[i]) int const_to_mem = 0;
== NO_REGS)
reject = 600; this_alternative_offmemok[i] = offmemok;
losers++;
if (badop)
bad = 1;
/* Alternative loses if it has no regs for a reg operand. */
if (REG_P (operand)
&& this_alternative[i] == NO_REGS
&& this_alternative_matches[i] < 0)
bad = 1;
/* If this is a constant that is reloaded into the desired
class by copying it to memory first, count that as another
reload. This is consistent with other code and is
required to avoid choosing another alternative when
the constant is moved into memory by this function on
an early reload pass. Note that the test here is
precisely the same as in the code below that calls
force_const_mem. */
if (CONST_POOL_OK_P (operand_mode[i], operand)
&& ((targetm.preferred_reload_class (operand,
this_alternative[i])
== NO_REGS)
|| no_input_reloads))
{
const_to_mem = 1;
if (this_alternative[i] != NO_REGS)
losers++;
}
if (operand_type[i] == RELOAD_FOR_OUTPUT /* Alternative loses if it requires a type of reload not
&& (targetm.preferred_output_reload_class (operand, permitted for this insn. We can always reload SCRATCH
this_alternative[i]) and objects with a REG_UNUSED note. */
== NO_REGS)) if (GET_CODE (operand) != SCRATCH
reject = 600; && 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 we can't reload this value at all, reject this
alternative. Note that we could also lose due to
LIMIT_RELOAD_CLASS, but we don't check that
here. */
if (! CONSTANT_P (operand) && this_alternative[i] != NO_REGS)
{
if (targetm.preferred_reload_class (operand,
this_alternative[i])
== NO_REGS)
reject = 600;
if (operand_type[i] == RELOAD_FOR_OUTPUT
&& (targetm.preferred_output_reload_class (operand,
this_alternative[i])
== NO_REGS))
reject = 600;
}
/* We prefer to reload pseudos over reloading other things, /* We prefer to reload pseudos over reloading other things,
since such reloads may be able to be eliminated later. since such reloads may be able to be eliminated later.
If we are reloading a SCRATCH, we won't be generating any If we are reloading a SCRATCH, we won't be generating any
insns, just using a register, so it is also preferred. insns, just using a register, so it is also preferred.
So bump REJECT in other cases. Don't do this in the So bump REJECT in other cases. Don't do this in the
case where we are forcing a constant into memory and case where we are forcing a constant into memory and
it will then win since we don't want to have a different it will then win since we don't want to have a different
alternative match then. */ alternative match then. */
if (! (REG_P (operand) if (! (REG_P (operand)
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER) && REGNO (operand) >= FIRST_PSEUDO_REGISTER)
&& GET_CODE (operand) != SCRATCH && GET_CODE (operand) != SCRATCH
&& ! (const_to_mem && constmemok)) && ! (const_to_mem && constmemok))
reject += 2; reject += 2;
/* Input reloads can be inherited more often than output /* Input reloads can be inherited more often than output
reloads can be removed, so penalize output reloads. */ reloads can be removed, so penalize output reloads. */
if (operand_type[i] != RELOAD_FOR_INPUT if (operand_type[i] != RELOAD_FOR_INPUT
&& GET_CODE (operand) != SCRATCH) && GET_CODE (operand) != SCRATCH)
reject++; reject++;
} }
/* If this operand is a pseudo register that didn't get a hard /* If this operand is a pseudo register that didn't get
reg and this alternative accepts some register, see if the a hard reg and this alternative accepts some
class that we want is a subset of the preferred class for this register, see if the class that we want is a subset
register. If not, but it intersects that class, use the of the preferred class for this register. If not,
preferred class instead. If it does not intersect the preferred but it intersects that class, use the preferred class
class, show that usage of this alternative should be discouraged; instead. If it does not intersect the preferred
it will be discouraged more still if the register is `preferred class, show that usage of this alternative should be
or nothing'. We do this because it increases the chance of discouraged; it will be discouraged more still if the
reusing our spill register in a later insn and avoiding a pair register is `preferred or nothing'. We do this
of memory stores and loads. because it increases the chance of reusing our spill
register in a later insn and avoiding a pair of
Don't bother with this if this alternative will accept this memory stores and loads.
operand.
Don't bother with this if this alternative will
Don't do this for a multiword operand, since it is only a accept this operand.
small win and has the risk of requiring more spill registers,
which could cause a large loss. Don't do this for a multiword operand, since it is
only a small win and has the risk of requiring more
Don't do this if the preferred class has only one register spill registers, which could cause a large loss.
because we might otherwise exhaust the class. */
Don't do this if the preferred class has only one
if (! win && ! did_match register because we might otherwise exhaust the
&& this_alternative[i] != NO_REGS class. */
&& GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
&& reg_class_size [(int) preferred_class[i]] > 0 if (! win && ! did_match
&& ! small_register_class_p (preferred_class[i])) && this_alternative[i] != NO_REGS
{ && GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
if (! reg_class_subset_p (this_alternative[i], && reg_class_size [(int) preferred_class[i]] > 0
preferred_class[i])) && ! small_register_class_p (preferred_class[i]))
{ {
/* Since we don't have a way of forming the intersection, if (! reg_class_subset_p (this_alternative[i],
we just do something special if the preferred class preferred_class[i]))
is a subset of the class we have; that's the most {
common case anyway. */ /* Since we don't have a way of forming the intersection,
if (reg_class_subset_p (preferred_class[i], we just do something special if the preferred class
this_alternative[i])) is a subset of the class we have; that's the most
this_alternative[i] = preferred_class[i]; common case anyway. */
else if (reg_class_subset_p (preferred_class[i],
reject += (2 + 2 * pref_or_nothing[i]); this_alternative[i]))
this_alternative[i] = preferred_class[i];
else
reject += (2 + 2 * pref_or_nothing[i]);
}
} }
} }
}
/* Now see if any output operands that are marked "earlyclobber" /* Now see if any output operands that are marked "earlyclobber"
in this alternative conflict with any input operands in this alternative conflict with any input operands
or any memory addresses. */ or any memory addresses. */
for (i = 0; i < noperands; i++) for (i = 0; i < noperands; i++)
if (this_alternative_earlyclobber[i] if (this_alternative_earlyclobber[i]
&& (this_alternative_win[i] || this_alternative_match_win[i])) && (this_alternative_win[i] || this_alternative_match_win[i]))
{ {
struct decomposition early_data; struct decomposition early_data;
early_data = decompose (recog_data.operand[i]); early_data = decompose (recog_data.operand[i]);
gcc_assert (modified[i] != RELOAD_READ); gcc_assert (modified[i] != RELOAD_READ);
if (this_alternative[i] == NO_REGS) if (this_alternative[i] == NO_REGS)
{ {
this_alternative_earlyclobber[i] = 0; this_alternative_earlyclobber[i] = 0;
gcc_assert (this_insn_is_asm); gcc_assert (this_insn_is_asm);
error_for_asm (this_insn, error_for_asm (this_insn,
"%<&%> constraint used with no register class"); "%<&%> constraint used with no register class");
} }
for (j = 0; j < noperands; j++)
/* Is this an input operand or a memory ref? */
if ((MEM_P (recog_data.operand[j])
|| modified[j] != RELOAD_WRITE)
&& j != i
/* Ignore things like match_operator operands. */
&& !recog_data.is_operator[j]
/* Don't count an input operand that is constrained to match
the early clobber operand. */
&& ! (this_alternative_matches[j] == i
&& rtx_equal_p (recog_data.operand[i],
recog_data.operand[j]))
/* Is it altered by storing the earlyclobber operand? */
&& !immune_p (recog_data.operand[j], recog_data.operand[i],
early_data))
{
/* If the output is in a non-empty few-regs class,
it's costly to reload it, so reload the input instead. */
if (small_register_class_p (this_alternative[i])
&& (REG_P (recog_data.operand[j])
|| GET_CODE (recog_data.operand[j]) == SUBREG))
{
losers++;
this_alternative_win[j] = 0;
this_alternative_match_win[j] = 0;
}
else
break;
}
/* If an earlyclobber operand conflicts with something,
it must be reloaded, so request this and count the cost. */
if (j != noperands)
{
losers++;
this_alternative_win[i] = 0;
this_alternative_match_win[j] = 0;
for (j = 0; j < noperands; j++) for (j = 0; j < noperands; j++)
if (this_alternative_matches[j] == i /* Is this an input operand or a memory ref? */
&& this_alternative_match_win[j]) if ((MEM_P (recog_data.operand[j])
|| modified[j] != RELOAD_WRITE)
&& j != i
/* Ignore things like match_operator operands. */
&& !recog_data.is_operator[j]
/* Don't count an input operand that is constrained to match
the early clobber operand. */
&& ! (this_alternative_matches[j] == i
&& rtx_equal_p (recog_data.operand[i],
recog_data.operand[j]))
/* Is it altered by storing the earlyclobber operand? */
&& !immune_p (recog_data.operand[j], recog_data.operand[i],
early_data))
{ {
this_alternative_win[j] = 0; /* If the output is in a non-empty few-regs class,
this_alternative_match_win[j] = 0; it's costly to reload it, so reload the input instead. */
losers++; if (small_register_class_p (this_alternative[i])
&& (REG_P (recog_data.operand[j])
|| GET_CODE (recog_data.operand[j]) == SUBREG))
{
losers++;
this_alternative_win[j] = 0;
this_alternative_match_win[j] = 0;
}
else
break;
} }
/* If an earlyclobber operand conflicts with something,
it must be reloaded, so request this and count the cost. */
if (j != noperands)
{
losers++;
this_alternative_win[i] = 0;
this_alternative_match_win[j] = 0;
for (j = 0; j < noperands; j++)
if (this_alternative_matches[j] == i
&& this_alternative_match_win[j])
{
this_alternative_win[j] = 0;
this_alternative_match_win[j] = 0;
losers++;
}
}
} }
}
/* If one alternative accepts all the operands, no reload required,
choose that alternative; don't consider the remaining ones. */
if (losers == 0)
{
/* Unswap these so that they are never swapped at `finish'. */
if (commutative >= 0)
{
recog_data.operand[commutative] = substed_operand[commutative];
recog_data.operand[commutative + 1]
= substed_operand[commutative + 1];
}
for (i = 0; i < noperands; i++)
{
goal_alternative_win[i] = this_alternative_win[i];
goal_alternative_match_win[i] = this_alternative_match_win[i];
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;
}
/* REJECT, set by the ! and ? constraint characters and when a register
would be reloaded into a non-preferred class, discourages the use of
this alternative for a reload goal. REJECT is incremented by six
for each ? and two for each non-preferred class. */
losers = losers * 6 + reject;
/* If this alternative can be made to work by reloading, /* If one alternative accepts all the operands, no reload required,
and it needs less reloading than the others checked so far, choose that alternative; don't consider the remaining ones. */
record it as the chosen goal for reloading. */ if (losers == 0)
if (! bad)
{
if (best > losers)
{ {
/* Unswap these so that they are never swapped at `finish'. */
if (swapped)
{
recog_data.operand[commutative] = substed_operand[commutative];
recog_data.operand[commutative + 1]
= substed_operand[commutative + 1];
}
for (i = 0; i < noperands; i++) for (i = 0; i < noperands; i++)
{ {
goal_alternative[i] = this_alternative[i];
goal_alternative_win[i] = this_alternative_win[i]; goal_alternative_win[i] = this_alternative_win[i];
goal_alternative_match_win[i] goal_alternative_match_win[i] = this_alternative_match_win[i];
= this_alternative_match_win[i]; goal_alternative[i] = this_alternative[i];
goal_alternative_offmemok[i] goal_alternative_offmemok[i] = this_alternative_offmemok[i];
= this_alternative_offmemok[i];
goal_alternative_matches[i] = this_alternative_matches[i]; goal_alternative_matches[i] = this_alternative_matches[i];
goal_alternative_earlyclobber[i] goal_alternative_earlyclobber[i]
= this_alternative_earlyclobber[i]; = this_alternative_earlyclobber[i];
} }
goal_alternative_swapped = swapped;
best = losers;
goal_alternative_number = this_alternative_number; goal_alternative_number = this_alternative_number;
goal_alternative_swapped = swapped;
goal_earlyclobber = this_earlyclobber; goal_earlyclobber = this_earlyclobber;
goto finish;
} }
}
}
/* If insn is commutative (it's safe to exchange a certain pair of operands) /* REJECT, set by the ! and ? constraint characters and when a register
then we need to try each alternative twice, would be reloaded into a non-preferred class, discourages the use of
the second time matching those two operands this alternative for a reload goal. REJECT is incremented by six
as if we had exchanged them. for each ? and two for each non-preferred class. */
To do this, really exchange them in operands. losers = losers * 6 + reject;
/* If this alternative can be made to work by reloading,
and it needs less reloading than the others checked so far,
record it as the chosen goal for reloading. */
if (! bad)
{
if (best > losers)
{
for (i = 0; i < noperands; i++)
{
goal_alternative[i] = this_alternative[i];
goal_alternative_win[i] = this_alternative_win[i];
goal_alternative_match_win[i]
= this_alternative_match_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 we have just tried the alternatives the second time, if (swapped)
return operands to normal and drop through. */ {
enum reg_class tclass;
int t;
if (commutative >= 0) /* If the commutative operands have been swapped, swap
{ them back in order to check the next alternative. */
swapped = !swapped; recog_data.operand[commutative] = substed_operand[commutative];
if (swapped) recog_data.operand[commutative + 1] = substed_operand[commutative + 1];
{ /* Unswap the duplicates too. */
enum reg_class tclass; for (i = 0; i < recog_data.n_dups; i++)
int t; if (recog_data.dup_num[i] == commutative
|| recog_data.dup_num[i] == commutative + 1)
recog_data.operand[commutative] = substed_operand[commutative + 1]; *recog_data.dup_loc[i]
recog_data.operand[commutative + 1] = substed_operand[commutative]; = recog_data.operand[(int) recog_data.dup_num[i]];
/* Swap the duplicates too. */
for (i = 0; i < recog_data.n_dups; i++) /* Unswap the operand related information as well. */
if (recog_data.dup_num[i] == commutative tclass = preferred_class[commutative];
|| recog_data.dup_num[i] == commutative + 1) preferred_class[commutative] = preferred_class[commutative + 1];
*recog_data.dup_loc[i] preferred_class[commutative + 1] = tclass;
= recog_data.operand[(int) recog_data.dup_num[i]];
t = pref_or_nothing[commutative];
tclass = preferred_class[commutative]; pref_or_nothing[commutative] = pref_or_nothing[commutative + 1];
preferred_class[commutative] = preferred_class[commutative + 1]; pref_or_nothing[commutative + 1] = t;
preferred_class[commutative + 1] = tclass;
t = address_reloaded[commutative];
t = pref_or_nothing[commutative]; address_reloaded[commutative] = address_reloaded[commutative + 1];
pref_or_nothing[commutative] = pref_or_nothing[commutative + 1]; address_reloaded[commutative + 1] = t;
pref_or_nothing[commutative + 1] = t; }
t = address_reloaded[commutative];
address_reloaded[commutative] = address_reloaded[commutative + 1];
address_reloaded[commutative + 1] = t;
memcpy (constraints, recog_data.constraints,
noperands * sizeof (const char *));
goto try_swapped;
}
else
{
recog_data.operand[commutative] = substed_operand[commutative];
recog_data.operand[commutative + 1]
= substed_operand[commutative + 1];
/* Unswap the duplicates too. */
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]];
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment