floorl.s   [plain text]


/*
 *  floorl.s
 *
 *      by Ian Ollmann
 *
 *  Copyright (c) Apple Inc. 2007. All Rights Reserved.
 *
 *  C99 implementation of floorl for __i386__ and __x86_64__.
 */
 
 
#include <machine/asm.h>
#include "abi.h"


ENTRY( floorl )
    movswl  8+FRAME_SIZE( STACKP ),     %eax        // load signed exponent
    movl    %eax,                       %edx        // sign + exponent
    andl    $0x7fff,                    %eax        // exponent
    subl    $0x3fff,                    %eax        // remove bias
    cmpl    $63,                        %eax        // if( |x| >= 0x1.0p63 || |x| < 1.0 || isnan(x) )
    jae     2f                                      //      goto 2
    
    movl    $63,                        %ecx
    movq    FRAME_SIZE( STACKP ),       %xmm0       // significand
    subl    %eax,                       %ecx        // 63 - exponent
    pcmpeqb %xmm1,                      %xmm1       // -1LL
    movd    %ecx,                       %xmm7       // 63-exponent
    pxor    %xmm2,                      %xmm2       // 0
    psubq   %xmm1,                      %xmm2       // 1
    movdqa  %xmm2,                      %xmm1       // 1
    psllq   %xmm7,                      %xmm2       // one's bit
    psubq   %xmm1,                      %xmm2       // fract mask
    pandn   %xmm0,                      %xmm2
    movq    %xmm2,                      FRAME_SIZE( STACKP )
    pcmpeqd %xmm2,                      %xmm0
    pmovmskb   %xmm0,                   %eax
    cmp     $0xffff,                    %eax
    fldt    FRAME_SIZE( STACKP )                    // result
    je      1f
    
    //need to set the inexact flag and correct rounding
    sarl    $31,                        %edx
    andl    $0xbf800000,                %edx
    movl    %edx,                       FRAME_SIZE(STACKP)
    fadds   FRAME_SIZE( STACKP )                                // correct rounding

    // set inexact
    fldpi
    fmul    %st(0), %st(0)
    fstp    %st(0)    
    
1:  ret

// |x| >= 0x1.0p63 || |x| < 1.0 || isnan(x)    
2:  jge     3f
    
//  |x| < 1.0
    fldt    FRAME_SIZE( STACKP )                    // { x }
    fldz                                            // { 0, x }
    fucomip %st(1), %st(0)                          // { x }
    je      1b

    fistpl  FRAME_SIZE( STACKP )
    fldz                                            //  { 0 }
    fld1                                            //  { 1, 0 }
    fchs                                            //  { -1, 0 }
    fcmovb  %st(1), %st(0)
    fstp    %st(1)
    ret

// |x| >= 0x1.0p63 || isnan(x)    
3:  fldt    FRAME_SIZE(STACKP)
    fldz
    faddp
    ret