windows-nt/Source/XPSP1/NT/base/crts/fpw32/tran/i386/87cdisp.asm

532 lines
11 KiB
NASM
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
page ,132
title 87cdisp - C transcendental function dispatcher
;***
;87cdisp.asm - C transcendental function dispatcher (80x87/emulator version)
;
; Copyright (c) 1987-2001, Microsoft Corporation. All rights reserved.
;
;Purpose:
; Common dispatch code and error handling for C transcendental functions
;
;Revision History:
; 07-04-84 GFW initial version
; 12-21-84 GFW correctly point to name in matherr struct
; 05-12-85 GFW return HUGE correctly signed on ERANGE errors
; fill 2nd operand for matherr structure correctly
; 07-05-85 GFW check for possible overflow on PLOSS errors
; in this case OVERFLOW overrides PLOSS
; 07-08-85 GFW added FWAIT in useHUGE
; 11-20-85 GFW faster RANGE checking
; 09-30-86 JMB internationalized error message handling
; 03-09-87 BCM changed writestr to _wrt2err (extern)
; 04-14-87 BCM log(0.0) and log10(0.0) sets errno to ERANGE
; for MS C 5.0 (ANSI compatible); errno is still
; set to EDOM for IBM C 2.0 (System V compatible).
; 04-28-87 BCM Added _cintrindisp1 and _cintrindisp2
; for C "intrinsic" versions of pow, log, log10, exp,
; cos, sin, tan, acos, asin, atan, atan2,
; cosh, sinh, tanh, sqrt, ... for MS C 5.0
; 08-04-87 BCM Removed "externP write" declaration.
; 08-17-87 BCM Changed _wrt2err from near to model-dependent
; except for IMBC20; this is because of QC core lib
; 10-12-87 BCM OS/2 support C library changes
; 11-24-87 BCM added _loadds under ifdef DLL
; 01-18-88 BCM eliminated IBMC20; ifos2,noos2 ==> ifmt, nomt
; 02-10-88 WAJ MTHREAD libraries now lock stderr when printing errors
; 04-25-88 WAJ _cpower is on the stack for MTHREAD so must be set to 1
; 07-11-88 WAJ address of matherr structure was incorrect in MTHREAD case
; 08-24-88 WAJ 386 version.
; 11-20-89 WAJ 386 MTHREAD is no longer _pascal.
; 08-17-90 WAJ Now uses _stdcall.
; 10-15-90 WAJ Fixed intrinsic/2 argument problems.
; 05-17-91 WAJ Added _STDCALL ifdefs.
; 08-27-91 JCR ANSI naming
; 09-15-91 GDP Added _cwrt2err. _NMSG_WRITE is no longer _pascal
; 11-15-91 GDP Removed error message display stuff
; moved exception structure to stack frame, even for
; single thread code (allow recursive calls of
; transcendentals through matherr)
; call _87except after fsave
; put Localfac on the stack for multi thread
; 02-10-92 GDP changed error handling avoid polluting the fp status word
; 03-15-92 GDP extensive changes in error detection scheme
; 10-27-92 SKS Re-arranged some code to make this work with MASM 6.10
; 11-06-92 GDP merged changes from the fp tree on \\vangogh: removed
; saveflag, added __fastflag, new range error checking
; 09-06-94 CFW Replace MTHREAD with _MT.
; 04-06-01 PML CHECKOVER should check overflow, not underflow (vs7#132450)
;*******************************************************************************
.xlist
include cruntime.inc
include mrt386.inc
include os2supp.inc
include elem87.inc
.list
EDOM = 33 ; math error numbers
ERANGE = 34
EDOMAIN = 120 ; internal error number for DOMAIN
ESING = 121 ; internal error number for SING
ETLOSS = 122 ; internal error number for TLOSS
.data
comm _matherr_flag:dword
extrn __fastflag:dword
.const
staticQ DblMax, 07fefffffffffffffR
staticQ DblMin, 00010000000000000R
staticQ IeeeAdjO, 0c098000000000000R
staticQ IeeeAdjU, 04098000000000000R
staticQ _infinity, 07ff0000000000000R
staticQ _zero, 00000000000000000R
ifndef _MT
.data?
staticQ LocalFac, ?
intrinflag db ?
else ;_MT
MTStackFrame struc
MTS_LocalFac dq ?
MTS_cdispflags db ?
MTStackFrame ends
MTSFISize equ ((size MTStackFrame) + ISIZE - 1) and (not (ISIZE-1))
LocalFac equ <MTSF.MTS_LocalFac>
cdispflags equ <MTSF.MTS_cdispflags>
INTRINFLAG = 01h
TWOARGFLAG = 02h
endif ;_MT
; error value action table
;labelW retvaltab
; DNCPTR codeOFFSET useretval
page
CODESEG
extrn _trandisp1:near
extrn _trandisp2:near
extrn _87except:proc
;----------------------------------------------------------
;
; intrinsic versions: TRANSCENDENTAL DISPATCH ROUTINES
;
;----------------------------------------------------------
;
; _cintrindisp1 - Intrinsic Dispatch for 1 arg DP transcendental
; _cintrindisp2 - Intrinsic Dispatch for 2 arg DP transcendental
;
; rdx - function dispatch table address
;
;----------------------------------------------------------
_cintrindisp2 proc uses RBXONLY
local DLSF[DSFISize]:IWORD
ifmt <local MTSF[MTSFISize]:IWORD>
fstcw [DSF.savCntrl]
fwait
; store the args in case they are needed by matherr.
; Generally avoid storing since this may generate
; various exceptions (overflow, underflow, inexact, invalid)
; Args will not be available to an exception handler and
; users should not use /Oi if interested in IEEE conformance
cmp [_matherr_flag], 0
JSE save2arg
lab resume2
;ifmt <mov [_cpower], 1> ; set _cpower to C semantics
; DISABLED this feature since pow(0,0)
; will return 1 in C (NCEG spec) which
; is the same as in FORTRAN --GDP
call _trandisp2
ifmt <or [cdispflags], (INTRINFLAG OR TWOARGFLAG)>
nomt <mov [intrinflag], 1>
call cintrinexit
ret
lab save2arg
fxch
fst [DSF.arg1]
fxch
fst [DSF.arg2]
jmp resume2
_cintrindisp2 endp
_cintrindisp1 proc uses RBXONLY
local DLSF[DSFISize]:IWORD
ifmt <local MTSF[MTSFISize]:IWORD>
fstcw [DSF.savCntrl]
cmp [_matherr_flag], 0
JSE save1arg
lab resume1
call _trandisp1
ifmt <or [cdispflags],INTRINFLAG>
ifmt <and [cdispflags],(NOT TWOARGFLAG)>
nomt <mov [intrinflag], 1>
call cintrinexit
ret
lab save1arg
fst [DSF.arg1]
jmp resume1
_cintrindisp1 endp
;*******************************************************************************
;*
;* TRANSCENDENTAL DISPATCH ROUTINES
;*
;*******************************************************************************
;*
;* _ctrandisp1 - Dispatch for 1 arg DP transcendental
;* _ctrandisp2 - Dispatch for 2 arg DP transcendental
;*
;* edx - function dispatch table address
;*
;*******************************************************************************
;*
;* Two arg standard dispatch.
;*
_ctrandisp2 proc uses ebx, parm1:qword, parm2:qword
local DLSF[DSFISize]:IWORD
ifmt <local MTSF[MTSFISize]:IWORD>
push dword ptr [parm1+4] ; load arg1
push dword ptr [parm1]
call _fload
ifndef _STDCALL
add esp, 8
endif
push dword ptr [parm2+4] ; load arg2
push dword ptr [parm2]
call _fload
ifndef _STDCALL
add esp, 8
endif
fstcw [DSF.savCntrl]
ifmt <or [cdispflags], TWOARGFLAG>
ifmt <mov [_cpower], 1> ; set _cpower to C semantics
call _trandisp2
call ctranexit
ifdef _STDCALL
ret 16
else
ret
endif
;*
;* Check for overflow and errors.
;*
ctranexit::
ifmt <and [cdispflags], (NOT INTRINFLAG)>
nomt <mov [intrinflag], 0>
cintrinexit::
cmp __fastflag, 0
JSNZ restoreCW
fst qword ptr [LocalFac] ; cast result to double precision
;
; PROBLEM: Since the intrinsics may be given an argument anywhere
; in the long double range, functions that are not normally
; expected to overflow (like sqrt) may generate IEEE exceptions
; at this point. We can cure this by making the checkrange test
; standard.
;
mov al, [DSF.ErrorType] ; check for errors
or al, al
JE checkinexact
cmp al, CHECKOVER
JE checkoverflow
cmp al, CHECKRANGE
JSE checkrng
or al, al
JSE restoreCW
CBI
mov [DSF.typ], rax ; set exception type
jmp haveerror
lab checkinexact
; This will be the most common path because of
; the nature of transcendentals. If inexact is
; unmasked in user's cw and active, raise it
mov ax, [DSF.savCntrl]
and ax, 20h
JSNZ restoreCW ; inexact exception masked
fstsw ax
and ax, 20h
JSZ restoreCW
mov [DSF.typ], INEXACT
jmp haveerror
lab restoreCW
lab restoreCW2
fldcw [DSF.savCntrl] ; load old control word
fwait
retn
lab checkrng
mov ax, word ptr [LocalFac+6] ; get exponent part
and ax, 07ff0h
or ax, ax
JSE haveunderflow
cmp ax, 07ff0h
JSE haveoverflow
jmp checkinexact ; assume possibly inexact result
lab checkoverflow
mov ax, word ptr [LocalFac+6] ; get exponent part
and ax, 07ff0h
cmp ax, 07ff0h
JSE haveoverflow
jmp checkinexact ; assume possibly inexact result
lab haveunderflow
mov [DSF.typ], UNDERFLOW
fld IeeeAdjU
fxch
fscale
fstp st(1)
fld st(0)
fabs
fcomp [DblMin]
fstsw ax
sahf
JSAE haveerror
fmul [_zero]
jmp short haveerror
lab haveoverflow
mov [DSF.typ], OVERFLOW
fld IeeeAdjO
fxch
fscale
fstp st(1)
fld st(0)
fabs
fcomp [DblMax]
fstsw ax
sahf
JSBE haveerror
fmul [_infinity]
lab haveerror
; fill error structure and call matherr
push rsi ; save si
push rdi
mov rbx, [DSF.Function] ; get function jmp table address
inc rbx
mov [DSF.nam], rbx ; save name address
ifmt <test cdispflags, INTRINFLAG>
nomt <cmp [intrinflag], 0>
JSNE aftercopy
;
; copy function args (for matherr structure)
;
cld
lea esi, [parm1]
lea edi, [DSF.arg1]
movsd
movsd
cmp [rbx-1].fnumarg, 1 ; check for 2nd parameter
JSE aftercopy
lea esi, [parm2]
lea edi, [DSF.arg2]
movsd
movsd
lab aftercopy
lab useretval
fstp [DSF.retval] ; store return value
;
; If intrinsic calling convention, an 'fsave' is required
; before matherr starts doing any fp operations.
; (This needs to be documented.)
lea rax, [DSF.typ]
lea rbx, [DSF.savCntrl]
push rbx
push rax
mov rbx, [DSF.function]
mov al, [rbx].fnumber
CBI
push rax
call _87except ; _fpexcept(&exception, &savedcw)
ifndef _STDCALL
add esp, 12 ; clear arguments if _cdecl.
endif
lab movretval
pop rdi ; restore di
pop rsi ; restore si
fld [DSF.retval] ; this assumes that the user
; does not want to return a
; signaling NaN
jmp restoreCW ; restore CW and return
_ctrandisp2 endp
;*
;* One arg standard dispatch.
;*
_ctrandisp1 proc uses ebx, parm1:qword
local DLSF[DSFISize]:IWORD
ifmt <local MTSF[MTSFISize]:IWORD>
push dword ptr [parm1+4] ; load arg1
push dword ptr [parm1]
call _fload
ifndef _STDCALL
add esp, 8
endif
fstcw [DSF.savCntrl]
ifmt <and [cdispflags],(NOT TWOARGFLAG)>
call _trandisp1
call ctranexit
ifdef _STDCALL
ret 8
else
ret
endif
_ctrandisp1 endp
;
; Load arg in the fp stack without raising an exception if the argument
; is a signaling NaN
;
_fload proc uses ebx, parm:qword
local tmp:tbyte
mov ax, word ptr [parm+6] ; get exponent field
mov bx, ax ; save it
and ax, 07ff0h
cmp ax, 07ff0h ; check for special exponent
JSNE fpload
; have special argument (NaN or INF)
or bx, 07fffh ; preserve sign, set max long double exp
mov word ptr [tmp+8], bx
; convert to long double
mov eax, dword ptr [parm+4]
mov ebx, dword ptr [parm]
shld eax, ebx, 11
; the MSB of the significand is
; already 1 because of the exponent value
mov dword ptr [tmp+4], eax
mov dword ptr [tmp], ebx
fld tmp
jmp short return
lab fpload
fld parm
lab return
ifdef _STDCALL
ret 8
else
ret
endif
_fload endp
end