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

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.

	fabs
	fxch	%st(1)
	fabs
	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.

zw

       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
               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
       print *,w
       end


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