Commit 4f4b3679 by Richard Henderson Committed by Richard Henderson

combine.c (subst): Process the inputs to a parallel asm_operands only once.

        * combine.c (subst): Process the inputs to a parallel asm_operands
        only once.

From-SVN: r23357
parent 3fbd5c2c
Mon Oct 26 13:35:02 1998 Richard Henderson <rth@cygnus.com>
* combine.c (subst): Process the inputs to a parallel asm_operands
only once.
Mon Oct 26 13:32:31 1998 Richard Henderson <rth@cygnus.com>
* stmt.c (expand_asm_operands): Accept `=' or `+' at any position.
......
......@@ -3048,103 +3048,154 @@ subst (x, from, to, in_dest, unique_copy)
if (COMBINE_RTX_EQUAL_P (x, to))
return to;
len = GET_RTX_LENGTH (code);
fmt = GET_RTX_FORMAT (code);
/* Parallel asm_operands need special attention because all of the
inputs are shared across the arms. Furthermore, unsharing the
rtl results in recognition failures. Failure to handle this case
specially can result in circular rtl.
Solve this by doing a normal pass across the first entry of the
parallel, and only processing the SET_DESTs of the subsequent
entries. Ug. */
if (code == PARALLEL
&& GET_CODE (XVECEXP (x, 0, 0)) == SET
&& GET_CODE (SET_SRC (XVECEXP (x, 0, 0))) == ASM_OPERANDS)
{
new = subst (XVECEXP (x, 0, 0), from, to, 0, unique_copy);
/* We don't need to process a SET_DEST that is a register, CC0, or PC, so
set up to skip this common case. All other cases where we want to
suppress replacing something inside a SET_SRC are handled via the
IN_DEST operand. */
if (code == SET
&& (GET_CODE (SET_DEST (x)) == REG
|| GET_CODE (SET_DEST (x)) == CC0
|| GET_CODE (SET_DEST (x)) == PC))
fmt = "ie";
/* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a
constant. */
if (fmt[0] == 'e')
op0_mode = GET_MODE (XEXP (x, 0));
/* If this substitution failed, this whole thing fails. */
if (GET_CODE (new) == CLOBBER
&& XEXP (new, 0) == const0_rtx)
return new;
for (i = 0; i < len; i++)
{
if (fmt[i] == 'E')
SUBST (XVECEXP (x, 0, 0), new);
for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
{
register int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
rtx dest = SET_DEST (XVECEXP (x, 0, i));
if (GET_CODE (dest) != REG
&& GET_CODE (dest) != CC0
&& GET_CODE (dest) != PC)
{
if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from))
{
new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
n_occurrences++;
}
else
{
new = subst (XVECEXP (x, i, j), from, to, 0, unique_copy);
new = subst (dest, from, to, 0, unique_copy);
/* If this substitution failed, this whole thing fails. */
if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
return new;
}
/* If this substitution failed, this whole thing fails. */
if (GET_CODE (new) == CLOBBER
&& XEXP (new, 0) == const0_rtx)
return new;
SUBST (XVECEXP (x, i, j), new);
SUBST (SET_DEST (XVECEXP (x, 0, i)), new);
}
}
else if (fmt[i] == 'e')
}
else
{
len = GET_RTX_LENGTH (code);
fmt = GET_RTX_FORMAT (code);
/* We don't need to process a SET_DEST that is a register, CC0,
or PC, so set up to skip this common case. All other cases
where we want to suppress replacing something inside a
SET_SRC are handled via the IN_DEST operand. */
if (code == SET
&& (GET_CODE (SET_DEST (x)) == REG
|| GET_CODE (SET_DEST (x)) == CC0
|| GET_CODE (SET_DEST (x)) == PC))
fmt = "ie";
/* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a
constant. */
if (fmt[0] == 'e')
op0_mode = GET_MODE (XEXP (x, 0));
for (i = 0; i < len; i++)
{
if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
if (fmt[i] == 'E')
{
register int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
{
if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from))
{
new = (unique_copy && n_occurrences
? copy_rtx (to) : to);
n_occurrences++;
}
else
{
new = subst (XVECEXP (x, i, j), from, to, 0,
unique_copy);
/* If this substitution failed, this whole thing
fails. */
if (GET_CODE (new) == CLOBBER
&& XEXP (new, 0) == const0_rtx)
return new;
}
SUBST (XVECEXP (x, i, j), new);
}
}
else if (fmt[i] == 'e')
{
/* In general, don't install a subreg involving two modes not
tieable. It can worsen register allocation, and can even
make invalid reload insns, since the reg inside may need to
be copied from in the outside mode, and that may be invalid
if it is an fp reg copied in integer mode.
We allow two exceptions to this: It is valid if it is inside
another SUBREG and the mode of that SUBREG and the mode of
the inside of TO is tieable and it is valid if X is a SET
that copies FROM to CC0. */
if (GET_CODE (to) == SUBREG
&& ! MODES_TIEABLE_P (GET_MODE (to),
GET_MODE (SUBREG_REG (to)))
&& ! (code == SUBREG
&& MODES_TIEABLE_P (GET_MODE (x),
GET_MODE (SUBREG_REG (to))))
if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
{
/* In general, don't install a subreg involving two
modes not tieable. It can worsen register
allocation, and can even make invalid reload
insns, since the reg inside may need to be copied
from in the outside mode, and that may be invalid
if it is an fp reg copied in integer mode.
We allow two exceptions to this: It is valid if
it is inside another SUBREG and the mode of that
SUBREG and the mode of the inside of TO is
tieable and it is valid if X is a SET that copies
FROM to CC0. */
if (GET_CODE (to) == SUBREG
&& ! MODES_TIEABLE_P (GET_MODE (to),
GET_MODE (SUBREG_REG (to)))
&& ! (code == SUBREG
&& MODES_TIEABLE_P (GET_MODE (x),
GET_MODE (SUBREG_REG (to))))
#ifdef HAVE_cc0
&& ! (code == SET && i == 1 && XEXP (x, 0) == cc0_rtx)
&& ! (code == SET && i == 1 && XEXP (x, 0) == cc0_rtx)
#endif
)
return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
)
return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
n_occurrences++;
new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
n_occurrences++;
}
else
/* If we are in a SET_DEST, suppress most cases unless we
have gone inside a MEM, in which case we want to
simplify the address. We assume here that things that
are actually part of the destination have their inner
parts in the first expression. This is true for SUBREG,
STRICT_LOW_PART, and ZERO_EXTRACT, which are the only
things aside from REG and MEM that should appear in a
SET_DEST. */
new = subst (XEXP (x, i), from, to,
(((in_dest
&& (code == SUBREG || code == STRICT_LOW_PART
|| code == ZERO_EXTRACT))
|| code == SET)
&& i == 0), unique_copy);
/* If we found that we will have to reject this combination,
indicate that by returning the CLOBBER ourselves, rather than
an expression containing it. This will speed things up as
well as prevent accidents where two CLOBBERs are considered
to be equal, thus producing an incorrect simplification. */
if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
return new;
SUBST (XEXP (x, i), new);
}
else
/* If we are in a SET_DEST, suppress most cases unless we
have gone inside a MEM, in which case we want to
simplify the address. We assume here that things that
are actually part of the destination have their inner
parts in the first expression. This is true for SUBREG,
STRICT_LOW_PART, and ZERO_EXTRACT, which are the only
things aside from REG and MEM that should appear in a
SET_DEST. */
new = subst (XEXP (x, i), from, to,
(((in_dest
&& (code == SUBREG || code == STRICT_LOW_PART
|| code == ZERO_EXTRACT))
|| code == SET)
&& i == 0), unique_copy);
/* If we found that we will have to reject this combination,
indicate that by returning the CLOBBER ourselves, rather than
an expression containing it. This will speed things up as
well as prevent accidents where two CLOBBERs are considered
to be equal, thus producing an incorrect simplification. */
if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
return new;
SUBST (XEXP (x, i), new);
}
}
......
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