316 lines
10 KiB
NASM
316 lines
10 KiB
NASM
;***
|
|
;
|
|
; Copyright (c) 1984-2001, Microsoft Corporation. All rights reserved.
|
|
;
|
|
; Revision History:
|
|
; 01-26-01 PML Pentium4 merge.
|
|
; 02-25-01 PML Fix pow(+/-0,-denorm)
|
|
;
|
|
;*******************************************************************************
|
|
|
|
.xlist
|
|
include cruntime.inc
|
|
include elem87.inc
|
|
.list
|
|
|
|
_FUNC_ equ <pow>
|
|
_FUNC_DEF_ equ <_pow_default>
|
|
_FUNC_P4_ equ <_pow_pentium4>
|
|
_FUNC_P4_EXTERN_ equ 1
|
|
include disp_pentium4.inc
|
|
|
|
_FUNC_ equ <_CIpow>
|
|
_FUNC_DEF_ equ <_CIpow_default>
|
|
_FUNC_P4_ equ <_CIpow_pentium4>
|
|
include disp_pentium4.inc
|
|
|
|
.data
|
|
globalQ _half, 03fe0000000000000R
|
|
POW_name db 'pow',0
|
|
|
|
extrn _infinity:tbyte
|
|
extrn _indefinite:tbyte
|
|
extrn __fastflag:dword
|
|
|
|
|
|
CODESEG
|
|
|
|
extrn _startTwoArgErrorHandling:near
|
|
extrn _fload_withFB:near
|
|
extrn _convertTOStoQNaN:near
|
|
extrn _checkTOS_withFB:near
|
|
extrn _check_range_exit:near
|
|
extrn _fast_exit:near
|
|
extrn _load_CW:near
|
|
extrn _powhlp:near
|
|
extrn _twoToTOS:near
|
|
|
|
; arg1(base) arg2(exponent) ErrorType result
|
|
;-----------------------------------------------------------
|
|
;infinity not NaN called powhlp()
|
|
;not NaN infinity called powhlp()
|
|
;QNaN not SNaN DOMAIN_QNAN QNaN
|
|
;SNaN any DOMAIN
|
|
;
|
|
;*0 *0 - 1
|
|
;*0 positive,not odd - +0
|
|
;+0 positive, odd - +0
|
|
;-0 positive, odd - -0
|
|
;*0 negative,not odd SING infinity
|
|
;+0 negative, odd SING infinity
|
|
;-0 negative, odd SING -infinity
|
|
;negative non-integer DOMAIN indefinite
|
|
;indefinite is like QNaN
|
|
;denormal(53) fld converts it to normal (64 bits)
|
|
;
|
|
; * in table above stands for both + and -
|
|
;
|
|
; if exponent field of result is 0, error type is set to UNDERFLOW
|
|
; if result is infinity, error type is set to OVERFLOW
|
|
|
|
public _CIpow_default,_pow_default
|
|
_CIpow_default proc
|
|
sub esp,2*DBLSIZE+4 ; prepare place for argument
|
|
fxch st(1)
|
|
fstp qword ptr [esp] ; base
|
|
fst qword ptr [esp+8] ; exponent
|
|
mov eax,[esp+12] ; high dword of exponent
|
|
call start
|
|
add esp,2*DBLSIZE+4 ; clean stack
|
|
ret
|
|
|
|
_pow_default label proc
|
|
|
|
lea edx,[esp+12] ; load exponent(arg2)
|
|
call _fload_withFB
|
|
start:
|
|
mov ecx,eax ; make copy of eax
|
|
push eax ; allocate space for Control Word
|
|
fstcw [esp] ; store Control Word
|
|
cmp word ptr[esp],default_CW
|
|
je CW_is_set_to_default
|
|
call _load_CW ; edx is destroyed
|
|
CW_is_set_to_default:
|
|
; at this point we have on stack: cw(4), ret_addr(4), arg1(8bytes), arg2(8bytes)
|
|
and ecx,7ff00000H
|
|
lea edx,[esp+8] ; edx points to arg1(base)
|
|
|
|
cmp ecx,7ff00000H
|
|
je special_exponent
|
|
|
|
call _fload_withFB ; edx already initialized
|
|
jz special_base
|
|
test eax,7ff00000H
|
|
jz test_if_we_have_zero_base
|
|
base_is_not_zero:
|
|
mov cl,[esp+15] ; cl will contain sign
|
|
and cl,80H ; test sign of base
|
|
jnz test_if_exp_is_int
|
|
normal: ; denormal is like normal
|
|
fyl2x ; compute y*log2(x)
|
|
call _twoToTOS
|
|
cmp cl,1 ; power was odd and base<0 ?
|
|
jnz exit
|
|
fchs ; if yes, we should change sign
|
|
exit:
|
|
cmp __fastflag,0
|
|
jnz _fast_exit
|
|
|
|
; prepare in registers arguments for math_exit
|
|
lea ecx,[POW_name]
|
|
mov edx,OP_POW
|
|
jmp _check_range_exit
|
|
|
|
_ErrorHandling:
|
|
cmp __fastflag,0
|
|
jnz _fast_exit
|
|
|
|
lea ecx,[POW_name]
|
|
mov edx,OP_POW
|
|
call _startTwoArgErrorHandling
|
|
pop edx ; remove saved CW from stack
|
|
ret
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
; some special cases
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
; 1.One of arguments is NaN
|
|
exponent_is_NAN:
|
|
lea edx,[esp+8] ; pointer to arg1(base)
|
|
call _fload_withFB ; load arg1 to FPU stack
|
|
test byte ptr[esp+22],08H ; test if arg2(exponent) is SNaN
|
|
jnz SNaN_detected
|
|
inc ecx ; ecx!=0 when one of args is QNaN
|
|
jmp test_base
|
|
|
|
SNaN_detected:
|
|
fadd
|
|
mov eax,DOMAIN
|
|
jmp _ErrorHandling
|
|
|
|
base_is_NAN:
|
|
test byte ptr[esp+14],08H ; is it SNaN
|
|
jnz SNaN_detected
|
|
one_of_args_is_QNaN:
|
|
fadd ; one of args is QNaN, and second is not SNaN
|
|
mov eax,DOMAIN_QNAN
|
|
jmp _ErrorHandling
|
|
|
|
special_base:
|
|
; both arguments are loaded to FPU stack
|
|
xor ecx,ecx
|
|
jmp test_base
|
|
|
|
special_exponent:
|
|
; only one argument is loaded to FPU stack
|
|
xor ecx,ecx ; we use ecx to set flags
|
|
and eax,000fffffH ; eax=high
|
|
or eax,[esp+16] ; test whether mantissa is zero
|
|
jne exponent_is_NAN
|
|
lea edx,[esp+8] ; pointer to arg1(base)
|
|
call _fload_withFB ; load arg1(base) to FPU stack
|
|
test_base: ; arg2 may be inf, QNaN or normal
|
|
; both arguments are loaded to FPU stack
|
|
mov eax,[esp+12] ; arg1 high
|
|
mov edx,eax
|
|
and eax,7ff00000H
|
|
and edx,000fffffH ; test mantissa of arg2
|
|
cmp eax,7ff00000H
|
|
jne end_of_tests
|
|
or edx,[esp+8]
|
|
jnz base_is_NAN ; arg1 is NaN,
|
|
|
|
end_of_tests:
|
|
test ecx,ecx
|
|
jnz one_of_args_is_QNaN ; base is QNaN
|
|
|
|
; one of args is infinity and second is not NaN. In this case we use powhlp()
|
|
;_usepowhlp
|
|
sub esp, SBUFSIZE+8 ; get storage for _retval and savebuf
|
|
mov ecx, esp
|
|
push ecx ; push address for result
|
|
|
|
sub esp, 16
|
|
fstp qword ptr [esp]
|
|
fstp qword ptr [esp+8]
|
|
|
|
fsave [ecx+8]
|
|
call _powhlp
|
|
add esp, 16 ; clear arguments if _cdecl.
|
|
pop ecx
|
|
frstor [ecx+8]
|
|
fld qword ptr [ecx] ; load result on the NDP stack
|
|
add esp, SBUFSIZE+8 ; get rid of storage
|
|
|
|
test eax,eax
|
|
jz _fast_exit
|
|
mov eax,DOMAIN
|
|
jmp _ErrorHandling
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
; 2. Base has zero exponent field
|
|
;
|
|
test_if_we_have_zero_base:
|
|
mov eax,[esp+12]
|
|
and eax,000fffffH
|
|
or eax,[esp+8]
|
|
jnz base_is_not_zero
|
|
|
|
; at this point we have two arguments on FPU stack.
|
|
; We know that TOS is zero, and arg2 is not special.
|
|
; We disinguish 3 cases:
|
|
; (1) exponent is zero
|
|
; (2) exponent is odd
|
|
; (3) none of above
|
|
|
|
fstp st(0) ; remove zero from FPU stack
|
|
mov eax,[esp+20] ; test if arg2 is also zero
|
|
and eax,7fffffffh
|
|
or eax,[esp+16]
|
|
jz zero_to_zero
|
|
; check whether exponent is odd
|
|
call _test_whether_TOS_is_int
|
|
; cl=1 if exponent is odd, 2 - if even and 0 otherwise
|
|
mov ch,[esp+15]
|
|
shr ch,7 ; ch==1 iff base is negative
|
|
test [esp+23],80H ; check sign of exponent
|
|
jz exp_is_positive
|
|
; exponent is negative
|
|
fld [_infinity]
|
|
test cl,ch
|
|
jz ret_inf
|
|
fchs ; base <0 and exponent is negative odd
|
|
ret_inf:
|
|
mov eax,SING
|
|
jmp _ErrorHandling
|
|
|
|
exp_is_positive: ; eax=error_code
|
|
fldz
|
|
test cl,ch
|
|
jz _fast_exit
|
|
fchs ; base <0 and exponent positive is odd
|
|
jmp _fast_exit ; return -0.0
|
|
|
|
zero_to_zero: ; arg1 and arg2 are zero
|
|
fstp st(0) ; remove useless argument from FPU stack
|
|
fld1
|
|
jmp _fast_exit
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;3. Base is negative.
|
|
;
|
|
; If exponent is not integer it's a DOMAIN error
|
|
;
|
|
|
|
test_if_exp_is_int:
|
|
fld st(1)
|
|
call _test_whether_TOS_is_int
|
|
fchs
|
|
test cl,cl
|
|
jnz normal
|
|
fstp st(0)
|
|
fstp st(0)
|
|
fld [_indefinite]
|
|
mov eax,DOMAIN
|
|
jmp _ErrorHandling
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;
|
|
; _test_whether_TOS_is_int
|
|
;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
; returns in cl : 0,1,2 if TOS is non-int, odd int or even int respectively
|
|
;
|
|
_test_whether_TOS_is_int:
|
|
fld st(0) ; duplicate stack top
|
|
frndint
|
|
fcomp ; is TOS integer???
|
|
mov cl,0 ; prepare return value
|
|
fstsw ax
|
|
sahf
|
|
jne _not_int ; TOS is not integer
|
|
fmul [_half]
|
|
inc cl ; cl>0, when exponent is integer
|
|
fld st(0) ; (exponent/2)
|
|
frndint
|
|
fcompp ; check if (exponent/2)==(int)(exponent/2)
|
|
fstsw ax
|
|
sahf
|
|
jne _odd
|
|
inc cl ; sign that exponent is even
|
|
_odd:
|
|
ret
|
|
|
|
_not_int:
|
|
fstp st(0)
|
|
ret
|
|
_CIpow_default endp
|
|
end
|
|
|
|
|
|
|