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.

511 lines
10 KiB

  1. page ,132
  2. title 87tran - elementary functions - EXP, LOG, LN, X^Y
  3. ;***
  4. ;87tran.asm - elementary functions - EXP, LOG, LN, X^Y
  5. ;
  6. ; Copyright (c) 1984-2001, Microsoft Corporation. All rights reserved.
  7. ;
  8. ;Purpose:
  9. ; Support for EXP, LOG, LN, X^Y (80x87/emulator version)
  10. ;
  11. ;Revision History:
  12. ;
  13. ; 07/04/84 Greg Whitten
  14. ; initial version
  15. ;
  16. ; 07/05/85 Greg Whitten
  17. ; support x ^ y where x < 0 and y is an integer
  18. ;
  19. ; 07/08/85 Greg Whitten
  20. ; corrected value of infinity (was a NaN)
  21. ;
  22. ; 07/26/85 Greg Whitten
  23. ; make XENIX version truely System V compatible
  24. ;
  25. ; 10/31/85 Jamie Bariteau
  26. ; made _fFEXP and _fFLN public labels
  27. ;
  28. ; 05/29/86 Jamie Bariteau
  29. ; make pow return values conform to System V and
  30. ; ANSI C standards
  31. ;
  32. ; 09/12/86 Barry McCord
  33. ; added FORTRAN specific code to deal
  34. ; with zero**nonpositive;
  35. ; it requires run-time switching on language
  36. ; for mixed-language support
  37. ;
  38. ; 10/09/86 Barry McCord
  39. ; cotan(0.0) ==> SING error (jmp _rtinfnpopse),
  40. ; return infinity
  41. ;
  42. ; 06/11/87 Greg Whitten
  43. ; faster transcendental functions
  44. ;
  45. ; 06/24/87 Barry McCord
  46. ; fixed FORTRAN 4.01 bug (bcp #1801) in which
  47. ; an expression of the form
  48. ; (small positive less than one) ** (large positive)
  49. ; was overflowing instead of underflowing to zero
  50. ;
  51. ; 10/30/87 Bill Johnston
  52. ; made changes for os/2 support.
  53. ;
  54. ; 04/25/88 Bill Johnston
  55. ; _cpower is now on stack for MTHREAD
  56. ;
  57. ; 05/01/88 Bill Johnston
  58. ; si was being trashed in MTHREAD
  59. ;
  60. ; 06/03/88 Bill Johnston
  61. ; fixed neg ^ int int MTHREAD case
  62. ;
  63. ; 08/24/88 Bill Johnston
  64. ; 386 version
  65. ;
  66. ; 11/15/91 Georgios Papagiannakopoulos
  67. ; NT port. call _powhlp to handle special cases for pow()
  68. ;
  69. ; 04/01/91 Georgios Papagiannakopoulos
  70. ; fixed special values: log(-INF), log(0), pow(0, neg)
  71. ;
  72. ; 10/27/92 Steve Salisbury
  73. ; Move declaration of _powhlp out of .data declarations
  74. ; This fix is required for use with MASM 6.10.
  75. ;
  76. ; 11/06/92 Georgios Papagiannakopoulos
  77. ; changed special return values for NCEG conformance
  78. ;
  79. ; 09/06/94 Chris Weight
  80. ; Change MTHREAD to _MT.
  81. ;
  82. ; 12/09/94 Jamie MacCalman
  83. ; Modified fFEXP to test for bogus Pentiums and call an FDIV workaround
  84. ;
  85. ; 12/13/94 SKS Correct spelling of _adjust_fdiv
  86. ;
  87. ; 10-15-95 BWT Don't do _adjust_fdiv test for NT.
  88. ;
  89. ;*******************************************************************************
  90. .xlist
  91. include cruntime.inc
  92. include mrt386.inc
  93. include elem87.inc
  94. include os2supp.inc
  95. .list
  96. .data
  97. globalT _infinity, 07FFF8000000000000000R
  98. globalT _minfinity, 0FFFF8000000000000000R
  99. globalT _logemax, 0400DB1716685B9D7A7DCR
  100. staticT _log2max, 0400DFFFF000000000000R
  101. staticT _smallarg, 03FFD95F619980C4336F7R
  102. staticQ _half, 03fe0000000000000R
  103. SBUFSIZE EQU 108
  104. ifndef _MT
  105. staticT _temp, 0
  106. extrn _cpower:byte
  107. endif
  108. ifndef NT_BUILD
  109. extrn _adjust_fdiv:dword
  110. endif
  111. jmptab OP_EXP,3,<'exp',0,0,0>,<0,0,0,0,0,0>,1
  112. DNCPTR codeoffset fFEXP ; 0000 TOS Valid non-0
  113. DNCPTR codeoffset _rtonenpop ; 0001 TOS 0
  114. DNCPTR codeoffset _tosnan1 ; 0010 TOS NAN
  115. DNCPTR codeoffset _rtforexpinf ; 0011 TOS Inf
  116. page
  117. CODESEG
  118. extrn _rtindfpop:near
  119. extrn _rtindfnpop:near
  120. extrn _rtnospop:near
  121. extrn _rtonepop:near
  122. extrn _rtonenpop:near
  123. extrn _rttospop:near
  124. extrn _rttosnpop:near
  125. extrn _rttosnpopde:near
  126. extrn _rtzeronpop:near
  127. extrn _tosnan1:near
  128. extrn _tosnan2:near
  129. extrn _nosnan2:near
  130. extrn _nan2:near
  131. extrn _powhlp:proc
  132. ifndef NT_BUILD
  133. extrn _safe_fdivr:near
  134. endif
  135. ;----------------------------------------------------------
  136. ;
  137. ; LOG AND EXPONENTIAL FUNCTIONS
  138. ;
  139. ;----------------------------------------------------------
  140. ;
  141. ; INPUTS - For single argument functions the argument
  142. ; is the stack top. For fFYTOX the base
  143. ; is next to stack top, the exponent is
  144. ; the stack top.
  145. ; For single argument functions the sign is
  146. ; in bit 2 of CL. For fFYTOX the base
  147. ; sign is bit 2 of CH, the exponent
  148. ; sign is bit 2 of CL.
  149. ;
  150. ; OUTPUT - The result is the stack top
  151. ;
  152. ;----------------------------------------------------------
  153. lab fFYTOX
  154. mov DSF.ErrorType, CHECKRANGE ; indicate possible over/under flow on exit
  155. or ch,ch ; base < 0
  156. JSNZ negYTOX ; check for integer power
  157. fxch ; TOS = base , NOS = exponent
  158. lab fFXTOY
  159. fyl2x ; compute y*log2(x)
  160. jmp short fF2X ; compute 2^(y*log2(x))
  161. ;-----------------------------------------------
  162. ;
  163. ; Entry for exponential function (exp)
  164. ;
  165. ;-----------------------------------------------
  166. labelNP _fFEXP, PUBLIC
  167. lab fFEXP
  168. mov DSF.ErrorType, CHECKRANGE ; indicate possible over/under flow on exit
  169. xor ch,ch ; result is always positive
  170. fldl2e
  171. fmul ; convert log base e to log base 2
  172. lab fF2X
  173. call _ffexpm1 ; get exponent and (2^fraction)-1
  174. fld1
  175. fadd
  176. test CondCode,1 ; if fraction > 0 (TOS > 0)
  177. JSZ ExpNoInvert ; bypass 2^x invert
  178. fld1
  179. ifdef NT_BUILD ; NT always handles the P5 bug in the OS
  180. fdivrp st(1),st(0)
  181. else
  182. cmp _adjust_fdiv, 1
  183. jz badP5_fdivr
  184. fdivrp st(1),st(0)
  185. jmp fdivr_done
  186. lab badP5_fdivr
  187. call _safe_fdivr
  188. lab fdivr_done
  189. endif
  190. lab ExpNoInvert
  191. test dl,040h ; if integer part was zero
  192. JSNZ ExpScaled ; bypass scaling to avoid bug
  193. fscale ; now TOS = 2^x
  194. lab ExpScaled
  195. or ch,ch ; check for negate flag
  196. JSZ expret
  197. fchs ; negate result (negreal ^ odd integer)
  198. lab expret
  199. jmp _rttospop
  200. lab negYTOX ; check for negreal ^ integer
  201. call _isintTOS
  202. or eax, eax
  203. JSE negYTOXerror
  204. xor ch,ch
  205. cmp eax, 2
  206. JSE evenexp
  207. not ch ; ch <> 0 means negative result
  208. lab evenexp
  209. fxch
  210. fabs ; x is positive
  211. jmp fFXTOY ; continue with ch <> 0 for neg result
  212. lab _rtfor0to0
  213. ;cmp [_cpower], 1 ; DISABLED (conform to NCEG spec)
  214. ;JSE c_0to0 ; C requires a DOMAIN error for System V compat.
  215. jmp _rtonepop ; MS FORTRAN has 0.0**0.0 == 1.0
  216. c_0to0:: ; System V needs DOMAIN error with 0.0 return
  217. lab negYTOXerror
  218. lab Yl2XArgNegative
  219. jmp _rtindfpop ; DOMAIN error or SING error
  220. ; top of stack now has a NAN
  221. ; code in 87cdisp replaces this with
  222. ; proper System V return value
  223. ; (for C only)
  224. ; FORTRAN keeps indefinite value but
  225. ; currently aborts on DOMAIN
  226. ; and SING errors
  227. ; FORTRAN SING error (return infinity)
  228. ; e.g. 0.0**negative
  229. ; and cotan(0.0)
  230. ;
  231. labelNP _rtinfpopse, PUBLIC
  232. fstp st(0)
  233. labelNP _rtinfnpopse, PUBLIC
  234. fstp st(0)
  235. fld tbyte ptr [_infinity]
  236. mov DSF.ErrorType, SING
  237. ret
  238. labelNP _fFLN, PUBLIC
  239. lab fFLN
  240. fldln2
  241. fxch
  242. ftst
  243. fstsw DSF.StatusWord
  244. fwait
  245. test CondCode, 041H ; if arg is negative or zero
  246. JSNZ Yl2XArgNegative ; return a NAN
  247. fyl2x ; compute y*log2(x)
  248. ret
  249. ;-------------------------------------------------------
  250. ;
  251. ; Logarithmic functions (log and log 10) entry points
  252. ;
  253. ;-------------------------------------------------------
  254. lab _rtforln0 ; (we don't distinguish +0, -0)
  255. mov DSF. ErrorType, SING ; set SING error
  256. fstp st(0)
  257. fld tbyte ptr [_minfinity]
  258. ret
  259. lab _rtforloginf
  260. or cl, cl ; check sign
  261. JSNZ tranindfnpop ; if negetive return indefinite
  262. ret ; else return +INF
  263. ; no overflow in this case (IEEE)
  264. lab fFLOGm
  265. fldlg2 ; main LOG10 entry point
  266. jmp short fFYL2Xm
  267. lab fFLNm ; main LN entry point
  268. fldln2
  269. lab fFYL2Xm
  270. fxch
  271. or cl, cl ; if arg is negative
  272. JSNZ Yl2XArgNegative ; return a NAN
  273. fyl2x ; compute y*log2(x)
  274. ret
  275. page
  276. lab _rtforyto0
  277. jmp _rtonepop ; return 1.0
  278. lab _rtfor0tox
  279. call _isintTOS
  280. fstp st(0)
  281. fstp st(0)
  282. or cl, cl ; if 0^(-valid)
  283. JSNZ _rtfor0toneg ; do more checking
  284. fldz
  285. cmp eax, 1 ; eax has the return value of _isintTOS
  286. JSNE zerotoxdone
  287. or ch, ch
  288. JSE zerotoxdone
  289. fchs
  290. lab zerotoxdone
  291. ret
  292. lab _rtfor0toneg
  293. mov DSF.ErrorType, SING
  294. fld tbyte ptr [_infinity]
  295. cmp eax, 1 ; eax has the return value of _isintTOS
  296. JSNE zerotoxdone
  297. or ch, ch
  298. JSE zerotoxdone
  299. fchs
  300. jmp zerotoxdone
  301. lab tranzeropop
  302. fstp st(0) ; toss 1 stack entry
  303. lab tranzeronpop
  304. jmp _rtzeronpop
  305. lab tranindfpop
  306. fstp st(0) ; toss 1 stack entry
  307. lab tranindfnpop
  308. jmp _rtindfnpop
  309. lab ExpArgOutOfRange
  310. pop rax ; remove return address from stack
  311. ; We need to check the sign of the
  312. ; exponent to distinguish underflow
  313. ; from overflow. We cannot just check
  314. ; CL directly since for the XtoY case,
  315. ; the exponent is a product of Y*log2(x)
  316. ; and not an original argument that
  317. ; has already been thru FXAM. So,
  318. ; the following instructions were
  319. ; substituted to fix FORTRAN 4.01
  320. ; bcp #1801)
  321. ftst ; check if exponent was negative large
  322. fstsw DSF.StatusWord
  323. fwait
  324. test CondCode, 01h ; if valid^(-large)
  325. JSNZ zeronpopue ; underflow error/return zero
  326. fstp st(0) ; else return infinity/overflow
  327. fld [_infinity]
  328. or ch, ch
  329. JSZ _expbigret
  330. fchs
  331. lab _expbigret
  332. ret
  333. lab zeronpopue
  334. mov DSF.ErrorType, UNDERFLOW
  335. jmp _rtzeronpop
  336. labelNP _rtinfpop, PUBLIC
  337. fstp st(0) ; remove ST(0)
  338. labelNP _rtinfnpop, PUBLIC
  339. fstp st(0) ; remove ST(0)
  340. fld [_infinity] ; push infinity onto stack
  341. lab setOVERFLOW
  342. mov DSF.ErrorType, OVERFLOW ; set OVERFLOW error
  343. ret
  344. lab _rtforexpinf
  345. or cl, cl
  346. JSNZ tranzeronpop ; if exp(-infinity) return +zero
  347. fstp st(0)
  348. fld [_infinity] ; return infinity, no overflow
  349. ret
  350. labelNP _ffexpm1, PUBLIC
  351. fld st(0) ; copy TOS
  352. fabs ; make TOS +ve
  353. fld [_log2max] ; get log2 of largest number
  354. fcompp
  355. fstsw DSF.StatusWord
  356. fwait
  357. test CondCode, 041H ; if abs(arg) >= 2^15-.5
  358. JSNZ ExpArgOutOfRange ; perform arg out of range routine
  359. fld st(0) ; copy TOS
  360. frndint ; near round to integer
  361. ftst
  362. fstsw DSF.StatusWord
  363. fwait
  364. mov dl, CondCode ; save sign of integer part
  365. fxch ; NOS gets integer part
  366. fsub st,st(1) ; TOS gets fraction
  367. ftst
  368. fstsw DSF.StatusWord ; store sign of fraction
  369. fabs
  370. f2xm1
  371. ret
  372. ;
  373. ; returns 0, 1, 2 if TOS is non-int, odd int or even int respectively
  374. ;
  375. lab _isintTOS
  376. fld st(0)
  377. frndint
  378. fcomp
  379. fstsw ax
  380. sahf
  381. JSNE notanint
  382. fld st(0) ; it is an integer
  383. fmul [_half]
  384. fld st(0)
  385. frndint
  386. fcompp
  387. fstsw ax
  388. sahf
  389. JSE evenint
  390. mov eax, 1
  391. lab _isintTOSret
  392. ret
  393. lab notanint
  394. mov eax, 0
  395. jmp _isintTOSret
  396. lab evenint
  397. mov eax, 2
  398. jmp _isintTOSret
  399. lab _usepowhlp
  400. push rsi ; save rsi
  401. sub rsp, SBUFSIZE+8 ; get storage for _retval and savebuf
  402. mov rsi, rsp
  403. push rsi ; push address for result
  404. sub rsp, 8
  405. fstp qword ptr [rsp]
  406. sub rsp, 8
  407. fstp qword ptr [rsp]
  408. fsave [rsi+8]
  409. call _powhlp
  410. ifndef _STDCALL
  411. add esp, 16+ISIZE ; clear arguments if _cdecl.
  412. endif
  413. frstor [rsi+8]
  414. fld qword ptr [rsi] ; load result on the NDP stack
  415. add rsp, SBUFSIZE+8 ; get rid of storage
  416. pop rsi ; restore rsi
  417. test rax, rax ; check return value for domain error
  418. JSZ noerror
  419. jmp _rttosnpopde
  420. lab noerror
  421. ret
  422. end