/* * modf.s * * by Steve Canon (scanon) * * Copyright (c) 2008 Apple Inc. All Rights Reserved. * * Rewritten by Steve Canon in December '08 to fix * behavior of small signaling nans and to get the * sign of a zero fractional part correct. */ // double modf(double x, double *iptr); // // breaks x into integral and fractional parts, each of which has the same sign as the argument. // the fractional part is returned, and iptr holds the integral part. // // Special Cases: // // Input Fractional Part Integral Part // +-inf +-0 +-inf // NaN NaN NaN #if defined __i386__ .text .align 4 .globl _modf _modf: movl 8(%esp), %eax // high word of x andl $0x7fffffff, %eax // high word of |x| subl $0x3ff00000, %eax // subtract off exponent bias movsd 4(%esp), %xmm0 // x pcmpeqb %xmm3, %xmm3 psllq $63, %xmm3 movapd %xmm3, %xmm4 // set aside signbit mask for later use andpd %xmm0, %xmm3 // signbit(x) cmpl $0x03400000, %eax // compare to unbiased 2**52 jae 1f // 1.0 <= |x| < 2**52 shrl $20, %eax // unbiased exponent of x movl $52, %edx subl %eax, %edx movd %edx, %xmm2 // 52 - unbiased exponent of x pcmpeqb %xmm1, %xmm1 psllq %xmm2, %xmm1 // mask for integral bits of x andpd %xmm0, %xmm1 // trunc(x) subsd %xmm1, %xmm0 // fractional part, except that sign of zero may be wrong andnpd %xmm0, %xmm4 // |fractional part| orpd %xmm3, %xmm4 // copysign(fractional part, x) movl 12(%esp), %ecx // iptr movsd %xmm4, 4(%esp) movsd %xmm1, (%ecx) // store integral part to iptr fldl 4(%esp) // return fraction part on the x87 stack retl 1: movl 12(%esp), %ecx // iptr jge 2f // |x| < 1.0 movsd %xmm3, (%ecx) // *iptr = copysign(0.0, x) fldl 4(%esp) // fractional part = x retl 2: ucomisd %xmm0, %xmm0 // check for NaN jp 3f // |x| >= 2**52 movsd %xmm3, 4(%esp) // fractional part = copysign(0.0, x) 3: movsd %xmm0, (%ecx) // *iptr = x fldl 4(%esp) retl #else // __x86_64__ .const .align 4 absmask: .quad 0x7fffffffffffffff one: .quad 0x3ff0000000000000 .text .align 4 .globl _modf _modf: movsd absmask(%rip), %xmm1 andpd %xmm0, %xmm1 // |x| movd %xmm1, %rax xorpd %xmm0, %xmm1 // copysign(0.0, x) subq one(%rip), %rax // subtract off exponent bias movq $52, %rcx sarq %cl, %rax cmpq %rcx, %rax // compare exponent of x to 52 jae 1f // 1.0 <= |x| < 2**52 subq %rax, %rcx // 52 - unbiased exponent of x pcmpeqb %xmm2, %xmm2 movd %rcx, %xmm3 psllq %xmm3, %xmm2 // mask for integral bits of x andpd %xmm0, %xmm2 // trunc(x) subsd %xmm2, %xmm0 // fractional part, except sign of zero may be wrong andpd absmask(%rip), %xmm0 // |fractional part| orpd %xmm1, %xmm0 // copysign(fractional part, x) movsd %xmm2, (%rdi) // *iptr = trunc(x) retq 1: jge 2f // |x| < 1.0 movsd %xmm1, (%rdi) // *iptr = copysign(0.0, x) retq 2: ucomisd %xmm0, %xmm0 // check for NaN jp 3f // |x| >= 2**52 movsd %xmm0, (%rdi) // *iptr = x movapd %xmm1, %xmm0 // fractional part = copysign(0.0, x) retq 3: movsd %xmm0, (%rdi) // *iptr = x retq #endif // __ARCH__