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: x86 fp fix


> Intel mode fp assembly output was wrong, mainly due to a wrong
> assumption about how the Unixware assembler is broken.  Ian Taylor
> and I, with help from Robert Lipe, thrashed out exactly how the
> Unixware assembler was broken quite a while ago (so that gas would be

I'm afraid I don't recall this conversation and I can't find it in any
of my mail folders.  (This isn't to say it didn't happen. :-)

Can you please offer a testcase or a pointer to the mail thread so we
can determine exactly which of the UnixWare assemblers are "broken"?
Since UW has a history of some 8 or more years (and the AT&T assembler
that it came from probably another 5 or 6), it's helpful to figure out
exactly which ones would be affected.  

For example, if it's "SVR4/386" or "Unixware 1.x" that's affected, I
won't even pretend to care and would rather just delete this whole mess.

Also, I'm FP impaired, so don't expect me to deduce much in this area.

Thanx,
RJL

> --- egcs/gcc/config/i386/i386.c~	Mon Mar 20 23:35:06 2000
> +++ egcs/gcc/config/i386/i386.c	Sat Mar 25 11:03:24 2000
> @@ -3434,6 +3434,15 @@ split_di (operands, num, lo_half, hi_hal
>     There is no guarantee that the operands are the same mode, as they
>     might be within FLOAT or FLOAT_EXTEND expressions. */
>  
> +#ifndef UNIXWARE_COMPAT
> +/* Set to 1 for compatibility with brain-damaged assemblers.  No-one
> +   wants to fix the assemblers because that causes incompatibility
> +   with gcc.  No-one wants to fix gcc because that causes
> +   incompatibility with assemblers...  You can use the option of
> +   !UNIXWARE_COMPAT if you recompile both gcc and gas this way.  */
> +#define UNIXWARE_COMPAT 1
> +#endif
> +
>  const char *
>  output_387_binary_op (insn, operands)
>       rtx insn;
> @@ -3443,6 +3452,22 @@ output_387_binary_op (insn, operands)
>    rtx temp;
>    const char *p;
>  
> +#ifdef FP_PARANOIA
> +  /* Even if we do not want to check the inputs, this documents input
> +     constraints.  Which helps in understanding the following code.  */
> +  if (STACK_REG_P (operands[0])
> +      && ((REG_P (operands[1])
> +	   && REGNO (operands[0]) == REGNO (operands[1])
> +	   && (STACK_REG_P (operands[2]) || GET_CODE (operands[2]) == MEM))
> +	  || (REG_P (operands[2])
> +	      && REGNO (operands[0]) == REGNO (operands[2])
> +	      && (STACK_REG_P (operands[1]) || GET_CODE (operands[1]) == MEM)))
> +      && (STACK_TOP_P (operands[1]) || STACK_TOP_P (operands[2])))
> +    ; /* ok */
> +  else
> +    abort ();
> +#endif
> +
>    switch (GET_CODE (operands[3]))
>      {
>      case PLUS:
> @@ -3494,6 +3519,8 @@ output_387_binary_op (insn, operands)
>  	  operands[1] = temp;
>  	}
>  
> +      /* know operands[0] == operands[1] */
> +
>        if (GET_CODE (operands[2]) == MEM)
>  	{
>  	  p = "%z2\t%2";
> @@ -3503,16 +3530,21 @@ output_387_binary_op (insn, operands)
>        if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
>  	{
>  	  if (STACK_TOP_P (operands[0]))
> -	    p = "p\t{%0,%2|%2, %0}";
> +	    /* How is it that we are storing to a dead operand[2]?
> +	       This smells like we're covering for a problem
> +	       elsewhere.  Well, maybe operands[1] is dead too.
> +	       gcc <= 2.8.1 didn't have this check and generated
> +	       assembly code that the Unixware assembler rejected.  */
> +	    p = "p\t{%0,%2|%2, %0}";	/* st(1) = st(0) op st(1); pop */
>  	  else
> -	    p = "p\t{%2,%0|%0, %2}";
> +	    p = "p\t{%2,%0|%0, %2}";	/* st(r1) = st(r1) op st(0); pop */
>  	  break;
>  	}
>  
>        if (STACK_TOP_P (operands[0]))
> -	p = "\t{%y2,%0|%0, %y2}";
> +	p = "\t{%y2,%0|%0, %y2}";	/* st(0) = st(0) op st(r2) */
>        else
> -	p = "\t{%2,%0|%0, %2}";
> +	p = "\t{%2,%0|%0, %2}";		/* st(r1) = st(r1) op st(0) */
>        break;
>  
>      case MINUS:
> @@ -3529,42 +3561,68 @@ output_387_binary_op (insn, operands)
>  	  break;
>  	}
>  
> -      if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2]))
> -	abort ();
> -
> -      /* Note that the Unixware assembler, and the AT&T assembler before
> -	 that, are confusingly not reversed from Intel syntax in this
> -	 area.  */
>        if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
>  	{
> +#if UNIXWARE_COMPAT
> +	  /* The Unixware assembler, and the AT&T assembler before
> +	     that, confusingly reverse the direction of the operation
> +	     for fsub{r} and fdiv{r} when the destination register is
> +	     not st(0).  The Intel assembler doesn't have this brain
> +	     damage.  Read !UNIXWARE_COMPAT to figure out what the
> +	     hardware really does.  */
> +	  if (STACK_TOP_P (operands[0]))
> +	    p = "{p\t%0,%2|rp\t%2, %0}";
> +	  else
> +	    p = "{rp\t%2,%0|p\t%0, %2}";
> +#else
>  	  if (STACK_TOP_P (operands[0]))
> -	    p = "p\t%0,%2";
> +	    p = "rp\t{%0,%2|%2, %0}";	/* st(1) = st(0) op st(1); pop */
>  	  else
> -	    p = "rp\t%2,%0";
> +	    p = "p\t{%2,%0|%0, %2}";	/* st(r1) = st(r1) op st(0); pop */
> +#endif
>  	  break;
>  	}
>  
>        if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
>  	{
> +#if UNIXWARE_COMPAT
>  	  if (STACK_TOP_P (operands[0]))
> -	    p = "rp\t%0,%1";
> +	    p = "{rp\t%0,%1|p\t%1, %0}";
>  	  else
> -	    p = "p\t%1,%0";
> +	    p = "{p\t%1,%0|rp\t%0, %1}";
> +#else
> +	  if (STACK_TOP_P (operands[0]))
> +	    p = "p\t{%0,%1|%1, %0}";	/* st(1) = st(1) op st(0); pop */
> +	  else
> +	    p = "rp\t{%1,%0|%0, %1}";	/* st(r2) = st(0) op st(r2); pop */
> +#endif
>  	  break;
>  	}
>  
>        if (STACK_TOP_P (operands[0]))
>  	{
>  	  if (STACK_TOP_P (operands[1]))
> -	    p = "\t%y2,%0";
> +	    p = "\t{%y2,%0|%0, %y2}";	/* st(0) = st(0) op st(r2) */
>  	  else
> -	    p = "r\t%y1,%0";
> +	    p = "r\t{%y1,%0|%0, %y1}";	/* st(0) = st(r1) op st(0) */
>  	  break;
>  	}
>        else if (STACK_TOP_P (operands[1]))
> -	p = "\t%1,%0";
> +	{
> +#if UNIXWARE_COMPAT
> +	  p = "{\t%1,%0|r\t%0, %1}";
> +#else
> +	  p = "r\t{%1,%0|%0, %1}";	/* st(r2) = st(0) op st(r2) */
> +#endif
> +	}
>        else
> -	p = "r\t%2,%0";
> +	{
> +#if UNIXWARE_COMPAT
> +	  p = "{r\t%2,%0|\t%0, %2}";
> +#else
> +	  p = "\t{%2,%0|%0, %2}";	/* st(r1) = st(r1) op st(0) */
> +#endif
> +	}
>        break;
>  
>      default:
> 
> 
> 

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