Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

315 lines
10 KiB

  1. ;***
  2. ;
  3. ; Copyright (c) 1984-2001, Microsoft Corporation. All rights reserved.
  4. ;
  5. ; Revision History:
  6. ; 01-26-01 PML Pentium4 merge.
  7. ; 02-25-01 PML Fix pow(+/-0,-denorm)
  8. ;
  9. ;*******************************************************************************
  10. .xlist
  11. include cruntime.inc
  12. include elem87.inc
  13. .list
  14. _FUNC_ equ <pow>
  15. _FUNC_DEF_ equ <_pow_default>
  16. _FUNC_P4_ equ <_pow_pentium4>
  17. _FUNC_P4_EXTERN_ equ 1
  18. include disp_pentium4.inc
  19. _FUNC_ equ <_CIpow>
  20. _FUNC_DEF_ equ <_CIpow_default>
  21. _FUNC_P4_ equ <_CIpow_pentium4>
  22. include disp_pentium4.inc
  23. .data
  24. globalQ _half, 03fe0000000000000R
  25. POW_name db 'pow',0
  26. extrn _infinity:tbyte
  27. extrn _indefinite:tbyte
  28. extrn __fastflag:dword
  29. CODESEG
  30. extrn _startTwoArgErrorHandling:near
  31. extrn _fload_withFB:near
  32. extrn _convertTOStoQNaN:near
  33. extrn _checkTOS_withFB:near
  34. extrn _check_range_exit:near
  35. extrn _fast_exit:near
  36. extrn _load_CW:near
  37. extrn _powhlp:near
  38. extrn _twoToTOS:near
  39. ; arg1(base) arg2(exponent) ErrorType result
  40. ;-----------------------------------------------------------
  41. ;infinity not NaN called powhlp()
  42. ;not NaN infinity called powhlp()
  43. ;QNaN not SNaN DOMAIN_QNAN QNaN
  44. ;SNaN any DOMAIN
  45. ;
  46. ;*0 *0 - 1
  47. ;*0 positive,not odd - +0
  48. ;+0 positive, odd - +0
  49. ;-0 positive, odd - -0
  50. ;*0 negative,not odd SING infinity
  51. ;+0 negative, odd SING infinity
  52. ;-0 negative, odd SING -infinity
  53. ;negative non-integer DOMAIN indefinite
  54. ;indefinite is like QNaN
  55. ;denormal(53) fld converts it to normal (64 bits)
  56. ;
  57. ; * in table above stands for both + and -
  58. ;
  59. ; if exponent field of result is 0, error type is set to UNDERFLOW
  60. ; if result is infinity, error type is set to OVERFLOW
  61. public _CIpow_default,_pow_default
  62. _CIpow_default proc
  63. sub esp,2*DBLSIZE+4 ; prepare place for argument
  64. fxch st(1)
  65. fstp qword ptr [esp] ; base
  66. fst qword ptr [esp+8] ; exponent
  67. mov eax,[esp+12] ; high dword of exponent
  68. call start
  69. add esp,2*DBLSIZE+4 ; clean stack
  70. ret
  71. _pow_default label proc
  72. lea edx,[esp+12] ; load exponent(arg2)
  73. call _fload_withFB
  74. start:
  75. mov ecx,eax ; make copy of eax
  76. push eax ; allocate space for Control Word
  77. fstcw [esp] ; store Control Word
  78. cmp word ptr[esp],default_CW
  79. je CW_is_set_to_default
  80. call _load_CW ; edx is destroyed
  81. CW_is_set_to_default:
  82. ; at this point we have on stack: cw(4), ret_addr(4), arg1(8bytes), arg2(8bytes)
  83. and ecx,7ff00000H
  84. lea edx,[esp+8] ; edx points to arg1(base)
  85. cmp ecx,7ff00000H
  86. je special_exponent
  87. call _fload_withFB ; edx already initialized
  88. jz special_base
  89. test eax,7ff00000H
  90. jz test_if_we_have_zero_base
  91. base_is_not_zero:
  92. mov cl,[esp+15] ; cl will contain sign
  93. and cl,80H ; test sign of base
  94. jnz test_if_exp_is_int
  95. normal: ; denormal is like normal
  96. fyl2x ; compute y*log2(x)
  97. call _twoToTOS
  98. cmp cl,1 ; power was odd and base<0 ?
  99. jnz exit
  100. fchs ; if yes, we should change sign
  101. exit:
  102. cmp __fastflag,0
  103. jnz _fast_exit
  104. ; prepare in registers arguments for math_exit
  105. lea ecx,[POW_name]
  106. mov edx,OP_POW
  107. jmp _check_range_exit
  108. _ErrorHandling:
  109. cmp __fastflag,0
  110. jnz _fast_exit
  111. lea ecx,[POW_name]
  112. mov edx,OP_POW
  113. call _startTwoArgErrorHandling
  114. pop edx ; remove saved CW from stack
  115. ret
  116. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  117. ; some special cases
  118. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  119. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  120. ; 1.One of arguments is NaN
  121. exponent_is_NAN:
  122. lea edx,[esp+8] ; pointer to arg1(base)
  123. call _fload_withFB ; load arg1 to FPU stack
  124. test byte ptr[esp+22],08H ; test if arg2(exponent) is SNaN
  125. jnz SNaN_detected
  126. inc ecx ; ecx!=0 when one of args is QNaN
  127. jmp test_base
  128. SNaN_detected:
  129. fadd
  130. mov eax,DOMAIN
  131. jmp _ErrorHandling
  132. base_is_NAN:
  133. test byte ptr[esp+14],08H ; is it SNaN
  134. jnz SNaN_detected
  135. one_of_args_is_QNaN:
  136. fadd ; one of args is QNaN, and second is not SNaN
  137. mov eax,DOMAIN_QNAN
  138. jmp _ErrorHandling
  139. special_base:
  140. ; both arguments are loaded to FPU stack
  141. xor ecx,ecx
  142. jmp test_base
  143. special_exponent:
  144. ; only one argument is loaded to FPU stack
  145. xor ecx,ecx ; we use ecx to set flags
  146. and eax,000fffffH ; eax=high
  147. or eax,[esp+16] ; test whether mantissa is zero
  148. jne exponent_is_NAN
  149. lea edx,[esp+8] ; pointer to arg1(base)
  150. call _fload_withFB ; load arg1(base) to FPU stack
  151. test_base: ; arg2 may be inf, QNaN or normal
  152. ; both arguments are loaded to FPU stack
  153. mov eax,[esp+12] ; arg1 high
  154. mov edx,eax
  155. and eax,7ff00000H
  156. and edx,000fffffH ; test mantissa of arg2
  157. cmp eax,7ff00000H
  158. jne end_of_tests
  159. or edx,[esp+8]
  160. jnz base_is_NAN ; arg1 is NaN,
  161. end_of_tests:
  162. test ecx,ecx
  163. jnz one_of_args_is_QNaN ; base is QNaN
  164. ; one of args is infinity and second is not NaN. In this case we use powhlp()
  165. ;_usepowhlp
  166. sub esp, SBUFSIZE+8 ; get storage for _retval and savebuf
  167. mov ecx, esp
  168. push ecx ; push address for result
  169. sub esp, 16
  170. fstp qword ptr [esp]
  171. fstp qword ptr [esp+8]
  172. fsave [ecx+8]
  173. call _powhlp
  174. add esp, 16 ; clear arguments if _cdecl.
  175. pop ecx
  176. frstor [ecx+8]
  177. fld qword ptr [ecx] ; load result on the NDP stack
  178. add esp, SBUFSIZE+8 ; get rid of storage
  179. test eax,eax
  180. jz _fast_exit
  181. mov eax,DOMAIN
  182. jmp _ErrorHandling
  183. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  184. ; 2. Base has zero exponent field
  185. ;
  186. test_if_we_have_zero_base:
  187. mov eax,[esp+12]
  188. and eax,000fffffH
  189. or eax,[esp+8]
  190. jnz base_is_not_zero
  191. ; at this point we have two arguments on FPU stack.
  192. ; We know that TOS is zero, and arg2 is not special.
  193. ; We disinguish 3 cases:
  194. ; (1) exponent is zero
  195. ; (2) exponent is odd
  196. ; (3) none of above
  197. fstp st(0) ; remove zero from FPU stack
  198. mov eax,[esp+20] ; test if arg2 is also zero
  199. and eax,7fffffffh
  200. or eax,[esp+16]
  201. jz zero_to_zero
  202. ; check whether exponent is odd
  203. call _test_whether_TOS_is_int
  204. ; cl=1 if exponent is odd, 2 - if even and 0 otherwise
  205. mov ch,[esp+15]
  206. shr ch,7 ; ch==1 iff base is negative
  207. test [esp+23],80H ; check sign of exponent
  208. jz exp_is_positive
  209. ; exponent is negative
  210. fld [_infinity]
  211. test cl,ch
  212. jz ret_inf
  213. fchs ; base <0 and exponent is negative odd
  214. ret_inf:
  215. mov eax,SING
  216. jmp _ErrorHandling
  217. exp_is_positive: ; eax=error_code
  218. fldz
  219. test cl,ch
  220. jz _fast_exit
  221. fchs ; base <0 and exponent positive is odd
  222. jmp _fast_exit ; return -0.0
  223. zero_to_zero: ; arg1 and arg2 are zero
  224. fstp st(0) ; remove useless argument from FPU stack
  225. fld1
  226. jmp _fast_exit
  227. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  228. ;3. Base is negative.
  229. ;
  230. ; If exponent is not integer it's a DOMAIN error
  231. ;
  232. test_if_exp_is_int:
  233. fld st(1)
  234. call _test_whether_TOS_is_int
  235. fchs
  236. test cl,cl
  237. jnz normal
  238. fstp st(0)
  239. fstp st(0)
  240. fld [_indefinite]
  241. mov eax,DOMAIN
  242. jmp _ErrorHandling
  243. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  244. ;
  245. ; _test_whether_TOS_is_int
  246. ;
  247. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  248. ; returns in cl : 0,1,2 if TOS is non-int, odd int or even int respectively
  249. ;
  250. _test_whether_TOS_is_int:
  251. fld st(0) ; duplicate stack top
  252. frndint
  253. fcomp ; is TOS integer???
  254. mov cl,0 ; prepare return value
  255. fstsw ax
  256. sahf
  257. jne _not_int ; TOS is not integer
  258. fmul [_half]
  259. inc cl ; cl>0, when exponent is integer
  260. fld st(0) ; (exponent/2)
  261. frndint
  262. fcompp ; check if (exponent/2)==(int)(exponent/2)
  263. fstsw ax
  264. sahf
  265. jne _odd
  266. inc cl ; sign that exponent is even
  267. _odd:
  268. ret
  269. _not_int:
  270. fstp st(0)
  271. ret
  272. _CIpow_default endp
  273. end