This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: egcs-19981012 - parsing troubles in assembler


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);
! 	    }
  	}
      }
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]