modff.s   [plain text]



/*
 *  modff.s
 *
 *      by Ian Ollmann
 *
 *  Copyright (c) 2007 Apple Inc. All Rights Reserved.
 */

#include <machine/asm.h>
#include "abi.h"

#if defined( __i386__ )
    #define RESULT_P        %eax
#else
    #define RESULT_P        %rdi
#endif


ENTRY( modff )
#if defined( __i386__ )
    movl    FRAME_SIZE( STACKP ),       %ecx            //load x
#else
	movd	%xmm0,						%ecx
#endif
    movl    %ecx,                       %edx            // x
    andl    $0x7fffffff,                %ecx            // |x|
    xorl    %ecx,                       %edx            // sign of x
    addl    $0x35000000,                %ecx            // add 128-22 to exponent. This forces Inf, NaN, numbers >= 2**23 to be negative
    cmpl    $0x74800000,                %ecx            // values with exponents less than 128-22 are fractional numbers only
    jl      1f                                          // branch for all exceptional conditions
    
    //we presume that the common case is 1.0 <= x < 2**23
#if defined( __i386__ )
    movss   FRAME_SIZE( STACKP ),       %xmm0			// load x
#endif
	movd	%edx,						%xmm2			// load signof( x ) to xmm
    shrl    $23,                        %ecx
    subl    $(127+128-22),              %ecx
    movl    $0xff800000,                %eax
    sarl    %cl,                        %eax
    movd    %eax,                       %xmm1
#if defined( __i386__ )
    movl    4+FRAME_SIZE( STACKP),      RESULT_P
#endif
	andps	%xmm0,						%xmm1			// find trunc(x)
    subss   %xmm1,                      %xmm0			// fract = x - trunc(x)
    orps    %xmm2,                      %xmm0			// fract = copysign( fract, x )
#if defined( __i386__ )
    movss   %xmm0,                      (RESULT_P)
    flds    (RESULT_P)
#endif
    movss   %xmm1,                      (RESULT_P)
    ret
    
1:  jae     2f                                          // Inf, NaN, big numbers go to 2
    // |x| < 1.0
#if defined( __i386__ )
    movl    4+FRAME_SIZE( STACKP),      RESULT_P
#endif
    movl    %edx,                       (RESULT_P)
#if defined( __i386__ )
    flds    FRAME_SIZE( STACKP )
#endif
    ret
    
2:  cmp     $0xb4800000,                %ecx            
    ja      3f                          //do NaNs elsewhere

    // |x| >= 2**23
#if defined( __i386__ )
    movl    4+FRAME_SIZE( STACKP),      RESULT_P
    movl    %edx,                       (RESULT_P)
    flds    (RESULT_P)
    movl    FRAME_SIZE( STACKP ),       %edx
    movl    %edx,                       (RESULT_P)
#else
	movss	%xmm0,						(RESULT_P)
    movd    %edx,                       %xmm0
#endif
    ret
      
3:  //Nan
#if defined( __i386__)
    movl    4+FRAME_SIZE( STACKP),      RESULT_P
    flds    FRAME_SIZE( STACKP )                        // { x }
    fld     %st(0)
    fstp    (RESULT_P)
#else
    movss   %xmm0,                      (RESULT_P)
#endif
    ret