lrintl.s   [plain text]



/*
 * lrintl.s
 *
 *      by Ian Ollmann
 *
 *  Copyright Apple Inc. 2007.
 *
 *  C99 implementation of lrintl and llrintl
 */
 
#include <machine/asm.h>
#include "abi.h"

#if ! defined( __LP64__ )

ENTRY( lrintl )
    fldt    FRAME_SIZE( STACKP )                // { x }
    movswl  8+FRAME_SIZE( STACKP),      %eax    // Load signed exponent
    movl    %eax,                       %ecx    // set aside sign
    andl    $0x7fff,                    %eax    // remove sign
    cmpl    $0x401d,                    %eax    // if( |x| > 0x1.0p30 || isnan(x) )
    jae     2f                                  //      goto 2

    // |x| < 0x1.0p30 || isnan(x)
    fistpl  FRAME_SIZE( STACKP )
1:  movl    FRAME_SIZE( STACKP ),       %eax    // load result
    ret
    
    //|x| >= 0x1.0p30 || isnan(x)
2:  fistl   FRAME_SIZE( STACKP )
    fucomip %st(0),     %st(0)                  // if( isnan(x) )
    jp      1b                                  //      goto 1

    // |x| >= 0x1.0p30. If sign != old sign, xor with -1 
    movl    FRAME_SIZE( STACKP ),       %eax    // load result
    xorl    %eax,                       %ecx    // check to see if the sign changed
    sarl    $31,                        %ecx    // sign changed ? -1 : 0
    xorl    %ecx,                       %eax    // if the sign changed, xor with -1  (flips 0x80000000 to 0x7fffffff)
    ret

#define MOVSW   movswl

#else
#define MOVSW   movswq

ENTRY( lrintl )
#endif
ENTRY( llrintl )
    MOVSW   8+FRAME_SIZE( STACKP),  AX_P        // load signed exponent
    fldt    FRAME_SIZE( STACKP )                //  { x }
    mov     AX_P,                   CX_P        // signed exponent
    and     $0x7fff,                AX_P        // remove sign
    cmp     $0x403d,                AX_P        // if( exponent + bias >= 16383+62 )
    jae     2f                                  //      goto 1

    // |x| < 0x1.0p62. Nothing can go wrong. Return the long long.
1:  fistpll FRAME_SIZE( STACKP )                //  store out x as 64-bit int with appropriate rounding

#if defined( __LP64__ )
    movq    FRAME_SIZE( STACKP ),   %rax
#else
    movl    FRAME_SIZE( STACKP ),   %eax
    movl    4+FRAME_SIZE( STACKP ), %edx
#endif
    ret

    // |x| >= 2**62 || isnan(x) -- might be invalid
2:  fucomi  %st(0), %st(0)                      // if( x != x )
    jp      1b
    
    fistpll FRAME_SIZE( STACKP )                //  store out x as 64-bit int with appropriate rounding

    // Load data in. If the sign changed, xor with -1
#if defined( __LP64__ )
    movq    FRAME_SIZE( STACKP ),   %rax
    xorq    %rax,                   %rcx
    sarq    $63,                    %rcx
    xorq    %rcx,                   %rax
#else
    movl    FRAME_SIZE( STACKP ),   %eax
    movl    4+FRAME_SIZE( STACKP ), %edx
    xorl    %edx,                   %ecx
    sarl    $31,                    %ecx
    xorl    %ecx,                   %eax
    xorl    %ecx,                   %edx
#endif
    ret