egcs-19981012 - parsing troubles in assembler
Richard Henderson
rth@cygnus.com
Fri Oct 16 15:52:00 GMT 1998
On Fri, Oct 16, 1998 at 11:10:17AM -0600, Michal Jaegermann wrote:
> /usr/src/linux-2.0.36/include/asm/byteorder.h:55:
> output operand constraint lacks `='
The error message is correct -- the "=" must come first. This
is new sanity checking of asms.
> This, indeed, prevents a bug I was reporting early (about problems
> with inlined functions and -O2) from showing up - but likely because
> optimizer was never reached. This price seem to be a bit excessive. :-)
I've located the failure you reported.
The problem is with combine constructing a bit of circular rtl. The
substitution is on an asm input that looks like
x = (and:DI (reg:DI 77)
(const_int 65535))
from = (reg:DI 77)
to = (ashiftrt:DI (ashift:DI (plus:DI (reg:DI 77)
(reg:DI 78))
(const_int 32))
(const_int 32))
The problem arises because the rtl for the inputs of the arms of a
multi-output asm are shared. If we process the parallel like any
other, we'll wind up with
(and:DI (ashiftrt:DI (ashift:DI (plus:DI (ashiftrt:DI (ashift:DI ...
I tried unsharing the rtl in stmt.c, but that resulted in recognition
failures. So I added some bits to recognize this case in subst.
Ok?
r~
* combine.c (subst): Process the inputs to a parallel asm_operands
only once.
Index: combine.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/combine.c,v
retrieving revision 1.48
diff -c -p -d -r1.48 combine.c
*** combine.c 1998/10/14 20:50:39 1.48
--- combine.c 1998/10/16 22:37:12
*************** subst (x, from, to, in_dest, unique_copy
*** 3067,3169 ****
if (COMBINE_RTX_EQUAL_P (x, to))
return to;
! 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 (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')
{
! 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)
#endif
! )
! return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
! 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);
}
}
--- 3067,3220 ----
if (COMBINE_RTX_EQUAL_P (x, to))
return to;
! /* 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);
!
! /* If this substitution failed, this whole thing fails. */
! if (GET_CODE (new) == CLOBBER
! && XEXP (new, 0) == const0_rtx)
! return new;
!
! SUBST (XVECEXP (x, 0, 0), new);
!
! for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
{
! rtx dest = SET_DEST (XVECEXP (x, 0, i));
!
! if (GET_CODE (dest) != REG
! && GET_CODE (dest) != CC0
! && GET_CODE (dest) != PC)
{
! 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;
! SUBST (SET_DEST (XVECEXP (x, 0, i)), new);
}
}
! }
! 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 (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')
! {
! 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)
#endif
! )
! return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
! 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);
! }
}
}
More information about the Gcc-bugs
mailing list