Leaked source code of windows server 2003
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.

973 lines
21 KiB

  1. /*++
  2. Copyright (c) 1995-2000 Microsoft Corporation
  3. Module Name:
  4. fputrig.c
  5. Abstract:
  6. Floating point trig and transcendental functions
  7. Author:
  8. 05-Oct-1995 BarryBo
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <float.h>
  16. #include <math.h>
  17. #include <stdio.h>
  18. #include "wx86.h"
  19. #include "cpuassrt.h"
  20. #include "fragp.h"
  21. #include "fpufragp.h"
  22. ASSERTNAME;
  23. //
  24. // Forward declarations
  25. //
  26. NPXFUNC1(FCOS_VALID);
  27. NPXFUNC1(FCOS_ZERO);
  28. NPXFUNC1(FCOS_SPECIAL);
  29. NPXFUNC1(FCOS_EMPTY);
  30. NPXFUNC2(FPATAN_VALID_VALID);
  31. NPXFUNC2(FPATAN_VALID_SPECIAL);
  32. NPXFUNC2(FPATAN_SPECIAL_VALID);
  33. NPXFUNC2(FPATAN_SPECIAL_SPECIAL);
  34. NPXFUNC2(FPATAN_EMPTY_ALL);
  35. NPXFUNC2(FPATAN_ALL_EMPTY);
  36. NPXFUNC0(FPTAN_VALID);
  37. NPXFUNC0(FPTAN_ZERO);
  38. NPXFUNC0(FPTAN_SPECIAL);
  39. NPXFUNC0(FSIN_VALID);
  40. NPXFUNC0(FSIN_ZERO);
  41. NPXFUNC0(FSIN_SPECIAL);
  42. NPXFUNC0(FSIN_EMPTY);
  43. NPXFUNC0(FSINCOS_VALID);
  44. NPXFUNC0(FSINCOS_ZERO);
  45. NPXFUNC0(FSINCOS_SPECIAL);
  46. NPXFUNC2(FYL2X_VALID_VALID);
  47. NPXFUNC2(FYL2X_VALID_ZERO);
  48. NPXFUNC2(FYL2X_ZERO_VALID);
  49. NPXFUNC2(FYL2X_ZERO_ZERO);
  50. NPXFUNC2(FYL2X_SPECIAL_VALIDORZERO);
  51. NPXFUNC2(FYL2X_VALIDORZERO_SPECIAL);
  52. NPXFUNC2(FYL2X_SPECIAL_SPECIAL);
  53. NPXFUNC2(FYL2X_ANY_EMPTY);
  54. NPXFUNC2(FYL2X_EMPTY_ANY);
  55. NPXFUNC2(FYL2XP1_VALIDORZERO_ZERO);
  56. NPXFUNC2(FYL2XP1_VALIDORZERO_VALID);
  57. NPXFUNC2(FYL2XP1_SPECIAL_VALIDORZERO);
  58. NPXFUNC2(FYL2XP1_VALIDORZERO_SPECIAL);
  59. NPXFUNC2(FYL2XP1_SPECIAL_SPECIAL);
  60. NPXFUNC2(FYL2XP1_ANY_EMPTY);
  61. NPXFUNC2(FYL2XP1_EMPTY_ANY);
  62. NPXFUNC1(F2XM1_VALID);
  63. NPXFUNC1(F2XM1_ZERO);
  64. NPXFUNC1(F2XM1_SPECIAL);
  65. NPXFUNC1(F2XM1_EMPTY);
  66. //
  67. // Jump tables
  68. //
  69. const NpxFunc1 FCOSTable[TAG_MAX] = {
  70. FCOS_VALID,
  71. FCOS_ZERO,
  72. FCOS_SPECIAL,
  73. FCOS_EMPTY
  74. };
  75. const NpxFunc2 FPATANTable[TAG_MAX][TAG_MAX] = {
  76. // left = TAG_VALID, right is ...
  77. { FPATAN_VALID_VALID, FPATAN_VALID_VALID, FPATAN_VALID_SPECIAL, FPATAN_ALL_EMPTY },
  78. // left = TAG_ZERO, right is ...
  79. { FPATAN_VALID_VALID, FPATAN_VALID_VALID, FPATAN_VALID_SPECIAL, FPATAN_ALL_EMPTY },
  80. // left = TAG_SPECIAL, right is ...
  81. { FPATAN_SPECIAL_VALID, FPATAN_SPECIAL_VALID, FPATAN_SPECIAL_SPECIAL, FPATAN_ALL_EMPTY },
  82. // left = TAG_EMPTY, right is ...
  83. { FPATAN_EMPTY_ALL, FPATAN_EMPTY_ALL, FPATAN_EMPTY_ALL, FPATAN_EMPTY_ALL }
  84. };
  85. const NpxFunc0 FPTANTable[TAG_MAX-1] = {
  86. FPTAN_VALID,
  87. FPTAN_ZERO,
  88. FPTAN_SPECIAL
  89. };
  90. const NpxFunc0 FSINTable[TAG_MAX] = {
  91. FSIN_VALID,
  92. FSIN_ZERO,
  93. FSIN_SPECIAL,
  94. FSIN_EMPTY
  95. };
  96. const NpxFunc0 FSINCOSTable[TAG_MAX-1] = {
  97. FSINCOS_VALID,
  98. FSINCOS_ZERO,
  99. FSINCOS_SPECIAL
  100. };
  101. // In the functions, l == ST(0), r = ST(1)
  102. // r = r*log(l), l must be > 0
  103. const NpxFunc2 FYL2XTable[TAG_MAX][TAG_MAX] = {
  104. // left is TAG_VALID, right is ...
  105. { FYL2X_VALID_VALID, FYL2X_VALID_ZERO, FYL2X_VALIDORZERO_SPECIAL, FYL2X_ANY_EMPTY },
  106. // left is TAG_ZERO, right is ...
  107. { FYL2X_ZERO_VALID, FYL2X_ZERO_ZERO, FYL2X_VALIDORZERO_SPECIAL, FYL2X_ANY_EMPTY },
  108. // left is TAG_SPECIAL, right is ...
  109. { FYL2X_SPECIAL_VALIDORZERO, FYL2X_SPECIAL_VALIDORZERO, FYL2X_SPECIAL_SPECIAL, FYL2X_ANY_EMPTY },
  110. // left is TAG_EMPTY, right is ...
  111. { FYL2X_EMPTY_ANY, FYL2X_EMPTY_ANY, FYL2X_EMPTY_ANY, FYL2X_EMPTY_ANY}
  112. };
  113. // In the functions, l == ST(0), r = ST(1)
  114. // r = r*(logl+1), l must be > 1
  115. const NpxFunc2 FYL2XP1Table[TAG_MAX][TAG_MAX] = {
  116. // left is TAG_VALID, right is ...
  117. { FYL2XP1_VALIDORZERO_VALID, FYL2XP1_VALIDORZERO_ZERO, FYL2XP1_VALIDORZERO_SPECIAL, FYL2XP1_ANY_EMPTY },
  118. // left is TAG_ZERO, right is ...
  119. { FYL2XP1_VALIDORZERO_VALID, FYL2XP1_VALIDORZERO_ZERO, FYL2XP1_VALIDORZERO_SPECIAL, FYL2X_ANY_EMPTY },
  120. // left is TAG_SPECIAL, right is ...
  121. { FYL2XP1_SPECIAL_VALIDORZERO, FYL2XP1_SPECIAL_VALIDORZERO, FYL2XP1_SPECIAL_SPECIAL, FYL2XP1_ANY_EMPTY },
  122. // left is TAG_EMPTY, right is ...
  123. { FYL2XP1_EMPTY_ANY, FYL2XP1_EMPTY_ANY, FYL2XP1_EMPTY_ANY, FYL2XP1_EMPTY_ANY}
  124. };
  125. const NpxFunc1 F2XM1Table[TAG_MAX] = {
  126. F2XM1_VALID,
  127. F2XM1_ZERO,
  128. F2XM1_SPECIAL,
  129. F2XM1_EMPTY
  130. };
  131. NPXFUNC1(FCOS_VALID)
  132. {
  133. Fp->r64 = cos(Fp->r64);
  134. SetTag(Fp);
  135. }
  136. NPXFUNC1(FCOS_ZERO)
  137. {
  138. Fp->Tag = TAG_VALID;
  139. Fp->r64 = 1.0;
  140. }
  141. NPXFUNC1(FCOS_SPECIAL)
  142. {
  143. switch (Fp->TagSpecial) {
  144. case TAG_SPECIAL_DENORM:
  145. FCOS_VALID(cpu, Fp);
  146. break;
  147. case TAG_SPECIAL_INFINITY:
  148. cpu->FpStatusC2 = 1;
  149. SetIndefinite(Fp);
  150. break;
  151. case TAG_SPECIAL_SNAN:
  152. HandleSnan(cpu, Fp);
  153. break;
  154. case TAG_SPECIAL_QNAN:
  155. case TAG_SPECIAL_INDEF:
  156. HandleInvalidOp(cpu);
  157. break;
  158. }
  159. }
  160. NPXFUNC1(FCOS_EMPTY)
  161. {
  162. HandleStackEmpty(cpu, Fp);
  163. }
  164. FRAG0(FCOS)
  165. {
  166. PFPREG ST0;
  167. FpArithPreamble(cpu);
  168. cpu->FpStatusC2 = 0;
  169. ST0 = cpu->FpST0;
  170. (*FCOSTable[ST0->Tag])(cpu, ST0);
  171. }
  172. NPXFUNC2(FPATAN_VALID_VALID)
  173. {
  174. l->r64 = Proxyatan2(l->r64, r->r64);
  175. SetTag(l);
  176. POPFLT;
  177. }
  178. NPXFUNC2(FPATAN_VALID_SPECIAL)
  179. {
  180. switch (r->TagSpecial) {
  181. case TAG_SPECIAL_DENORM:
  182. case TAG_SPECIAL_INFINITY:
  183. FPATAN_VALID_VALID(cpu, l, r);
  184. break;
  185. case TAG_SPECIAL_SNAN:
  186. if (HandleSnan(cpu, r)) {
  187. break;
  188. }
  189. // else fall into QNAN
  190. case TAG_SPECIAL_QNAN:
  191. case TAG_SPECIAL_INDEF:
  192. // return the QNAN as the result
  193. l->r64 = r->r64;
  194. l->Tag = TAG_SPECIAL;
  195. l->TagSpecial = r->TagSpecial;
  196. POPFLT;
  197. break;
  198. }
  199. }
  200. NPXFUNC2(FPATAN_SPECIAL_VALID)
  201. {
  202. switch (l->TagSpecial) {
  203. case TAG_SPECIAL_DENORM:
  204. case TAG_SPECIAL_INFINITY:
  205. FPATAN_VALID_VALID(cpu, l, r);
  206. break;
  207. case TAG_SPECIAL_SNAN:
  208. if (HandleSnan(cpu, l)) {
  209. break;
  210. }
  211. // else fall into QNAN
  212. case TAG_SPECIAL_QNAN:
  213. case TAG_SPECIAL_INDEF:
  214. // The QNAN is already in l, so nothing to do.
  215. POPFLT;
  216. break;
  217. }
  218. }
  219. NPXFUNC2(FPATAN_SPECIAL_SPECIAL)
  220. {
  221. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  222. return;
  223. }
  224. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  225. return;
  226. }
  227. if (IS_TAG_NAN(l)) {
  228. if (IS_TAG_NAN(r)) {
  229. //
  230. // Return the larger of the two NANs
  231. //
  232. l->r64 = l->r64 + r->r64;
  233. SetTag(l);
  234. }
  235. //
  236. // else l is a NAN and r isn't - return the NAN in l
  237. //
  238. POPFLT;
  239. return;
  240. }
  241. if (IS_TAG_NAN(r)) {
  242. // r is a NAN and l isn't - return the NAN in l
  243. l->r64 = r->r64;
  244. l->Tag = TAG_SPECIAL;
  245. l->TagSpecial = r->TagSpecial;
  246. POPFLT;
  247. }
  248. // Otherwise, l and r are both INFINITY. Return INDEFINITE
  249. CPUASSERT(l->TagSpecial == TAG_SPECIAL_INFINITY &&
  250. r->TagSpecial == TAG_SPECIAL_INFINITY);
  251. SetIndefinite(l);
  252. POPFLT;
  253. }
  254. NPXFUNC2(FPATAN_EMPTY_ALL)
  255. {
  256. if (!HandleStackEmpty(cpu, l)) {
  257. (*FPATANTable[TAG_SPECIAL][r->Tag])(cpu, l, r);
  258. }
  259. }
  260. NPXFUNC2(FPATAN_ALL_EMPTY)
  261. {
  262. if (!HandleStackEmpty(cpu, r)) {
  263. (*FPATANTable[l->Tag][TAG_SPECIAL])(cpu, l, r);
  264. }
  265. }
  266. FRAG0(FPATAN)
  267. {
  268. PFPREG l = &cpu->FpStack[ST(1)];
  269. PFPREG r = cpu->FpST0;
  270. FpArithPreamble(cpu);
  271. (*FPATANTable[l->Tag][r->Tag])(cpu, l, r);
  272. }
  273. NPXFUNC0(FPTAN_VALID)
  274. {
  275. int Exponent;
  276. PFPREG ST0;
  277. // get the exponent and make sure it is < 63
  278. ST0 = cpu->FpST0;
  279. Exponent = (int)((ST0->rdw[1] >> 20) & 0x7ff) - 1023;
  280. if (Exponent >= 63) {
  281. cpu->FpStatusC2 = 1;
  282. return;
  283. }
  284. ST0->r64 = tan(ST0->r64);
  285. SetTag(ST0);
  286. PUSHFLT(ST0);
  287. ST0->Tag = TAG_VALID;
  288. ST0->r64 = 1.0;
  289. }
  290. NPXFUNC0(FPTAN_ZERO)
  291. {
  292. PFPREG ST0;
  293. ST0=cpu->FpST0;
  294. ST0->r64 = 0.0;
  295. ST0->Tag = TAG_ZERO;
  296. PUSHFLT(ST0);
  297. ST0->r64 = 1.0;
  298. ST0->Tag = TAG_VALID;
  299. }
  300. NPXFUNC0(FPTAN_SPECIAL)
  301. {
  302. if (cpu->FpST0->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, cpu->FpST0)) {
  303. return;
  304. } else if (cpu->FpST0->TagSpecial == TAG_SPECIAL_DENORM) {
  305. FPTAN_VALID(cpu);
  306. }
  307. cpu->FpStatusC2 = 1;
  308. }
  309. FRAG0(FPTAN)
  310. {
  311. PFPREG ST0;
  312. FpArithPreamble(cpu);
  313. ST0 = cpu->FpST0;
  314. //
  315. // TAG_EMPTY is handled first so that we can check ST(7) before
  316. // anything else has a chance to raise an exception.
  317. //
  318. if (ST0->Tag == TAG_EMPTY && HandleStackEmpty(cpu, ST0)) {
  319. return;
  320. }
  321. if (cpu->FpStack[ST(7)].Tag != TAG_EMPTY) {
  322. HandleStackFull(cpu, &cpu->FpStack[ST(7)]);
  323. return;
  324. }
  325. // assume no error
  326. cpu->FpStatusC2 = 0;
  327. // calculate the value
  328. CPUASSERT(ST0->Tag < TAG_EMPTY); // EMPTY was already handled
  329. (*FPTANTable[ST0->Tag])(cpu);
  330. }
  331. NPXFUNC0(FSIN_VALID)
  332. {
  333. PFPREG ST0;
  334. ST0 = cpu->FpST0;
  335. ST0->r64 = sin(ST0->r64);
  336. SetTag(ST0);
  337. }
  338. NPXFUNC0(FSIN_ZERO)
  339. {
  340. // sin(0.0) == 0.0, so there is nothing to do
  341. }
  342. NPXFUNC0(FSIN_SPECIAL)
  343. {
  344. if (cpu->FpST0->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, cpu->FpST0)) {
  345. return;
  346. } else if (cpu->FpST0->TagSpecial == TAG_SPECIAL_DENORM) {
  347. FSIN_VALID(cpu);
  348. }
  349. cpu->FpStatusC2 = 1;
  350. }
  351. NPXFUNC0(FSIN_EMPTY)
  352. {
  353. if (!HandleStackEmpty(cpu, cpu->FpST0)) {
  354. cpu->FpStatusC2 = 1;
  355. }
  356. }
  357. FRAG0(FSIN)
  358. {
  359. FpArithPreamble(cpu);
  360. // assume no error
  361. cpu->FpStatusC2 = 0;
  362. // calculate the value
  363. (*FSINTable[cpu->FpST0->Tag])(cpu);
  364. }
  365. NPXFUNC0(FSINCOS_VALID)
  366. {
  367. DOUBLE Val;
  368. PFPREG ST0;
  369. ST0 = cpu->FpST0;
  370. Val = ST0->r64;
  371. ST0->r64 = sin(Val);
  372. SetTag(ST0);
  373. PUSHFLT(ST0);
  374. ST0->r64 = cos(Val);
  375. SetTag(ST0);
  376. }
  377. NPXFUNC0(FSINCOS_ZERO)
  378. {
  379. PFPREG ST0;
  380. ST0=cpu->FpST0;
  381. ST0->r64 = 0.0;
  382. ST0->Tag = TAG_ZERO;
  383. PUSHFLT(ST0);
  384. ST0->r64 = 1.0;
  385. ST0->Tag = TAG_VALID;
  386. }
  387. NPXFUNC0(FSINCOS_SPECIAL)
  388. {
  389. switch (cpu->FpST0->TagSpecial) {
  390. case TAG_SPECIAL_DENORM:
  391. FSINCOS_VALID(cpu);
  392. break;
  393. case TAG_SPECIAL_INFINITY:
  394. cpu->FpStatusC2 = 1;
  395. SetIndefinite(cpu->FpST0);
  396. break;
  397. case TAG_SPECIAL_SNAN:
  398. if (HandleSnan(cpu, cpu->FpST0)) {
  399. return;
  400. }
  401. // else fall into TAG_SPECIAL_QNAN
  402. case TAG_SPECIAL_QNAN:
  403. case TAG_SPECIAL_INDEF:
  404. cpu->FpStatusC2 = 1;
  405. break;
  406. }
  407. }
  408. FRAG0(FSINCOS)
  409. {
  410. PFPREG ST0;
  411. FpArithPreamble(cpu);
  412. // assume no errors
  413. cpu->FpStatusC2 = 0;
  414. ST0 = cpu->FpST0;
  415. if (ST0->Tag == TAG_EMPTY && HandleStackEmpty(cpu, ST0)) {
  416. return;
  417. }
  418. if (cpu->FpStack[ST(7)].Tag != TAG_EMPTY) {
  419. HandleStackFull(cpu, &cpu->FpStack[ST(7)]);
  420. return;
  421. }
  422. CPUASSERT(ST0->Tag < TAG_EMPTY); // EMPTY was already handled
  423. (*FSINCOSTable[ST0->Tag])(cpu);
  424. }
  425. NPXFUNC2(FYL2X_VALID_VALID)
  426. {
  427. if (l->r64 < 0.0) {
  428. // ST0 is negative - invalid operation
  429. if (!HandleInvalidOp(cpu)) {
  430. SetIndefinite(r);
  431. POPFLT;
  432. }
  433. return;
  434. }
  435. // r = r * log10(l->r64) / log10(2)
  436. //
  437. r->r64 *= Proxylog10(l->r64) / (0.301029995664);
  438. SetTag(r);
  439. POPFLT;
  440. }
  441. NPXFUNC2(FYL2X_VALID_ZERO)
  442. {
  443. if (l->r64 < 0.0) {
  444. // ST0 is negative - invalid operation
  445. if (!HandleInvalidOp(cpu)) {
  446. SetIndefinite(r);
  447. POPFLT;
  448. }
  449. return;
  450. }
  451. // r = r*log2(l), but r=0, so the answer is 0.
  452. r->r64 = 0;
  453. r->Tag = TAG_ZERO;
  454. POPFLT;
  455. }
  456. NPXFUNC2(FYL2X_ZERO_VALID)
  457. {
  458. // Divide-by-zero error
  459. cpu->FpStatusExceptions |= FPCONTROL_ZM;
  460. if (cpu->FpControlMask & FPCONTROL_ZM) {
  461. // Zero-divide exception is masked - return -INFINITY
  462. r->r64 = R8NegativeInfinity;
  463. r->Tag = TAG_SPECIAL;
  464. r->TagSpecial = TAG_SPECIAL_INFINITY;
  465. POPFLT;
  466. } else {
  467. cpu->FpStatusES = 1;
  468. }
  469. }
  470. NPXFUNC2(FYL2X_ZERO_ZERO)
  471. {
  472. if (!HandleInvalidOp(cpu)) {
  473. SetIndefinite(r);
  474. POPFLT;
  475. }
  476. }
  477. NPXFUNC2(FYL2X_SPECIAL_VALIDORZERO)
  478. {
  479. switch (l->TagSpecial) {
  480. case TAG_SPECIAL_DENORM:
  481. (*FYL2XTable[TAG_VALID][r->Tag])(cpu, l, r);
  482. break;
  483. case TAG_SPECIAL_INFINITY:
  484. if (r->Tag == TAG_ZERO || r->rb[7] & 0x80) {
  485. // 0*infinity, or anything*-infinity
  486. SetIndefinite(r);
  487. } else {
  488. // return -infinity
  489. r->rb[7] |= 0x80;
  490. }
  491. POPFLT;
  492. break;
  493. case TAG_SPECIAL_SNAN:
  494. if (HandleSnan(cpu, l)) {
  495. return;
  496. }
  497. // else fall into TAG_SPECIAL_QNAN
  498. case TAG_SPECIAL_QNAN:
  499. case TAG_SPECIAL_INDEF:
  500. // l is a NAN and r is VALID or ZERO - return the NAN
  501. r->r64 = l->r64;
  502. r->Tag = l->Tag;
  503. r->TagSpecial = r->TagSpecial;
  504. POPFLT;
  505. break;
  506. }
  507. }
  508. NPXFUNC2(FYL2X_VALIDORZERO_SPECIAL)
  509. {
  510. switch (r->TagSpecial) {
  511. case TAG_SPECIAL_DENORM:
  512. (*FYL2XTable[l->Tag][TAG_VALID])(cpu, l, r);
  513. break;
  514. case TAG_SPECIAL_INFINITY:
  515. // log(x)*infinity
  516. if (l->r64 > 1.0) {
  517. // return the original infinity - nothing to do
  518. } else if (l->r64 < 0.0 || l->r64 == 1.0) {
  519. if (HandleInvalidOp(cpu)) {
  520. return;
  521. }
  522. SetIndefinite(r);
  523. } else {
  524. // return infinity with sign flipped
  525. r->rb[7] ^= 0x80;
  526. }
  527. POPFLT;
  528. break;
  529. case TAG_SPECIAL_SNAN:
  530. if (HandleSnan(cpu, r)) {
  531. return;
  532. }
  533. // else fall into TAG_SPECIAL_QNAN
  534. case TAG_SPECIAL_QNAN:
  535. case TAG_SPECIAL_INDEF:
  536. // r is a NAN and l is VALID or ZERO - return the NAN
  537. POPFLT;
  538. break;
  539. }
  540. }
  541. NPXFUNC2(FYL2X_SPECIAL_SPECIAL)
  542. {
  543. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleStackEmpty(cpu, l)) {
  544. return;
  545. }
  546. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleStackEmpty(cpu, r)) {
  547. return;
  548. }
  549. if (l->TagSpecial == TAG_SPECIAL_DENORM) {
  550. (*FYL2XTable[TAG_VALID][r->Tag])(cpu, l, r);
  551. return;
  552. }
  553. if (r->TagSpecial == TAG_SPECIAL_DENORM) {
  554. (*FYL2XTable[l->Tag][TAG_VALID])(cpu, l, r);
  555. return;
  556. }
  557. if (l->Tag == TAG_SPECIAL_INFINITY) {
  558. if (r->Tag == TAG_SPECIAL_INFINITY) {
  559. // two infinities - return INDEFINITE
  560. SetIndefinite(r);
  561. } else {
  562. CPUASSERT(IS_TAG_NAN(r));
  563. // r already has the NAN to return
  564. }
  565. } else {
  566. CPUASSERT(IS_TAG_NAN(l));
  567. if (r->Tag == TAG_SPECIAL_INFINITY) {
  568. //
  569. // Return the NAN from l
  570. //
  571. r->r64 = l->r64;
  572. r->TagSpecial = l->TagSpecial;
  573. } else {
  574. //
  575. // Return the largest of the two NANs
  576. //
  577. r->r64 = l->r64 + r->r64;
  578. SetTag(r);
  579. }
  580. }
  581. POPFLT;
  582. }
  583. NPXFUNC2(FYL2X_ANY_EMPTY)
  584. {
  585. if (!HandleStackEmpty(cpu, r)) {
  586. (*FYL2XTable[l->Tag][TAG_SPECIAL])(cpu, l, r);
  587. }
  588. }
  589. NPXFUNC2(FYL2X_EMPTY_ANY)
  590. {
  591. if (!HandleStackEmpty(cpu, l)) {
  592. (*FYL2XTable[TAG_SPECIAL][r->Tag])(cpu, l, r);
  593. }
  594. }
  595. FRAG0(FYL2X)
  596. {
  597. PFPREG l, r;
  598. FpArithPreamble(cpu);
  599. l = cpu->FpST0;
  600. r = &cpu->FpStack[ST(1)];
  601. // In the functions, l == ST(0), r = ST(1)
  602. (*FYL2XTable[l->Tag][r->Tag])(cpu, l, r);
  603. }
  604. NPXFUNC2(FYL2XP1_VALIDORZERO_VALID)
  605. {
  606. if (l->r64 < -1.0) {
  607. if (!HandleInvalidOp(cpu)) {
  608. SetIndefinite(r);
  609. POPFLT;
  610. }
  611. return;
  612. } else if (l->r64 == -1.0) {
  613. // Divide-by-zero error
  614. cpu->FpStatusExceptions |= FPCONTROL_ZM;
  615. if (cpu->FpControlMask & FPCONTROL_ZM) {
  616. // Zero-divide exception is masked - return -INFINITY
  617. r->r64 = R8NegativeInfinity;
  618. r->Tag = TAG_SPECIAL;
  619. r->TagSpecial = TAG_SPECIAL_INFINITY;
  620. POPFLT;
  621. } else {
  622. cpu->FpStatusES = 1;
  623. }
  624. return;
  625. }
  626. // r = r * log10(l+1) / log10(2)
  627. //
  628. r->r64 *= Proxylog10(l->r64 + 1.0) / (0.301029995664);
  629. SetTag(r);
  630. POPFLT;
  631. }
  632. NPXFUNC2(FYL2XP1_VALIDORZERO_ZERO)
  633. {
  634. if (l->r64 < -1.0) {
  635. if (!HandleInvalidOp(cpu)) {
  636. SetIndefinite(r);
  637. POPFLT;
  638. }
  639. return;
  640. }
  641. // r = r*log2(l), but r=0, so the answer is 0.
  642. r->r64 = 0;
  643. r->Tag = TAG_ZERO;
  644. POPFLT;
  645. }
  646. NPXFUNC2(FYL2XP1_SPECIAL_VALIDORZERO)
  647. {
  648. switch (l->TagSpecial) {
  649. case TAG_SPECIAL_DENORM:
  650. (*FYL2XP1Table[TAG_VALID][r->Tag])(cpu, l, r);
  651. break;
  652. case TAG_SPECIAL_INFINITY:
  653. if (r->Tag == TAG_ZERO || r->rb[7] & 0x80) {
  654. if (HandleInvalidOp(cpu)) {
  655. return;
  656. }
  657. // 0*infinity, or anything*-infinity
  658. SetIndefinite(r);
  659. } else {
  660. // return -infinity
  661. r->rb[7] |= 0x80;
  662. }
  663. POPFLT;
  664. break;
  665. case TAG_SPECIAL_SNAN:
  666. if (HandleSnan(cpu, l)) {
  667. return;
  668. }
  669. // else fall into TAG_SPECIAL_QNAN
  670. case TAG_SPECIAL_QNAN:
  671. case TAG_SPECIAL_INDEF:
  672. // l is a NAN and r is VALID or ZERO - return the NAN
  673. r->r64 = l->r64;
  674. r->Tag = l->Tag;
  675. r->TagSpecial = r->TagSpecial;
  676. POPFLT;
  677. break;
  678. }
  679. }
  680. NPXFUNC2(FYL2XP1_VALIDORZERO_SPECIAL)
  681. {
  682. switch (r->TagSpecial) {
  683. case TAG_SPECIAL_DENORM:
  684. (*FYL2XP1Table[l->Tag][TAG_VALID])(cpu, l, r);
  685. break;
  686. case TAG_SPECIAL_INFINITY:
  687. // log(x)*infinity
  688. if (l->r64 > 1.0) {
  689. // return the original infinity - nothing to do
  690. } else if (l->r64 < 0.0 || l->r64 == 1.0) {
  691. if (HandleInvalidOp(cpu)) {
  692. return;
  693. }
  694. SetIndefinite(r);
  695. } else {
  696. // return infinity with sign flipped
  697. r->rb[7] ^= 0x80;
  698. }
  699. POPFLT;
  700. break;
  701. case TAG_SPECIAL_SNAN:
  702. if (HandleSnan(cpu, r)) {
  703. return;
  704. }
  705. // else fall into TAG_SPECIAL_QNAN
  706. case TAG_SPECIAL_QNAN:
  707. case TAG_SPECIAL_INDEF:
  708. // r is a NAN and l is VALID or ZERO - return the NAN
  709. POPFLT;
  710. break;
  711. }
  712. }
  713. NPXFUNC2(FYL2XP1_SPECIAL_SPECIAL)
  714. {
  715. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleStackEmpty(cpu, l)) {
  716. return;
  717. }
  718. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleStackEmpty(cpu, r)) {
  719. return;
  720. }
  721. if (l->TagSpecial == TAG_SPECIAL_DENORM) {
  722. (*FYL2XP1Table[TAG_VALID][r->Tag])(cpu, l, r);
  723. return;
  724. }
  725. if (r->TagSpecial == TAG_SPECIAL_DENORM) {
  726. (*FYL2XP1Table[l->Tag][TAG_VALID])(cpu, l, r);
  727. return;
  728. }
  729. if (l->Tag == TAG_SPECIAL_INFINITY) {
  730. if (r->Tag == TAG_SPECIAL_INFINITY) {
  731. if (l->rb[7] & 0x80) {
  732. // l is negative infinity. Invalid op
  733. if (HandleInvalidOp(cpu)) {
  734. return;
  735. }
  736. SetIndefinite(r);
  737. }
  738. } else {
  739. CPUASSERT(IS_TAG_NAN(r));
  740. // r already has the NAN to return
  741. }
  742. } else {
  743. CPUASSERT(IS_TAG_NAN(l));
  744. if (r->Tag == TAG_SPECIAL_INFINITY) {
  745. //
  746. // Return the NAN from l
  747. //
  748. r->r64 = l->r64;
  749. r->TagSpecial = l->TagSpecial;
  750. } else {
  751. //
  752. // Return the largest of the two NANs
  753. //
  754. r->r64 = l->r64 + r->r64;
  755. SetTag(r);
  756. }
  757. }
  758. POPFLT;
  759. }
  760. NPXFUNC2(FYL2XP1_ANY_EMPTY)
  761. {
  762. if (!HandleStackEmpty(cpu, r)) {
  763. (*FYL2XP1Table[l->Tag][TAG_SPECIAL])(cpu, l, r);
  764. }
  765. }
  766. NPXFUNC2(FYL2XP1_EMPTY_ANY)
  767. {
  768. if (!HandleStackEmpty(cpu, l)) {
  769. (*FYL2XP1Table[TAG_SPECIAL][r->Tag])(cpu, l, r);
  770. }
  771. }
  772. FRAG0(FYL2XP1)
  773. {
  774. PFPREG l, r;
  775. FpArithPreamble(cpu);
  776. l = cpu->FpST0;
  777. r = &cpu->FpStack[ST(1)];
  778. // In the functions, l == ST(0), r = ST(1)
  779. (*FYL2XP1Table[l->Tag][r->Tag])(cpu, l, r);
  780. }
  781. NPXFUNC1(F2XM1_VALID)
  782. {
  783. Fp->r64 = pow(2.0, Fp->r64) - 1.0;
  784. SetTag(Fp);
  785. }
  786. NPXFUNC1(F2XM1_ZERO)
  787. {
  788. // nothing to do - return the same zero
  789. }
  790. NPXFUNC1(F2XM1_SPECIAL)
  791. {
  792. switch (Fp->TagSpecial) {
  793. case TAG_SPECIAL_DENORM:
  794. F2XM1_VALID(cpu, Fp);
  795. break;
  796. case TAG_SPECIAL_INFINITY:
  797. if (Fp->rb[7] & 0x80) {
  798. // -infinity - return 1
  799. Fp->r64 = 1.0;
  800. Fp->Tag = TAG_VALID;
  801. }
  802. // else +infinity - return +infinity
  803. break;
  804. case TAG_SPECIAL_SNAN:
  805. HandleSnan(cpu, Fp);
  806. // fall into TAG_SPECIAL_QNAN
  807. case TAG_SPECIAL_QNAN:
  808. case TAG_SPECIAL_INDEF:
  809. // return the NAN
  810. break;
  811. }
  812. }
  813. NPXFUNC1(F2XM1_EMPTY)
  814. {
  815. HandleStackEmpty(cpu, Fp);
  816. }
  817. FRAG0(F2XM1)
  818. {
  819. PFPREG ST0;
  820. FpArithPreamble(cpu);
  821. ST0 = cpu->FpST0;
  822. (*F2XM1Table[ST0->Tag])(cpu, ST0);
  823. }