modf.s   [plain text]



/*
 *  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__