windows-nt/Source/XPSP1/NT/base/ntdll/i386/emround.asm
2020-09-26 16:20:57 +08:00

713 lines
21 KiB
NASM

subttl emround.asm - Rounding and Precision Control and FRNDINT
page
;*******************************************************************************
;emround.asm - Rounding and Precision Control
;
; Microsoft Confidential
;
; Copyright (c) Microsoft Corporation 1991
; All Rights Reserved
;
;Purpose:
; Rounding and precision control. The correct routine is jumped
; to through the [RoundMode] vector.
;
;Revision History:
;
; [] 09/05/91 TP Initial 32-bit version.
; 02/28/92 JWM Minor bug fix in NotNearLow
;
;*******************************************************************************
RndIntSpcl:
cmp cl,bTAG_INF
jz RndIntX ;Leave infinity unchanged
cmp cl,bTAG_DEN
jnz SpclDestNotDen ;Handle NAN & empty - in emarith.asm
;Handle denormal
mov EMSEG:[CURerr],Denormal
test EMSEG:[CWmask],Denormal ;Is it masked?
jnz NormRndInt ;If so, ignore denormalization
RndIntX:
ret
;********
EM_ENTRY eFRNDINT
eFRNDINT:
;********
;edi points to top of stack
mov ecx,EMSEG:[edi].ExpSgn
cmp cl,bTAG_ZERO
.erre bTAG_VALID lt bTAG_ZERO
.erre bTAG_SNGL lt bTAG_ZERO
jz RndIntX
ja RndIntSpcl
cmp ecx,63 shl 16 ;Is it already integer?
jge RndIntX
NormRndInt:
mov ebx,EMSEG:[edi].lManHi
mov esi,EMSEG:[edi].lManLo
mov EMSEG:[Result],edi ;Save result pointer
xor eax,eax ;Extend mantissa
push offset SaveResult
jmp RoundToBit
;*******************************************************************************
ResultOverflow:
;mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7, tag in cl.
;We were all ready to save the rounded result, but the exponent turned out
;to be too large.
or EMSEG:[CURerr],Overflow
sub ecx,UnderBias shl 16 ;Unmasked response
test EMSEG:[CWmask],Overflow ;Is exception unmasked?
jz SaveResult ;If so, we're ready
;Produce masked overflow response
mov ebx,1 shl 31 ;Assume infinity
xor esi,esi
mov cl,bTAG_INF
mov al,EMSEG:[CWcntl] ;Get rounding control
mov ah,al
and ah,RCchop ;Rounding control only
;Return max value if RCup bit = 1 and -, or RCdown bit = 1 and +
;i.e., RCup & sign OR RCdown & not sign
.erre RCchop eq RCup + RCdown ;Always return max value
.erre RCnear eq 0 ;Never return max value
sar ch,7 ;Expand sign through whole byte
.erre (RCdown and bSign) eq 0 ;Don't want to change real sign
xor ch,RCdown ;Flip sign for RCdown bit
and ah,ch ;RCup & sign OR RCdown & not sign
jnz SaveMax
and ecx,0FFFFH
or ecx,TexpMax shl 16
jmp SaveResult ;Save Infinity
SaveMax:
;Get max value for current precision
mov ebx,0FFFFFF00H ;Max value for 24 bits
and ecx,bSign shl 8 ;Preserve only sign
or ecx,(IexpMax-IexpBias-1) shl 16 + bTAG_VALID ;Set up max value
and al,PrecisionControl
.erre PC24 eq 0
jz SaveResult ;Save 24-bit max value
dec esi ;esi == -1
mov ebx,esi
cmp al,PC53
jnz SaveResult ;Save 64-bit max value
mov esi,0FFFFF800H
jmp SaveResult ;Save 53-bit max value
;*******************************************************************************
;
;64-bit rounding routines
;
;***********
Round64down:
;***********
cmp ecx,(IexpMin-IexpBias+1) shl 16 ;Test for Underflow
jl RndDenorm64
or eax,eax ;Exact result?
jz SaveValidResult
or EMSEG:[CURerr],Precision ;Set flag on inexact result
;Chop if positive, increase mantissa if negative
test ch,bSign
jz SaveValidResult ;Positive, so chop
jmp RoundUp64 ;Round up if negative
RndDenorm64:
test EMSEG:[CWmask],Underflow ;Is exception unmasked?
jz RndSetUnder
Denormalize:
;We don't really store in denormalized format, but we need the number
;to be rounded as if we do. If the exponent were -IexpBias, we would
;lose 1 bit of precision; as it gets more negative, we lose more bits.
;We'll do this by adjusting the exponent so that the bits we want to
;keep look like integer bits, and performing round-to-integer.
add ecx,(IexpBias+62) shl 16 ;Adjust exponent so we're integer
call RoundToBit
;Set underflow exception if precision exception is set
mov al,EMSEG:[CURerr]
and al,Precision
ror al,Precision-Underflow ;Move Precision bit to Underflow pos.
or EMSEG:[CURerr],al ;Signal Underflow if inexact
cmp cl,bTAG_ZERO
jz SaveResult
sub ecx,(IexpBias+62) shl 16;Restore unbiased exponent
cmp ecx,TexpMin shl 16 ;Did we round out of denorm?
jae SaveResult
mov cl,bTAG_DEN
jmp SaveResult
RndSetUnder:
;Underflow exception not masked. Adjust exponent and try again.
or EMSEG:[CURerr],Underflow
add ecx,UnderBias shl 16
jmp EMSEG:[RoundMode] ;Try again with revised exponent
;***********
Round64near:
;***********
;mantissa in ebx:esi:eax, exponent in high ecx, sign in ch bit 7
cmp ecx,TexpMin shl 16 ;Test for Underflow
jl RndDenorm64
or eax,eax ;Exact result?
jz short SaveValidResult
or EMSEG:[CURerr],Precision ;Set flag on inexact result
;To perform "round even" when the round bit is set and the sticky bits
;are zero, we treat the LSB as if it were a sticky bit. Thus if the LSB
;is set, that will always force a round up (to even) if the round bit is
;set. If the LSB is zero, then the sticky bits remain zero and we always
;round down. This rounding rule is implemented by adding RoundBit-1
;(7F..FFH), setting CY if round up.
bt esi,0 ;Is mantissa even or odd? (set CY)
adc eax,(1 shl 31)-1 ;Sum LSB & sticky bits--CY if round up
jnc SaveValidResult
RoundUp64:
mov EMSEG:[SWcc],RoundUp
add esi,1
adc ebx,0
jc BumpExponent ;Overflowed, increment exponent
SaveValidResult: ;A jump to here requires 9 clocks
or esi,esi ;Any bits in low half?
.erre bTAG_VALID eq 1
.erre bTAG_SNGL eq 0
setnz cl ;if low half==0 then cl=0 else cl=1
cmp ecx,TexpMax shl 16 ;Test for overflow
jge ResultOverflow
SaveResult: ;A jump to here requires 10 clocks
;mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7, tag in cl
mov edi,EMSEG:[Result]
SaveResultEdi:
mov EMSEG:[edi].lManLo,esi
mov EMSEG:[edi].lManHi,ebx
SaveExpSgn:
mov EMSEG:[edi].ExpSgn,ecx
ret
;***********
Round64up:
;***********
cmp ecx,TexpMin shl 16 ;Test for Underflow
jl RndDenorm64
or eax,eax ;Exact result?
jz short SaveValidResult
or EMSEG:[CURerr],Precision;Set flag on inexact result
;Chop if negative, increase mantissa if positive
cmp ch,bSign ;No CY iff sign bit is set
jc RoundUp64 ;Round up if positive
jmp short SaveValidResult
;***********
Round64chop:
;***********
cmp ecx,TexpMin shl 16 ;Test for Underflow
jl RndDenorm64
or eax,eax ;Exact result?
jz short SaveValidResult
or EMSEG:[CURerr],Precision;Set flag on inexact result
jmp short SaveValidResult
;*******************************************************************************
;
;53-bit rounding routines
;
;***********
Round53down:
;***********
cmp ecx,TexpMin shl 16 ;Test for Underflow
jl RndDenorm53
mov edx,esi ;Get low bits
and edx,(1 shl 11) - 1 ;Mask to last 11 bits
or edx,eax ;Throwing away any bits?
jz SaveValidResult
or EMSEG:[CURerr],Precision;Set flag on inexact result
;Chop if positive, increase mantissa if negative
and esi,not ((1 shl 11)-1) ;Mask off low 11 bits
test ch,bSign
jz SaveValidResult ;Positive, go chop
jmp RoundUp53
RndDenorm53:
test EMSEG:[CWmask],Underflow;Is exception unmasked?
jz RndSetUnder
;We don't really store in denormalized format, but we need the number
;to be rounded as if we do. If the exponent were -IexpBias, we would
;lose 1 bit of precision; as it gets more negative, we lose more bits.
;We'll do this by adjusting the exponent so that the bits we want to
;keep look like integer bits, and performing round-to-integer.
add ecx,(IexpBias+51) shl 16 ;Adjust exponent so we're integer
call RoundToBit
;Set underflow exception if precision exception is set
mov al,EMSEG:[CURerr]
and al,Precision
ror al,Precision-Underflow ;Move Precision bit to Underflow pos.
or EMSEG:[CURerr],al ;Signal Underflow if inexact
cmp cl,bTAG_ZERO
jz SaveResult
sub ecx,(IexpBias+51) shl 16;Restore unbiased exponent
cmp ecx,(IexpMin-IexpBias+1) shl 16 ;Did we round out of denorm?
jae SaveResult
mov cl,bTAG_DEN
jmp SaveResult
;***********
Round53near:
;***********
;mantissa in ebx:esi:eax, exponent in high ecx, sign in ch bit 7
cmp ecx,TexpMin shl 16 ;Test for Underflow
jl RndDenorm53
mov edx,esi ;Get low bits
and edx,(1 shl 11) - 1 ;Mask to last 11 bits
or edx,eax ;Throwing away any bits?
jz SaveValidResult
or EMSEG:[CURerr],Precision;Set flag on inexact result
;To perform "round even" when the round bit is set and the sticky bits
;are zero, we treat the LSB as if it were a sticky bit. Thus if the LSB
;is set, that will always force a round up (to even) if the round bit is
;set. If the LSB is zero, then the sticky bits remain zero and we always
;round down.
mov edx,esi
and esi,not ((1 shl 11)-1) ;Mask off low 11 bits
test edx,1 shl 10 ;Is round bit set?
jz SaveValidResult
and edx,(3 shl 10)-1 ;Keep only sticky bits and LSB
or eax,edx ;Combine with other sticky bits
jz SaveValidResult
RoundUp53:
mov EMSEG:[SWcc],RoundUp
add esi,1 shl 11 ;Round
adc ebx,0
jnc SaveValidResult
BumpExponent:
add ecx,1 shl 16 ;Mantissa overflowed, bump exponent
or ebx,1 shl 31 ;Set MSB
jmp SaveValidResult
;***********
Round53up:
;***********
cmp ecx,TexpMin shl 16 ;Test for Underflow
jl RndDenorm53
mov edx,esi ;Get low bits
and edx,(1 shl 11) - 1 ;Mask to last 11 bits
or edx,eax ;Throwing away any bits?
jz SaveValidResult
or EMSEG:[CURerr],Precision;Set flag on inexact result
;Chop if negative, increase mantissa if positive
and esi,not ((1 shl 11)-1) ;Mask off low 11 bits
test ch,bSign
jz RoundUp53 ;Round up if positive
jmp SaveValidResult
;***********
Round53chop:
;***********
cmp ecx,TexpMin shl 16 ;Test for Underflow
jl RndDenorm53
mov edx,esi ;Get low bits
and edx,(1 shl 11) - 1 ;Mask to last 11 bits
or edx,eax ;Throwing away any bits?
jz SaveValidResult
or EMSEG:[CURerr],Precision;Set flag on inexact result
and esi,not ((1 shl 11)-1) ;Mask off low 11 bits
jmp SaveValidResult
;*******************************************************************************
;
;24-bit rounding routines
;
;***********
Round24down:
;***********
cmp ecx,TexpMin shl 16 ;Test for Underflow
jl RndDenorm24
or eax,esi ;Low dword is just sticky bits
mov edx,ebx ;Get low bits
and edx,(1 shl 8) - 1 ;Mask to last 8 bits
or edx,eax ;Throwing away any bits?
jz SaveValidResult
or EMSEG:[CURerr],Precision;Set flag on inexact result
;Chop if positive, increase mantissa if negative
xor esi,esi
and ebx,not ((1 shl 8)-1) ;Mask off low 8 bits
test ch,bSign
jz SaveValidResult ;Chop if positive
jmp RoundUp24
RndDenorm24:
test EMSEG:[CWmask],Underflow;Is exception unmasked?
jz RndSetUnder
;We don't really store in denormalized format, but we need the number
;to be rounded as if we do. If the exponent were -IexpBias, we would
;lose 1 bit of precision; as it gets more negative, we lose more bits.
;We'll do this by adjusting the exponent so that the bits we want to
;keep look like integer bits, and performing round-to-integer.
add ecx,(IexpBias+22) shl 16 ;Adjust exponent so we're integer
call RoundToBit
;Set underflow exception if precision exception is set
mov al,EMSEG:[CURerr]
and al,Precision
ror al,Precision-Underflow ;Move Precision bit to Underflow pos.
or EMSEG:[CURerr],al ;Signal Underflow if inexact
cmp cl,bTAG_ZERO
jz SaveResult
sub ecx,(IexpBias+22) shl 16;Restore unbiased exponent
cmp ecx,(IexpMin-IexpBias+1) shl 16 ;Did we round out of denorm?
jae SaveResult
mov cl,bTAG_DEN
jmp SaveResult
;***********
Round24near:
;***********
;mantissa in ebx:esi:eax, exponent in high ecx, sign in ch bit 7
cmp ecx,TexpMin shl 16 ;Test for Underflow
jl RndDenorm24
or eax,esi ;Low dword is just sticky bits
mov edx,ebx ;Get low bits
and edx,(1 shl 8) - 1 ;Mask to last 8 bits
or edx,eax ;Throwing away any bits?
jz SaveValidResult
or EMSEG:[CURerr],Precision;Set flag on inexact result
xor esi,esi
;To perform "round even" when the round bit is set and the sticky bits
;are zero, we treat the LSB as if it were a sticky bit. Thus if the LSB
;is set, that will always force a round up (to even) if the round bit is
;set. If the LSB is zero, then the sticky bits remain zero and we always
;round down.
mov edx,ebx
and ebx,not ((1 shl 8)-1) ;Mask off low 8 bits
test dl,1 shl 7 ;Round bit set?
jz SaveValidResult
and edx,(3 shl 7)-1 ;Mask to LSB and sticky bits
or eax,edx ;Combine all sticky bits
jz SaveValidResult
RoundUp24:
mov EMSEG:[SWcc],RoundUp
add ebx,1 shl 8
jnc SaveValidResult
jmp BumpExponent ;Overflowed, increment exponent
;***********
Round24up:
;***********
cmp ecx,TexpMin shl 16 ;Test for Underflow
jl RndDenorm24
or eax,esi ;Low dword is just sticky bits
mov edx,ebx ;Get low bits
and edx,(1 shl 8) - 1 ;Mask to last 8 bits
or edx,eax ;Throwing away any bits?
jz SaveValidResult
or EMSEG:[CURerr],Precision;Set flag on inexact result
;Chop if negative, increase mantissa if positive
xor esi,esi
and ebx,not ((1 shl 8)-1) ;Mask off low 8 bits
test ch,bSign
jz RoundUp24 ;Round up if positive
jmp SaveValidResult
;***********
Round24chop:
;***********
cmp ecx,TexpMin shl 16 ;Test for Underflow
jl RndDenorm24
or eax,esi ;Low dword is just sticky bits
mov edx,ebx ;Get low bits
and edx,(1 shl 8) - 1 ;Mask to last 8 bits
or edx,eax ;Throwing away any bits?
jz SaveValidResult
or EMSEG:[CURerr],Precision;Set flag on inexact result
xor esi,esi
and ebx,not ((1 shl 8)-1) ;Mask off low 8 bits
jmp SaveValidResult
;*******************************************************************************
;*** RoundToInteger
;
;This routine is used by FISTP Int64 and BSTP. Unlike RoundToBit, this
;unnormalizes the number into a 64-bit integer.
;
;Inputs:
; edi = pointer to number to round in stack
;Outputs:
; CY set if invalid operation
; ebx:edi = rounded integer if CY clear
; ch = sign if CY clear
;Note:
; FIST/FISTP/BSTP exception rules are used: If the number is too big,
; Invalid Operation occurs. Denormals are ignored.
;
;esi preserved
RoundSpcl64Int:
cmp cl,bTAG_DEN
jz NormRound64Int ;Ignore denormal
cmp cl,bTAG_EMPTY
jnz RoundInvalid ;All other specials are invalid
mov EMSEG:[CURerr],StackFlag+Invalid
stc ;Flag exception to caller
ret
RoundInvalid:
;Overflow on integer store is invalid according to IEEE
mov EMSEG:[CURerr],Invalid
stc ;Flag exception to caller
ret
RoundToInteger:
mov ebx,EMSEG:[edi].lManHi
mov ecx,EMSEG:[edi].ExpSgn
mov edi,EMSEG:[edi].lManLo
;mantissa in ebx:edi, exponent in high ecx, sign in ch bit 7, tag in cl
mov al,ch ;Save sign bit
cmp cl,bTAG_ZERO
.erre bTAG_VALID lt bTAG_ZERO
.erre bTAG_SNGL lt bTAG_ZERO
jz RoundIntX ;Just return zero
ja RoundSpcl64Int
NormRound64Int:
xor edx,edx
sar ecx,16 ;Bring exponent down
cmp ecx,-1 ;Is it less than 1?
jle Under64Int
cmp ecx,63
jg RoundInvalid
sub ecx,63
neg ecx ;cl = amount to shift right
mov ch,al ;Get sign out of al
xor eax,eax
cmp cl,32 ;Too big for one shift?
jl ShortShft64
;32-bit shift right
xchg edx,edi
xchg ebx,edi ;ebx=0 now
shrd eax,edx,cl
;Max total shift is 63 bits, so we know that the LSB of eax is still zero.
;We can rotate this zero to the MSB so the sticky bits in eax can be combined
;with those in edx without affecting the rounding bit in the MSB of edx.
ror eax,1 ;MSB is now zero
ShortShft64:
;Shift count in cl is modulo-32
shrd edx,edi,cl
shrd edi,ebx,cl
shr ebx,cl
or edx,eax ;Collapse sticky bits into one dword
jz RoundIntX ;No sticky or round bits, so don't round
;Result will not be exact--check rounding mode
Round64Int:
mov EMSEG:[CURerr],Precision;Set flag on inexact result
test EMSEG:[CWcntl],RoundControl ;Check rounding control bits
.erre RCnear eq 0
jnz NotNearest64Int ;Not just round-to-nearest
;To perform "round even" when the round bit is set and the sticky bits
;are zero, we treat the LSB as if it were a sticky bit. Thus if the LSB
;is set, that will always force a round up (to even) if the round bit is
;set. If the LSB is zero, then the sticky bits remain zero and we always
;round down.
bt edi,0 ;Look at LSB (for round even)
adc edx,(1 shl 31)-1 ;CY set if round up
jnc RoundIntX
mov EMSEG:[SWcc],RoundUp
add edi,1 ;Round
adc ebx,0
jc RoundInvalid
RoundIntX:
ret ;CY clear, no Invalid exception
Shift64Round:
or edi,edi
setnz dl ;Set sticky bit in edx
xor edi,edi ;Mantissa is all zero
jmp Round64Int
Under64Int:
;ZF set if exponent is -1
xchg ebx,edx ;64-bit right shift
mov ch,al ;Restore sign to ch
jz Shift64Round ;Exp. is -1, could need to round up
xor edi,edi ;Mantissa is all zero
mov EMSEG:[CURerr],Precision;Set flag on inexact result
NotNearest64Int:
;We want to increase the magnitude if RCup and +, or RCdown and -
mov al,EMSEG:[CWcntl] ;Get rounding control
.erre (not RCup and RoundControl) eq RCdown
sar ch,7 ;Expand sign through whole byte
xor al,ch ;Flip round mode if -
and al,RoundControl
cmp al,RCup ;Rounding up?
jnz RoundIntOk ;No, chop it
mov EMSEG:[SWcc],RoundUp
add edi,1
adc ebx,0
jc RoundInvalid
RoundIntOk:
clc
ret
;*******************************************************************************
;*** RoundToBit
;
;This is a relatively low performance routine used by FRNDINT and to
;generate internal-format denormals. It can round to any bit position.
;
;Inputs:
; mantissa in ebx:esi:eax, exponent in high ecx, sign in ch bit 7
;Purpose:
; Round number to integer. Zero exponent means number is in the
; range [1,2), so only the MSB will survive (MSB-1 is round bit).
; Larger exponents keep more bits; 63 would mean no rounding.
;Outputs:
; mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7, tag in cl
;
;Does NOT detect overflow.
NoSigBits:
;Exponent was negative: no integer part
and ecx,bSign shl 8 ;Zero exponent, preserve sign
mov cl,bTAG_ZERO
or EMSEG:[CURerr],Precision;Set flag on inexact result
test EMSEG:[CWcntl],RoundControl ;Check rounding control bits
.erre RCnear eq 0
jnz NotNearNoSig ;Not just round-to-nearest
cmp edx,-1 ;Exponent of -1 ==> range [.5,1)
je HalfBitRound
RndIntToZero:
xor ebx,ebx
mov esi,ebx ;Just return zero
ret
NotNearNoSig:
;We want to increase the magnitude if RCup and +, or RCdown and -
mov al,EMSEG:[CWcntl] ;Get rounding control
sar ch,7 ;Expand sign through whole byte
xor al,ch ;Flip rounding bits if negative
and al,RoundControl
cmp al,RCup ;Rounding up?
jnz RndIntToZero ;No, chop it
RndIntToOne:
mov ebx,1 shl 31
xor esi,esi
mov cl,bTAG_SNGL
mov EMSEG:[SWcc],RoundUp
ret
HalfBitRound:
add ebx,ebx ;Shift off MSB (round bit)
or ebx,esi
or ebx,eax
jnz RndIntToOne
ret ;Return zero
;**********
RoundToBit:
;**********
mov edx,ecx ;Make copy of exponent
sar edx,16 ;Bring rounding exponent down
jl NoSigBits
mov cl,dl
cmp cl,32 ;Rounding in low word?
jae RoundLow
;When cl = 31, the RoundBit is in the low half while the LSB is in the
;high half. We must preserve the RoundBit when we move it to eax.
xchg eax,esi ;Low half becomes sticky bits
or ah,al ;Preserve lowest bits in ah
add esi,-1 ;Set CY if any original sticky bits
sbb al,al ;Put original sticky bits in al
mov esi,ebx
xor ebx,ebx ;Shift mantissa right 32 bits
RoundLow:
mov edx,(1 shl 31) - 1
shr edx,cl ;Make mask
;Note in the case of cl = 31, edx is now zero.
mov edi,esi
and edi,edx
or edi,eax ;Any bits being lost?
jz RndSetTag ;All done
inc edx ;Mask for LSB
or EMSEG:[CURerr],Precision;Set flag on inexact result
test EMSEG:[CWcntl],RoundControl ;Check rounding control bits
.erre RCnear eq 0
jnz NotNearLow ;Not just round-to-nearest
mov edi,edx ;Save LSB mask
shr edi,1 ;Mask for round bit
jc SplitRound ;Round bit in eax?
test esi,edi ;Round bit set?
jz MaskOffLow
dec edi ;Mask for sticky bits
or edi,edx ;Sticky bits + LSB
and edi,esi
or edi,eax ;Any sticky bits set?
jz MaskOffLow
RoundUpThenMask:
mov EMSEG:[SWcc],RoundUp
add esi,edx ;Round up
adc ebx,0
jc RoundBumpExp
MaskOffLow:
dec edx ;Mask for round & sticky bits
not edx
and esi,edx ;Zero out low bits
RndSetTag:
or ebx,ebx ;Is it normalized?
jns RoundedHighHalf
or esi,esi ;Any bits in low half?
.erre bTAG_VALID eq 1
.erre bTAG_SNGL eq 0
setnz cl ;if low half==0 then cl=0 else cl=1
ret
SplitRound:
;Rounding high half in esi on rounding bit in eax
bt esi,0 ;Look at LSB
adc eax,(1 shl 31) - 1 ;Set CY if round up
jc RoundUpThenMask
or ebx,ebx ;Will set ZF for jnz below
RoundedHighHalf:
;Rounding occured in high half, which had been moved low.
;Move it back up high.
;
;ZF set here on content of ebx. If not zero, rounding high half in esi
;rippled forward into zero in ebx.
mov cl,bTAG_SNGL
jnz RndIntNorm ;Present high half should be zero
xchg ebx,esi ;Shift left 32 bits
ret
RndIntNorm:
;Rounded up high half of mantissa, which rolled over to 0.
add ecx,1 shl 16 ;Increase exponent
mov ebx,1 shl 31 ;Restore MSB
ret ;Tag already set to SNGL
RoundBumpExp:
;Mantissa was FFFFF... and rolled over to 0 when we rounded
add ecx,1 shl 16 ;Increase exponent
mov ebx,1 shl 31 ;Restore MSB
jmp MaskOffLow
NotNearLow:
;We want to increase the magnitude if RCup and +, or RCdown and -
mov al,EMSEG:[CWcntl] ;Get rounding control
sar ch,7 ;Expand sign through whole byte
.erre (not RCup and RoundControl) eq RCdown
xor al,ch ;Flip rounding bits if negative
and al,RoundControl
cmp al,RCup ;Rounding up?
jz RoundUpThenMask ;yes
jmp MaskOffLow ;No, chop it