windows-nt/Source/XPSP1/NT/base/ntdll/i386/emarith.asm

336 lines
8.2 KiB
NASM
Raw Normal View History

2020-09-26 03:20:57 -05:00
subttl emarith.asm - Arithmetic Operations
page
;*******************************************************************************
;emarith.asm - Arithmetic Operations
;
; Microsoft Confidential
;
; Copyright (c) Microsoft Corporation 1991
; All Rights Reserved
;
;Purpose:
; Arithmetic Operations
;
;Revision History:
;
; [] 09/05/91 TP Initial 32-bit version.
;
;*******************************************************************************
NextStackWrap esi,TwoOp ;Tied to NextStackElem below
EM_ENTRY eFPREM
eFPREM:
and [esp].[OldLongStatus+4],NOT(ConditionCode SHL 16) ;clear C0,C1,C2,C3
push offset PremCont ;Return address if normal
PremPointTopTwo:
push offset PremSpclDone ;Return address if special
mov ebp,offset tFpremDisp
PointTopTwo:
mov esi,edi
NextStackElem esi,TwoOp
TwoOpSiDi:
mov ecx,EMSEG:[esi].ExpSgn
mov ebx,EMSEG:[esi].lManHi
mov esi,EMSEG:[esi].lManLo
TwoOpSetResult:
mov EMSEG:[Result],edi ;Save result pointer
TwoOpResultSet:
mov ah,EMSEG:[edi].bTag
TwoOpDispAh:
mov al,cl
TwoOpDispatch:
and eax,TAG_MASK + 100H*TAG_MASK ;Look at internal tags only
shl al,TAG_SHIFT
or al,ah
xor ah,ah ;Zero ah
;UNDONE: masm bug! ebp + scaled index requires a displacement.
;UNDONE: No displacement is needed here, so masm should generate a
;UNDONE: zero. It doesn't! dec eax so we can add 4*1 back.
dec eax ;UNDONE
jmp dword ptr cs:[ebp+4*eax+4];UNDONE Go to appropriate routine.
EM_ENTRY eFPREM1
eFPREM1:
and [esp].[OldLongStatus+4],NOT(ConditionCode SHL 16) ;clear C0,C1,C2,C3
push offset Prem1Cont ;Return address if normal
jmp PremPointTopTwo
EM_ENTRY eFSCALE
eFSCALE:
mov ebp,offset tFscaleDisp
jmp PointTopTwo
EM_ENTRY eFPATAN
eFPATAN:
mov ebp,offset tFpatanDisp
TopTwoPop:
push offset PopWhenDone
mov esi,edi
add edi,Reg87Len ;edi = ST(1)
cmp edi,ENDstk
jb TwoOpSiDi
mov edi,BEGstk
jmp TwoOpSiDi
EM_ENTRY eFYL2X
eFYL2X:
mov ebp,offset tFyl2xDisp
jmp TopTwoPop
EM_ENTRY eFYL2XP1
eFYL2XP1:
mov ebp,offset tFyl2xp1Disp
jmp TopTwoPop
;*******************************************************************************
page
;-----------------------------------------------------------;
; ;
; Special Case Routines for Arithmetic Functions ;
; ;
;-----------------------------------------------------------;
;There are four kinds of "specials", encoded in the tag:
;
; Empty
; Infinity
; NAN (which can be QNAN or SNAN)
; Denormal
;
;Empty always results in an Invalid Operation exception with Stack Flag set
;and C1 (O/U#) bit clear, and returns Indefinite (a specific QNAN).
;
;Operations on NAN return the same NAN except it is always modified to a
;QNAN. If both operands are NAN, the one with the larger mantissa is
;returned. An SNAN causes an Invalid Operation exception except for
;internal FP stack operations, FCHS, and FABS. A QNAN does not cause
;and exception.
;
;Operations on Infinity return a result depending on the operation.
;
;UNDONE: Old code plays with sign of NAN when two NANs with equal
;mantissas are used. Why?
;"***" means entry point from dispatch tables
;***
DivSpclSource:
cmp cl,bTAG_INF
jnz SpclSource
;Division by infinity always returns zero
xor ch,EMSEG:[edi].bSgn
jmp SignedZero ;in emfmul.asm
;***
MulSpclSource:
cmp cl,bTAG_INF
jnz SpclSource
MulByInf:
cmp EMSEG:[edi].bTag,bTAG_ZERO ;Infinity * zero?
jz ReturnIndefinite
XorSourceSign:
xor ch,EMSEG:[edi].bSgn
jmp SaveResultEdi
;***
AddSpclSource:
cmp cl,bTAG_INF
jnz SpclSource
xor ch,dl ;Flip sign of infinity if subtracting
jmp SaveResultEdi
DenormalSource:
mov cl,bTAG_VALID ;Change denormal to DOUBLE
mov EMSEG:[CURerr],Denormal
test EMSEG:[CWmask],Denormal ;Is denormal exception masked?
jnz TwoOpResultSet
AbortOp:
mov cl,bTAG_NOPOP ;Unmasked, don't pop stack
ret
DenormalDisp:
;Repeat dispatch, but for normal ops
jmp dword ptr cs:[ebp+4*(TAG_VALID + TAG_VALID shl TAG_SHIFT)]
;***
DivrSpclSource:
cmp cl,bTAG_INF
jz XorSourceSign ;Return infinity
SpclSource:
cmp cl,bTAG_DEN
jz DenormalSource
cmp cl,bTAG_EMPTY
jz StackError
;Must be a NAN
SourceNAN:
test ebx,1 shl 30 ;Check for SNAN
jnz SaveResultEdi ;If QNAN, just use it as result
SourceSNAN:
or EMSEG:[CURerr],Invalid ;Flag the error
or ebx,1 shl 30 ;Make it into a QNAN
test EMSEG:[CWmask],Invalid ;Is it masked?
jnz SaveResultEdi ;If so, update with masked response
mov cl,bTAG_NOPOP ;Unmasked, don't pop stack
ret
;***
DivrSpclDest:
mov eax,EMSEG:[edi].ExpSgn ;Pick up tag
cmp al,bTAG_INF
jnz SpclDest
;Division by infinity always returns zero
xor ch,ah
jmp SignedZero ;in emfmul.asm
;***
MulSpclDest:
mov al,EMSEG:[edi].bTag ;Pick up tag
cmp al,bTAG_INF
jnz SpclDest
cmp cl,bTAG_ZERO ;Infinity * zero?
jz ReturnIndefinite
XorDestSign:
xor EMSEG:[edi].bSgn,ch ;Xor signs
ret
;***
AddSpclDest:
mov al,EMSEG:[edi].bTag ;Pick up tag
cmp al,bTAG_INF
jnz SpclDest
xor EMSEG:[edi].bSgn,dh ;Flip sign of infinity if subtracting
ret
DenormalDest:
mov ah,bTAG_VALID ;Change denormal to DOUBLE
mov EMSEG:[CURerr],Denormal
test EMSEG:[CWmask],Denormal ;Is denormal exception masked?
jnz TwoOpDispAh
mov cl,bTAG_NOPOP ;Unmasked, don't pop stack
ret
;***
DivSpclDest:
mov al,EMSEG:[edi].bTag ;Pick up tag
cmp al,bTAG_INF
jz XorDestSign ;Return infinity
SpclDest:
cmp al,bTAG_DEN
jz DenormalDest
SpclDestNotDen:
cmp al,bTAG_EMPTY
jz StackError
;Must be a NAN
DestNAN:
test EMSEG:[edi].bMan7,40H ;Check for SNAN
jnz ReturnDest ;If QNAN, just use it as result
DestSNAN:
or EMSEG:[CURerr],Invalid ;Flag the error
test EMSEG:[CWmask],Invalid ;Is it masked?
jz AbortOp ;No - preserve value
or EMSEG:[edi].bMan7,40H ;Make it into a QNAN
ret
StackError:
mov EMSEG:[CURerr],Invalid+StackFlag
ReturnIndefinite:
or EMSEG:[CURerr],Invalid
test EMSEG:[CWmask],Invalid ;Is it masked?
jz AbortOp ;No - preserve value
mov EMSEG:[edi].lManLo,0
mov EMSEG:[edi].lManHi,0C0000000H
mov EMSEG:[edi].ExpSgn,TexpMax shl 16 + bSign shl 8 + bTAG_NAN
ReturnDest:
ret
AddTwoInf:
;Adding two infinites.
;If signs are the same, return that infinity. Otherwise, Invalid Operation.
xor ch,dl ;Possibly subtracting source
xor ah,dh ;Possibly subtracting dest
xor ch,ah ;Compare signs
js ReturnIndefinite
mov EMSEG:[edi].bSgn,ah ;Correct the sign if subtracting
ret
;***
TwoOpBothSpcl:
;ebp = dispatch table address
mov al,EMSEG:[edi].bTag
mov ah,cl
cmp ax,(bTAG_NAN shl 8) + bTag_NAN ;Are both NAN?
jz TwoNANs
cmp cl,bTAG_EMPTY
jz StackError
cmp al,bTAG_EMPTY
jz StackError
cmp cl,bTAG_NAN
jz SourceNAN
cmp al,bTAG_NAN
jz DestNAN
cmp ax,(bTAG_INF shl 8) + bTag_INF ;Are both infinity?
jz TwoInfs
;At least one of the operands is a denormal
mov EMSEG:[CURerr],Denormal
test EMSEG:[CWmask],Denormal ;Is denormal exception masked?
jz AbortOp ;If not, don't do operation
;Denormal exception is masked, treat denormals as VALID
;Dispatch through operation table in ebp again
cmp ax,(bTAG_DEN shl 8) + bTag_DEN ;Are both denormal?
jz DenormalDisp
;Have an infinity and a denormal
cmp al,bTAG_INF
jz DestInf
;Source is denormal, Dest is infinity
jmp dword ptr [ebp+4*(TAG_SPCL + TAG_VALID shl TAG_SHIFT)]
DestInf:
;Source is infinity, Dest is denormal
jmp dword ptr [ebp+4*(TAG_VALID + TAG_SPCL shl TAG_SHIFT)]
TwoNANs:
;Two NANs. Use largest mantissa
cmp ebx,EMSEG:[edi].lManHi
ja BiggerNAN
jb DestBigger
;Now we know they're both the same type, SNAN or QNAN
cmp esi,EMSEG:[edi].lManLo
ja SourceNAN
;UNDONE: Old code did funny business with signs when mantissas were equal
jmp DestNAN
BiggerNAN:
test EMSEG:[edi].bMan7,40H ;Is smaller one SNAN?
jz SourceSNAN
jmp SourceNAN
DestBigger:
test ebx,40H ;Is smaller one SNAN?
jz DestSNAN
jmp DestNAN
TwoInfs:
mov ah,EMSEG:[edi].bSgn
jmp dword ptr [ebp+4*16] ;Go do code for two infinites
;***
DivideByMinusZero:
mov ch,bSign
;***
DivideByZero:
or EMSEG:[CURerr],ZeroDivide
test EMSEG:[CWmask],ZeroDivide ;Is exception masked?
jz AbortOp ;No - preserve value
;Set up a signed infinity
xor ch,EMSEG:[edi].bSgn ;Get result sign
and ecx,1 shl 15 ;Keep only sign bit
or ecx,(4000H+TexpBias) shl 16 + bTAG_INF ;ExpSgn of infinity
mov ebx,1 shl 31
xor esi,esi
jmp SaveResultEdi