s_floor.s   [plain text]


/*
 * Written by Ian Ollmann
 * Copyright © 2005, Apple Computer Inc. All rights reserved.
 */

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


ENTRY( floorl )
    xorl        %ecx,                       %ecx
    fldz                                    // { 0 }
    movw        8+FIRST_ARG_OFFSET(STACKP), %cx
    andw        $0x7fff,                    %cx
	fldt		FIRST_ARG_OFFSET(STACKP)	// { f, 0 }
    cmpw        $(16383+63),                %cx         //test for NaNs, Infs, large integer
    jae         1f
    fucomi      %st(1),     %st(0)                      // test for zeros
    je          1f

    fadd        %st(0),     %st(1)          //{ f, f }

    //do rint
    fistpll    FRAME_SIZE( STACKP )         // { f }
    fildll      FRAME_SIZE( STACKP )        // { rintl(f), f }

	fucomi		%ST(1), %ST					//  test for rintl(f) <= f or NaN
    jbe         1f
	fld1									//{ 1, rintl(f), f }
	fsubrp		%ST(0), %ST(1)				//{ floorl(f), f }
1:  fstp        %st(1)
	ret

ENTRY( floorf )
#if defined( __i386__ )
    movl    FRAME_SIZE( STACKP ),       %ecx
    movss   FRAME_SIZE( STACKP ),       %xmm0
#else
    movd    %xmm0,                      %ecx
#endif
    andl    $0x7fffffff,                %ecx            // |x|
    subl    $1,                         %ecx            // subtract 1. This forces |+-0| to -0
    cmpl    $0x4afffffe,                %ecx            // values >= 0x4b000000 - 1 are either integers, NaN or Inf
    ja      1f                                          // unsigned compare adds 0 to the list

    cvttps2dq   %xmm0,                  %xmm2
    movl    $0xBf800000,                %edx            // -1.0f
    cvtdq2ps    %xmm2,                  %xmm2
    movd    %edx,                       %xmm1
    cmpltss %xmm2,                      %xmm0
    andps   %xmm1,                      %xmm0
    addss   %xmm2,                      %xmm0
#if defined( __i386__ )
    movss   %xmm0,                      FRAME_SIZE( STACKP )
#endif
    
1:
#if defined( __i386__ )
    flds    FRAME_SIZE( STACKP )
#endif
    ret


#if defined ( __i386__ )

    ENTRY( floor )
        movsd       FRAME_SIZE( STACKP ),   %xmm0
        fldl        FRAME_SIZE( STACKP )
        xorps       %xmm1,                  %xmm1
        ucomisd     %xmm0,                  %xmm1
        psrlq       $32,                    %xmm0
        je          1f
        movd        %xmm0,                  %ecx
        andl        $0x7fffffff,            %ecx
        cmpl        $0x43300000,            %ecx
        jae         1f

        //rint(f)
        fld         %st(0)                      // { x, x}
        fistpll     FRAME_SIZE( STACKP )
        fildll      FRAME_SIZE( STACKP )
                                                
        fucomi      %st(1), %st(0)          // { rint(x), x }
        fstp        %st(1)                  // { rint(x) }
        jbe         1f

        fld1                                // { 1, trunc(x) }
        fsubrp      %st(0), %st(1)          // { floor(x) }
            
    1:  ret

#else //x86_64

    ENTRY( floor )
        movd    %xmm0,                      %rcx
        movq    $-1,                        %rdx            // -1ULL
        movq    $0x43300000,                %rax            
        shrq    $1,                         %rdx            // 0x7fffffffffffffff
        shlq    $32,                        %rax            // 0x1.0p52
        andq    %rdx,                       %rcx            // |x|
        subq    $1,                         %rcx            // push 0 negative
        cmpq    %rax,                       %rcx            // |x| - 1 ulp >= 0x1.0p52?
        jae     1f                                          // if x == 0.0f, x >= 2**23 or x is NaN, skip to the end

        //find trunc(x)
        cvttsd2si   %xmm0,                  %rax
        cvtsi2sd    %rax,                   %xmm1
        cmpltsd		%xmm1,                  %xmm0           
        cvtdq2pd    %xmm0,                  %xmm0
        addsd       %xmm1,                  %xmm0
        
    1:  ret

#endif