310 lines
5.8 KiB
NASM
310 lines
5.8 KiB
NASM
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
|