fmaxfminfdim.s   [plain text]


/*
 *  fmax.s
 *
 *      by Ian Ollmann
 *
 *  Copyright © 2007 Apple Inc. All Rights Reserved.
 */
 
 
#include <machine/asm.h>
#include "abi.h"

#if defined( BUILDING_FOR_CARBONCORE_LEGACY )

    #if defined( __i386__ )

    ENTRY( fmax )
        fldl    8+FRAME_SIZE(STACKP)          //{ y }
        fldl    FRAME_SIZE(STACKP)            //{ x, y }
        fucomi  %st(0), %st(0)                //Check for x is NaN
        fcmovb  %st(1), %st(0)                //{ x or y, y}
        fxch                                  //{ y, x or y }
        fucomi  %st(1), %st(0)                //Check y < x  or y is NaN
        fcmovb  %st(1), %st(0)                //{ max, x or y }
        fstp    %st(1)                        //{ max }
        ret

    ENTRY( fmin )
        fldl    8+FRAME_SIZE(STACKP)          //{ y }
        fldl    FRAME_SIZE(STACKP)            //{ x, y }
        fucomi  %st(0), %st(0)                //Check for x is NaN
        fcmovb  %st(1), %st(0)                //{ x or y, y }
        fucomi  %st(1), %st(0)                //Check x < y  or y is NaN
        fxch                                  //{ y, x or y }
        fcmovb  %st(1), %st(0)                //{ max, x or y }
        fstp    %st(1)                        //{ max }
        ret

	ENTRY( fdim )
		movsd	FRAME_SIZE( STACKP),	%xmm0		// x
		movsd	8+FRAME_SIZE( STACKP),	%xmm1		// y
		movapd	%xmm1,					%xmm2		// x
		ucomisd	%xmm0,					%xmm1		// if( x != x || y != y )
		jp		1f									//		goto 1
		cmpltpd	%xmm0,					%xmm2		//  y < x
		andpd	%xmm2,					%xmm0
		andpd	%xmm2,					%xmm1
	1:	subsd	%xmm1,					%xmm0
		movsd	%xmm0,					FRAME_SIZE(STACKP)
		fldl	FRAME_SIZE(STACKP)
		ret

    #else

    ENTRY( fmax )
        SUBP    $16,    STACKP
        
        //create an array on the stack s[2] = { x, y }
        movsd   %xmm0,  (STACKP)
        movsd   %xmm1,  8(STACKP)

        //test a = x < y 
        xorq    %rax,   %rax
        xorq    %rdx,   %rdx
        ucomisd %xmm1,  %xmm0           
        setb    %al                     // a = x < y || isnan(y) || isnan(x)
        ucomisd %xmm1,  %xmm1           
        setp    %dl                     // isnan(y)
        xorq    %rdx,    %rax           // if (isnan(y)) a = 0

        // return s[a]
        movsd   (STACKP,%rax,8), %xmm0  
        ADDP    $16,    STACKP
        ret

    ENTRY( fmin )
        SUBP    $16,    STACKP
        
        //create an array on the stack s[2] = { x, y }
        movsd   %xmm0,  (STACKP)
        movsd   %xmm1,  8(STACKP)

        //test a = y < x 
        xorq    %rax,   %rax
        xorq    %rdx,   %rdx
        ucomisd %xmm0,  %xmm1           
        setb    %al                     // a = y < x || isnan(y) || isnan(x)
        ucomisd %xmm1,  %xmm1           
        setp    %dl                     // isnan(y)
        xorq    %rdx,    %rax           // if (isnan(y)) a = 0

        // return s[a]
        movsd   (STACKP,%rax,8), %xmm0  
        ADDP    $16,    STACKP
        ret

    ENTRY( fdim )
        //a == ( y < x || isnan( y) || isnan(x) )
        xor     %eax,   %eax
        ucomisd %xmm0,  %xmm1       
        setb    %al                 
        
        // map a = {0,1} to a = { 0, -1ULL }
        movd    %eax,   %xmm2
        pxor    %xmm3,  %xmm3
        psubq   %xmm2,  %xmm3
        
        //mask x and y to zero if ( y > x && ! isnan( y) && ! isnan(x) )
        andpd   %xmm3,  %xmm1
        andpd   %xmm3,  %xmm0
        
        //Do the subtract
        subsd   %xmm1,  %xmm0
        ret

    #endif

#else

    //Not CARBONCORE LEGACY

    #if defined( __i386__ )
    ENTRY( fmaxf )
        flds    4+FRAME_SIZE(STACKP)          //{ y }
        flds    FRAME_SIZE(STACKP)            //{ x, y }
        fucomi  %st(0), %st(0)                //Check for x is NaN
        fcmovb  %st(1), %st(0)                //{ x or y, y}
        fxch                                  //{ y, x or y }
        fucomi  %st(1), %st(0)                //Check y < x  or y is NaN
        fcmovb  %st(1), %st(0)                //{ max, x or y }
        fstp    %st(1)                        //{ max }
        ret

    ENTRY( fminf )
        flds    4+FRAME_SIZE(STACKP)          //{ y }
        flds    FRAME_SIZE(STACKP)            //{ x, y }
        fucomi  %st(0), %st(0)                //Check for x is NaN
        fcmovb  %st(1), %st(0)                //{ x or y, y }
        fucomi  %st(1), %st(0)                //Check x < y  or y is NaN
        fxch                                  //{ y, x or y }
        fcmovb  %st(1), %st(0)                //{ max, x or y }
        fstp    %st(1)                        //{ max }
        ret

    //We have to use xmm here so that the subtraction doesnt take a double rounding
    ENTRY( fdimf )
        movss   FRAME_SIZE(STACKP), %xmm0
        movss   4+FRAME_SIZE(STACKP), %xmm1

        SUBP    $4,     STACKP

        //a == ( y < x || isnan( y) || isnan(x) )
        xor     %eax,   %eax
        ucomiss %xmm0,  %xmm1       
        setb    %al                 
        
        // map a = {0,1} to a = { 0, -1ULL }
        negl    %eax
        movd    %eax,   %xmm2
        
        //mask x and y to zero if ( y > x && ! isnan( y) && ! isnan(x) )
        andps   %xmm2,  %xmm1
        andps   %xmm2,  %xmm0
        
        //Do the subtract
        subss   %xmm1,  %xmm0
        movss   %xmm0,  (STACKP)
        flds    (STACKP)
        
        ADDP    $4,     STACKP
        ret

        
    #else

    ENTRY( fmaxf )
        SUBP    $8,    STACKP
        
        //create an array on the stack s[2] = { x, y }
        movss   %xmm0,  (STACKP)
        movss   %xmm1,  4(STACKP)

        //test a = x < y 
        xorq    %rax,   %rax
        xorq    %rdx,   %rdx
        ucomiss %xmm1,  %xmm0           
        setb    %al                     // a = x < y || isnan(y) || isnan(x)
        ucomiss %xmm1,  %xmm1           
        setp    %dl                     // isnan(y)
        xorq    %rdx,    %rax           // if (isnan(y)) a = 0

        // return s[a]
        movss   (STACKP,%rax,4), %xmm0  
        ADDP    $8,    STACKP
        ret

    ENTRY( fminf )
        SUBP    $8,    STACKP
        
        //create an array on the stack s[2] = { x, y }
        movss   %xmm0,  (STACKP)
        movss   %xmm1,  4(STACKP)

        //test a = y < x 
        xorq    %rax,   %rax
        xorq    %rdx,   %rdx
        ucomiss %xmm0,  %xmm1           
        setb    %al                     // a = y < x || isnan(y) || isnan(x)
        ucomiss %xmm1,  %xmm1           
        setp    %dl                     // isnan(y)
        xorq    %rdx,    %rax           // if (isnan(y)) a = 0

        // return s[a]
        movss   (STACKP,%rax,4), %xmm0  
        ADDP    $8,    STACKP
        ret

    ENTRY( fdimf )
        //a == ( y < x || isnan( y) || isnan(x) )
        xor     %eax,   %eax
        ucomiss %xmm0,  %xmm1       
        setb    %al                 
        
        // map a = {0,1} to a = { 0, -1ULL }
        negl    %eax
        movd    %eax,   %xmm2
        
        //mask x and y to zero if ( y > x && ! isnan( y) && ! isnan(x) )
        andps   %xmm2,  %xmm1
        andps   %xmm2,  %xmm0
        
        //Do the subtract
        subss   %xmm1,  %xmm0
        ret
        
    #endif


    // long double fminl( long double a, long double b )
    ENTRY( fminl )                      
        fldt        FIRST_ARG_OFFSET(STACKP)    //  {a}
        fldt        SECOND_ARG_OFFSET(STACKP)   //  {b,a}
        fucomi      %ST(0), %ST					//  test b is NaN
        fcmovu      %ST(1), %ST(0)				// if( b is NaN) b = a
        fucomi      %ST(1), %ST					//  b > a
        fcmovnb     %ST(1), %ST(0)
        fstp        %ST(1)
        ret
        
    // long double fmaxl( long double a, long double b )
    ENTRY( fmaxl )                      
        fldt        FIRST_ARG_OFFSET(STACKP)    //  {a}
        fldt        SECOND_ARG_OFFSET(STACKP)   //  {b,a}
        fucomi      %ST(0), %ST					//  test b is NaN
        fcmovu      %ST(1), %ST(0)				// if( b is NaN) b = a
        fld         %ST(1)						//  {a, b, a}
        fucomip     %ST(1), %ST					//  a >= b
        fcmovnb     %ST(1), %ST(0)
        fstp        %ST(1)
        ret

    // long double fdiml( long double a, long double b )
    ENTRY( fdiml )
        fldz									//	{0}
        fldt        FIRST_ARG_OFFSET(STACKP)    //  {a, 0}
        fldt        SECOND_ARG_OFFSET(STACKP)   //  {b, a, 0}
        fucomi      %ST(1), %ST					//  {b, a, 0}      b >= a  and not NaN
        fcmovnb		%ST(2), %ST(0)				//	{b or 0, a, 0 }
        fxch									//	{a, b or 0, 0 }
        fcmovnb		%ST(2), %ST(0)				//	{a or 0, b or 0, 0 }
        fsubp									//	{result, 0 }
        fstp		%ST(1)						//	{result}
        ret


#endif /*BUILDING_FOR_CARBONCORE_LEGACY*/