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