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 cdispflags equ 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 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 ; 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 nomt 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 fstcw [DSF.savCntrl] cmp [_matherr_flag], 0 JSE save1arg lab resume1 call _trandisp1 ifmt ifmt nomt 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 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 ifmt ; set _cpower to C semantics call _trandisp2 call ctranexit ifdef _STDCALL ret 16 else ret endif ;* ;* Check for overflow and errors. ;* ctranexit:: ifmt nomt 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 nomt 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 push dword ptr [parm1+4] ; load arg1 push dword ptr [parm1] call _fload ifndef _STDCALL add esp, 8 endif fstcw [DSF.savCntrl] ifmt 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