page	,132
	title	ldsplit	 - split long double
;*** 
;ldsplit.asm - split long double into two doubles
;
;	Copyright (c) 1992-2001, Microsoft Corporation. All rights reserved.
;
;Purpose:
;   Helper for handling 10byte long double quantities if there is no
;   compiler support.
;
;Revision History:
;
;   04/21/92	GDP	written
;
;*******************************************************************************

.xlist
	include cruntime.inc
	include mrt386.inc
	include elem87.inc
	include os2supp.inc
.list

.data

labelB TagTable
			; C2 C1 C0 C3	 Meaning
	db	2 * 4	;  0  0  0  0  +Unnormal=>   NAN
	db	1 * 4	;  0  0  0  1  +Zero	=>   Zero
	db	2 * 4	;  0  0  1  0  +NAN	=>   NAN
	db	2 * 4	;  0  0  1  1	Empty	=>   NAN
	db	2 * 4	;  0  1  0  0  -Unnormal=>   NAN
	db	1 * 4	;  0  1  0  1  -Zero	=>   Zero
	db	2 * 4	;  0  1  1  0  -NAN	=>   NAN
	db	2 * 4	;  0  1  1  1	Empty	=>   NAN
	db	0 * 4	;  1  0  0  0  +Normal	=>   Valid
	db	4 * 4	;  1  0  0  1  +Denormal=>   Denormal
	db	3 * 4	;  1  0  1  0  +Infinity=>   Infinity
	db	2 * 4	;  1  0  1  1	Empty	=>   NAN
	db	0 * 4	;  1  1  0  0  -Normal	=>   Valid
	db	4 * 4	;  1  1  0  1  -Denormal=>   Zero
	db	3 * 4	;  1  1  1  0  -Infinity=>   Infinity
	db	2 * 4	;  1  1  1  1	Empty	=>   NAN

; factor = 2^64
staticQ factor,	      043F0000000000000R

LDBIAS		equ	3fffh
DBIAS		equ	3ffh
MAX_BIASED_DEXP equ	7feh

CODESEG



table:
	dd	valid
	dd	zero
	dd	nan
	dd	inf
	dd	denorm



;***
;int _ldsplit(pld, pd1, pd2) - split long double
;
;Purpose:
;   partition a long double quantity ld into two double quantities
;   d1, d2 and an integer scaling factror s. The mantissa of d1 has
;   the high order word of the mantissa of ld. Respectively, the
;   mantissa of d2 has the low order word of the mantissa of ld.
;   The following relation should be satisfied:
;
;	    ld == ((long double)d1 + (long double)d2) * 2^s
;
;   s is 0, unless d1 or d2 cannot be expressed as normalized
;   doubles; in that case s != 0, and .5 <= d1 < 1
;
;
;Entry:
;   pld     pointer to the long double argument
;   pd1     pointer to d1
;   pd2     pointer to d2
;
;Exit:
;   *pd1, *pd2 are updated
;   return value is equal to s
;
;
;Exceptions:
;   This function should raise no IEEE exceptions.
;   special cases:
;     ld is QNAN or SNAN: d1 = QNAN, d2 = 0, s = 0
;     ls is INF:	  d1 = INF, d2 = 0, s = 0
;
;
;******************************************************************************/


_ldsplit proc	uses ebx edx edi, pld:dword, pd1:dword, pd2:dword
	local	ld:tbyte
	local	exp_adj:dword
	local	retvalue:dword
	local	denorm_adj:dword

	mov	[retvalue], 0		; default return value
	mov	[denorm_adj], 0
	mov	ebx, [pld]
	fld	tbyte ptr [ebx]
	fxam
	fstsw	ax
	fstp	[ld]			; store to local area
	shl	ah, 1
	sar	ah, 1
	rol	ah, 1
	and	ah, 0fh
	mov	al, ah
	mov	ebx, dataoffset TagTable	; Prepare for XLAT
	xlat
	movzx	eax, al
	mov	ebx, OFFSET table
	add	ebx, eax

	mov	edx, pd1	    ; edx points to the high order double
	mov	edi, pd2	    ; edi points to the low order double

	jmp	[ebx]

lab valid
	; have a valid normalized non-special long double

	mov	eax, dword ptr [ld]
	or	eax, eax
	jz	d2zero

				    ; compute mantissa an exponent for d2
	mov	[exp_adj], 31	    ; adjustment to be subtracted from exp of *pd2

	;
	; compute mantissa of d2
	; shift left low order word of ld, until a '1' is hit
	;

	cmp	eax, 0ffffh
	ja	shl16done
	sal	eax, 16
	add	[exp_adj], 16

lab shl16done
	cmp	eax, 0ffffffh
	ja	shl8done
	sal	eax, 8
	add	[exp_adj], 8

lab shl8done
lab shiftloop
	inc	[exp_adj]
	sal	eax, 1
	jnc	shiftloop

	; now eax contains the mantissa for d2
	; exp_adj is the difference of the
	; exponents of d1 and d2
	; exp_adj should be in the range
	;	  32 <= exp_adj <= 63
	; By convention, if exp_adj is 0 then
	; d2 is zero

lab setd2man
	mov	dword ptr [edi+4], 0
	shld	dword ptr [edi+4], eax, 20
	shl	eax, 20
	mov	[edi], eax

	;
	; set mantissa of d1
	;

lab setd1man
	mov	eax, dword ptr [ld+4]
	sal	eax, 1			    ; get rid of explicit bit
	mov	dword ptr [edx+4], 0
	shld	dword ptr [edx+4], eax, 20
	shl	eax, 20
	mov	[edx], eax

				    ; check if exponent is in range
	mov	ax, word ptr [ld+8]

	and	ax, 07fffh		; clear sign bit
	movzx	eax, ax

	sub	eax, LDBIAS - DBIAS

	cmp	eax, MAX_BIASED_DEXP
	ja	expoutofrange


	cmp	eax, [exp_adj]
	jb	expoutofrange


	;
	; set exponent of d1
	;

lab setexp1
	mov	ebx, eax		; save exp value
	shl	eax, 20
	or	dword ptr [edx+4], eax


	cmp	[exp_adj], 0
	je	exp2zero
	sub	ebx, [exp_adj]
	je	exp2zero
lab setexp2
	shl	ebx, 20
	or	dword ptr [edi+4], ebx
	mov	[retvalue], 0


lab setsign				; set correct signs and return
					; at this point eax contains
					; the return value
	mov	bx, word ptr [ld+8]
	and	bx, 1 SHL 15		; get sign

	or	[edi+6], bx		; set sign bit
	or	[edx+6], bx		; set sign bit

	mov	eax, [retvalue]
	add	eax, [denorm_adj]
	ret


lab d2zero
	mov	[exp_adj], 0
	jmp	setd2man

lab exp2zero
	mov	ebx, 0
	jmp	setexp2



lab expoutofrange
	mov	ebx, DBIAS
	mov	ecx, ebx
	sub	ecx, [exp_adj]

	shl	ebx, 20
	or	dword ptr [edx+4], ebx

	shl	ecx, 20
	or	dword ptr [edi+4], ecx

	sub	eax, DBIAS		; unbias exp
	mov	[retvalue], eax		; this is the return value
	jmp	short setsign


lab zero
	mov	dword ptr [edx],   0
	mov	dword ptr [edx+4], 0
	mov	dword ptr [edi],   0
	mov	dword ptr [edi+4], 0
	jmp	setsign

lab nan
	mov	dword ptr [edx],   0
	mov	dword ptr [edx+4], 07ff80000h
	mov	dword ptr [edi],   0
	mov	dword ptr [edi+4], 0
	jmp	setsign

lab inf
	mov	dword ptr [edx],   0
	mov	dword ptr [edx+4], 07ff00000h
	mov	dword ptr [edi],   0
	mov	dword ptr [edi+4], 0
	jmp	setsign

lab denorm

	;
	; We have a long double denormal
	; so we know for sure that this is out of the double
	; precision range, and the return value of _ldsplit
	; should be non-zero.
	; Multiply the denormal by 2^64, then adjust the
	; return value by subtracting 64
	;


	; this assumes denormal exception masked
	fld	[ld]
	fmul	[factor]
	fstp	[ld]
	mov	[denorm_adj], 64
	jmp	valid



_ldsplit endp

end