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


I wrote:
> confusing.  Which is why I've added some comments.  Ah, the "smells"
> comment might be wrong.

The more I look at this, 

       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

and the two other places like it handling dead operands in this function,
the more sure I am that this should be

       if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
 	{
 	  if (STACK_TOP_P (operands[0]))
-	    p = "p\t{%0,%2|%2, %0}";
+	    abort ();
 	  else


I dug out the original test-case (attached) where gcc-2.7.2 generated
faulty assembly code, and it's clear that gcc-2.7.2 loses track of the fp
register stack.  Look at the end of the assembly.

        jle .L15		# start with one item on fp stack
        fld %st(0)		# two
.L19:
        faddp %st,%st(1)	# one
        jmp .L18		# exit func with one on stack, ok
.L15:
        cmpl $8388607,%ecx
        jg .L22
        fld %st(0)		# two
        fsubrp %st(1),%st	# one
.L23:
        pushl %edx
        flds (%esp)		# two
        addl $4,%esp
        jmp .L18		# exit with two!!
.L22:
        fstp %st(0)		# zero
        jmp .L23		# leads to exit with one
.L21:
        fstp %st(1)
.L18:
        movl -4(%ebp),%ebx
        movl %ebp,%esp
        popl %ebp
        ret

BTW, current CVS compiles the testcase OK.
/*
 * inspired by glibc-2.0.6/sysdeps/libm-ieee754/s_nextafterf.c
 *
 * gcc -O2 -S -DOP=+ gives faddp %st(1),%st
 * gcc -O2 -S -DOP=* gives fmulp %st(1),%st
 * gcc -O2 -S -DOP=- gives fsubrp %st(1),%st
 * gcc -O2 -S -DOP=/ gives fdivrp %st(1),%st
 */

#ifndef OP
#define OP *
#endif

typedef int int32_t __attribute__ ((__mode__ (  __SI__ ))) ;
typedef unsigned int u_int32_t __attribute__ ((__mode__ (  __SI__ ))) ;

typedef union
{
  float value;
  u_int32_t word;
} ieee_float_shape_type;

float __nextafterf(float x, float y)
{
 int32_t hx,hy,ix,iy;

 {
  ieee_float_shape_type gf_u;
  gf_u.value = x;
  hx = gf_u.word;
 }
 {
  ieee_float_shape_type gf_u;
  gf_u.value = y;
  hy = gf_u.word;
 }
 ix = hx&0x7fffffff;
 iy = hy&0x7fffffff;

 if ( ix > 0x7f800000 || iy > 0x7f800000 )
    return x+y;
 if (x == y) return x;
 if (ix == 0)
   {
    {
     ieee_float_shape_type sf_u;
     sf_u.word = (hy&0x80000000) | 1;
     x = sf_u.value;
    }
    y = x*x;
    if (y == x) return y; else return x;
   }
 if (hx >= 0)
   {
    if (hx > hy)
       hx -= 1;
    else
       hx += 1;
   }
 else
   {
    if (hy >= 0 || hx > hy)
       hx -= 1;
    else
       hx += 1;
   }
 hy = hx & 0x7f800000;
 if (hy >= 0x7f800000)
    return x+x;
 if (hy < 0x00800000)
   {
    y = x OP x;
    if (y != x)
      {
       ieee_float_shape_type sf_u;
       sf_u.word = hx;
       y = sf_u.value;
       return y;
      }
   }
 {
  ieee_float_shape_type sf_u;
  sf_u.word = hx;
  x = sf_u.value;
 }
 return x;
}

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