This is the mail archive of the 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]

Reg-stack and cmove bug

On Thu, Feb 15, 2001 at 10:14:01PM -0800, Tim Prince wrote:
> It's still a problem on linux as well as cygwin.  I know that cygwin is not
> a supported target, and I'm grateful to the extent that people have helped
> make it work.  The problem is the same old one which started early in
> gcc-2.96 with the g77 sequence (all typed double precision).  It has always
> worked correctly in the 2.95 series.
> if(x /= y)then
>     if( x * y >=0)then
>         a=abs(x)
>         b=abs(y)
>         c=max(a,b)
>         d=min(a,b)
>         w=1-d/c
>     else
>         w=1
>     endif
> else
>     w=0
> endif
> which, when compiled with g77-2.97 -O, -Os, or -O2, along with the
> combination -march=pentiumpro -ffast-math, sets w to 0., regardless of the
> values of x and y.

Okay, I can now reproduce this.  There's a complete Fortran test case
appended (requires user input).  It looks like a general problem to
me.  Jan, this appears to be right in your corner: it's a problem with
reg-stack and conditional moves.

Here is the code generated for the innermost if clause by the gcc-3.0
branch as of earlier today, at -Os -march=pentiumpro -ffast-math.  On
entry to this block, x and y are in %st(0) and %st(1) respectively.

	fxch	%st(1)
	fcomi	%st(1), %st
	fld	%st(0)
	fcmovbe	%st(2), %st
	fxch	%st(1)
***	fcmovbe	%st(2), %st
	fstp	%st(2)
	fdivrp	%st, %st(1)
	fsubrl	.LC3		; constant 1.0D
	fstpl	-24(%ebp)

Let's say x and y are 12. and 23.  Top of stack is at right.

 fabs			      12 -- 12
 fxch %st(1)		   23 12 -- 12 23
 fabs			      23 -- 23
 fcomi %st(1),%st	         --
 fld %st(0)		   12 23 -- 12 23 23
 fcmovbe %st(2),%st	         --
 fxch %st(1)		         --
 fcmovbe %st(2),%st	         --
 fstp %st(2)		12 23 23 -- 23 23
 fdivrp %st, %st(1)	   23 23 -- 1
 fsubrl .LC3		       1 -- 0

If I swap x and y (23 and 12), we get instead

 fld %st(0)		   23 12 -- 23 12 12
 fcmovbe %st(2),%st	23 12 12 -- 23 12 23
 fxch %st(1)		   12 23 -- 23 12
 fcmovbe %st(2),%st	23 23 12 -- 23 23 23
 fstp %st(2)		23 23 23 -- 23 23

The intended result of the stack shuffle is to put 'd' at %st(0) and
'c' at %st(1): fdivrp %st,%st(1) means divide %st(0) by %st(1).  We
can get this right by changing one instruction: the one I marked with
three stars.  It needs to be 'fcmovnbe' (not bigger or equal).  This
is reg-stack's fault.  Right before reg-stack, the insns which will
become fcmovs are

(insn 208 228 211 {*movdfcc_1}
   (set (reg:DF 10 st(2))
        (if_then_else:DF (ge (reg:CCFP 17 flags) 0)
            (reg:DF 8 st(0))
            (reg:DF 10 st(2)))))

(insn 211 208 115 {*movdfcc_1} 
   (set (reg:DF 9 st(1))
        (if_then_else:DF (unle (reg:CCFP 17 flags) 0)
            (reg:DF 8 st(0))
            (reg:DF 9 st(1)))))

After reg-stack, they are instead

(insn 208 228 270 {*movdfcc_1}
   (set (reg:DF 8 st(0))
        (if_then_else:DF (le (reg:CCFP 17 flags) 0)
            (reg:DF 10 st(2))
            (reg:DF 8 st(0)))))

(insn 211 270 271 {*movdfcc_1}
   (set (reg:DF 8 st(0))
        (if_then_else:DF (unle (reg:CCFP 17 flags) 0)
            (reg:DF 10 st(2))
            (reg:DF 8 st(0)))))

Notice how the 'ge' in the first insn has mysteriously become an 'le'
after reg-stack.  It is NOT trying to reverse the sense of the
comparison here; it has got confused while trying to reorder operands
to fit the 387 register stack.  fcmov can only move to top-of-stack.

N.B. 'unle' means 'UNordered less or equal' not 'not less or equal'.

That should be enough analysis for someone to find the bug on.


       program test
       implicit none
       double precision a,b,c,d,w,x,y
       read *,x,y
       if(x /= y)then
           if( x * y >=0)then
       print *,w

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