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.

563 lines
14 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. fpuload.c
  5. Abstract:
  6. Floating point load functions
  7. Author:
  8. 04-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. #include "fpuarith.h"
  23. ASSERTNAME;
  24. VOID GetIntelR4(
  25. PFPREG Fp,
  26. FLOAT *pIntelReal
  27. )
  28. /*++
  29. Routine Description:
  30. Load an Intel R4 and convert it to a native R4, accounting for
  31. the difference in how MIPS represents QNAN/SNAN.
  32. NOTE: This is not in fpufrag.c due to a code-generator bug on PPC -
  33. irbexpr.c:932 asserts trying to inline this function. Moving it
  34. to a different file defeats the inliner.
  35. Arguments:
  36. Fp - floating-point register to load the R4 into
  37. pIntelReal - R4 value to load (in Intel format)
  38. Return Value:
  39. None.
  40. --*/
  41. {
  42. DWORD d = GET_LONG(pIntelReal);
  43. if ((d & 0x7f800000) == 0x7f800000) {
  44. Fp->Tag = TAG_SPECIAL;
  45. // Found some sort of NAN
  46. if (d == 0xffc00000) { // Indefinite
  47. // Create the native indefinite form
  48. #if NATIVE_NAN_IS_INTEL_FORMAT
  49. Fp->rdw[0] = 0;
  50. Fp->rdw[1] = 0xfff80000;
  51. #else
  52. Fp->rdw[0] = 0xffffffff;
  53. Fp->rdw[1] = 0x7ff7ffff;
  54. #endif
  55. Fp->TagSpecial = TAG_SPECIAL_INDEF;
  56. } else if (d == 0x7f800000) { // +infinity
  57. Fp->r64 = R8PositiveInfinity;
  58. Fp->TagSpecial = TAG_SPECIAL_INFINITY;
  59. } else if (d == 0xff800000) { // -infinity
  60. Fp->r64 = R8NegativeInfinity;
  61. Fp->TagSpecial = TAG_SPECIAL_INFINITY;
  62. } else { // SNAN/QNAN
  63. DWORD Sign;
  64. if (d & 0x00400000) {
  65. //
  66. // Intel QNAN
  67. //
  68. Fp->TagSpecial = TAG_SPECIAL_QNAN;
  69. } else {
  70. //
  71. // Intel SNAN
  72. //
  73. Fp->TagSpecial = TAG_SPECIAL_SNAN;
  74. }
  75. #if !NATIVE_NAN_IS_INTEL_FORMAT
  76. //
  77. // Toggle the NAN to native format
  78. //
  79. d ^= 0x00400000;
  80. #endif
  81. //
  82. // Cast the r4 RISC QNAN to double. Don't trust the CRT to
  83. // do the right thing - MIPS converts them both to INDEFINITE.
  84. //
  85. Sign = d & 0x80000000;
  86. d &= 0x007fffff; // grab the mantissa from the r4 (23 bits)
  87. Fp->rdw[1] = Sign | 0x7ff00000 | (d >> 3); // store 20 bits of mantissa, plus sign
  88. Fp->rdw[0] = d << 25; // store 3 bits of mantissa
  89. }
  90. } else { // denormal, zero, or number
  91. // Coerce it to an R8
  92. Fp->r64 = (DOUBLE)*(FLOAT *)&d;
  93. // Compute its tag by looking at the value *after* the conversion,
  94. // as the native FPU may have normalized the value
  95. if (Fp->r64 == 0.0) {
  96. Fp->Tag = TAG_ZERO;
  97. } else if ((Fp->rdw[1] & 0x7ff00000) == 0) {
  98. // Exponent is 0 - R8 denormal
  99. Fp->Tag = TAG_SPECIAL;
  100. Fp->TagSpecial = TAG_SPECIAL_DENORM;
  101. } else {
  102. Fp->Tag = TAG_VALID;
  103. #if DBG
  104. SetTag(Fp);
  105. CPUASSERT(Fp->Tag == TAG_VALID);
  106. #endif
  107. }
  108. }
  109. }
  110. #if !NATIVE_NAN_IS_INTEL_FORMAT
  111. VOID GetIntelR8(
  112. PFPREG Fp,
  113. DOUBLE *pIntelReal
  114. )
  115. /*++
  116. Routine Description:
  117. Load an Intel R8 and convert it to a native R8, accounting for
  118. the difference in how MIPS represents QNAN/SNAN.
  119. Arguments:
  120. Fp - floating-point register to load the R8 into
  121. pIntelReal - R8 value to load (in Intel format)
  122. Return Value:
  123. None.
  124. --*/
  125. {
  126. //
  127. // Copy the R8 into the FP register
  128. //
  129. Fp->r64 = *(UNALIGNED DOUBLE *)pIntelReal;
  130. //
  131. // Compute its tag
  132. //
  133. SetTag(Fp);
  134. //
  135. // If the value is QNAN/SNAN/INDEF, convert it to native format
  136. //
  137. if (IS_TAG_NAN(Fp)) {
  138. if (Fp->rdw[0] == 0 && Fp->rdw[1] == 0xfff80000) {
  139. // indefinite - make the R8 into a native indefinite
  140. Fp->TagSpecial = TAG_SPECIAL_INDEF;
  141. Fp->rdw[0] = 0xffffffff;
  142. Fp->rdw[1] = 0x7ff7ffff;
  143. } else {
  144. if (Fp->rdw[1] & 0x00080000) {
  145. // top bit of mantissa is set - QNAN
  146. Fp->TagSpecial = TAG_SPECIAL_QNAN;
  147. } else {
  148. // top bit of mantissa clear - SNAN
  149. Fp->TagSpecial = TAG_SPECIAL_SNAN;
  150. }
  151. Fp->rdw[1] ^= 0x00080000; // invert the top bit of the mantissa
  152. }
  153. }
  154. }
  155. #endif //!NATIVE_NAN_IS_INTEL_FORMAT
  156. VOID
  157. SetTag(
  158. PFPREG FpReg
  159. )
  160. /*++
  161. Routine Description:
  162. Sets the Tag value corresponding to a r64 value in an FP register.
  163. Assumes the R8 value is in native format (ie. Intel NANs are already
  164. converted to native NANs).
  165. Arguments:
  166. FpReg - register to set Tag field in.
  167. Return Value:
  168. None
  169. --*/
  170. {
  171. DWORD Exponent;
  172. /* On average, the value will be zero or a valid real, so those cases
  173. * have the fastest code paths. NANs tend to be less frequent and are
  174. * slower to calculate.
  175. */
  176. Exponent = FpReg->rdw[1] & 0x7ff00000;
  177. if (Exponent == 0x7ff00000) {
  178. // exponent is all 1's - NAN of some sort
  179. FpReg->Tag = TAG_SPECIAL;
  180. if (FpReg->rdw[0] == 0 && (FpReg->rdw[1] & 0x7fffffff) == 0x7ff00000) {
  181. // Exponent is all 1s, mantissa is all 0s - Infinity
  182. FpReg->TagSpecial = TAG_SPECIAL_INFINITY;
  183. } else {
  184. #if NATIVE_NAN_IS_INTEL_FORMAT
  185. if (FpReg->rdw[0] == 0 && FpReg->rdw[1] == 0xfff80000) {
  186. // indefinite
  187. FpReg->TagSpecial = TAG_SPECIAL_INDEF;
  188. } else if (FpReg->rdw[1] & 0x00080000) {
  189. // top bit of mantissa is set - QNAN
  190. FpReg->TagSpecial = TAG_SPECIAL_QNAN;
  191. } else {
  192. // Top bit of mantissa clear - but some mantissa bit set - QNAN
  193. FpReg->TagSpecial = TAG_SPECIAL_SNAN;
  194. }
  195. #else //!NATIVE_NAN_IS_INTEL_FORMAT
  196. if (FpReg->rdw[0] == 0xffffffff && FpReg->rdw[1] == 0x7ff7ffff) {
  197. // indefinite
  198. FpReg->TagSpecial = TAG_SPECIAL_INDEF;
  199. } else if (FpReg->rdw[1] & 0x00080000) {
  200. // top bit of mantissa is set - SNAN
  201. FpReg->TagSpecial = TAG_SPECIAL_SNAN;
  202. } else {
  203. // top bit of mantissa clear - QNAN
  204. FpReg->TagSpecial = TAG_SPECIAL_QNAN;
  205. }
  206. #endif //!NATIVE_NAN_IS_INTEL_FORMAT
  207. }
  208. } else if (Exponent == 0) {
  209. // exponent is 0 - DENORMAL or ZERO
  210. if ((FpReg->rdw[1] & 0x1ffff) == 0 && FpReg->rdw[0] == 0) {
  211. // mantissa is all zeroes - ZERO
  212. FpReg->Tag = TAG_ZERO;
  213. } else {
  214. FpReg->Tag = TAG_SPECIAL;
  215. FpReg->TagSpecial = TAG_SPECIAL_DENORM;
  216. }
  217. } else {
  218. // Exponent is not all 1's and not all 0's - a VALID
  219. FpReg->Tag = TAG_VALID;
  220. }
  221. }
  222. FRAG1(FILD16, SHORT) // FILD m16int
  223. {
  224. PFPREG ST0;
  225. FpArithDataPreamble(cpu, pop1);
  226. cpu->FpStatusC1 = 0; // assume no error
  227. PUSHFLT(ST0);
  228. if (ST0->Tag != TAG_EMPTY) {
  229. HandleStackFull(cpu, ST0);
  230. } else {
  231. SHORT s;
  232. s = (SHORT)GET_SHORT(pop1);
  233. ST0->r64 = (DOUBLE)s;
  234. if (s) {
  235. ST0->Tag = TAG_VALID;
  236. } else {
  237. ST0->Tag = TAG_ZERO;
  238. }
  239. }
  240. }
  241. FRAG1(FILD32, LONG) // FILD m32int
  242. {
  243. PFPREG ST0;
  244. FpArithDataPreamble(cpu, pop1);
  245. cpu->FpStatusC1 = 0; // assume no error
  246. PUSHFLT(ST0);
  247. if (ST0->Tag != TAG_EMPTY) {
  248. HandleStackFull(cpu, ST0);
  249. } else {
  250. LONG l;
  251. l = (LONG)GET_LONG(pop1);
  252. ST0->r64 = (DOUBLE)l;
  253. if (l) {
  254. ST0->Tag = TAG_VALID;
  255. } else {
  256. ST0->Tag = TAG_ZERO;
  257. }
  258. }
  259. }
  260. FRAG1(FILD64, LONGLONG) // FILD m64int
  261. {
  262. PFPREG ST0;
  263. FpArithDataPreamble(cpu, pop1);
  264. cpu->FpStatusC1 = 0; // assume no error
  265. PUSHFLT(ST0);
  266. if (ST0->Tag != TAG_EMPTY) {
  267. HandleStackFull(cpu, ST0);
  268. } else {
  269. LONGLONG ll;
  270. ll = *(UNALIGNED LONGLONG *)pop1;
  271. ST0->r64 = (DOUBLE)ll;
  272. if (ll) {
  273. ST0->Tag = TAG_VALID;
  274. } else {
  275. ST0->Tag = TAG_ZERO;
  276. }
  277. }
  278. }
  279. FRAG1(FLD32, FLOAT) // FLD m32real
  280. {
  281. PFPREG ST0;
  282. FpArithDataPreamble(cpu, pop1);
  283. cpu->FpStatusC1 = 0; // assume no error
  284. PUSHFLT(ST0);
  285. if (ST0->Tag != TAG_EMPTY) {
  286. HandleStackFull(cpu, ST0);
  287. } else {
  288. GetIntelR4(ST0, pop1);
  289. if (ST0->Tag == TAG_SPECIAL) {
  290. if (ST0->TagSpecial == TAG_SPECIAL_DENORM) {
  291. if (!(cpu->FpControlMask & FPCONTROL_DM)) {
  292. cpu->FpStatusES = 1; // Unmasked exception
  293. //
  294. // Instruction needs to be aborted due to unmasked
  295. // exception. We've already hosed ST0, so "correct"
  296. // it by popping the FP stack. Note that
  297. // the contents of the register have been lost, which
  298. // is a compatibility break with Intel.
  299. //
  300. POPFLT;
  301. }
  302. cpu->FpStatusExceptions |= FPCONTROL_DM;
  303. } else if (ST0->TagSpecial == TAG_SPECIAL_SNAN) {
  304. if (HandleSnan(cpu, ST0)) {
  305. //
  306. // Instruction needs to be aborted due to unmasked
  307. // exception. We've already hosed ST0, so "correct"
  308. // it by popping the FP stack. Note that
  309. // the contents of the register have been lost, which
  310. // is a compatibility break with Intel.
  311. //
  312. POPFLT;
  313. }
  314. }
  315. }
  316. }
  317. }
  318. FRAG1(FLD64, DOUBLE) // FLD m64real
  319. {
  320. PFPREG ST0;
  321. FpArithDataPreamble(cpu, pop1);
  322. cpu->FpStatusC1 = 0; // assume no error
  323. PUSHFLT(ST0);
  324. if (ST0->Tag != TAG_EMPTY) {
  325. HandleStackFull(cpu, ST0);
  326. } else {
  327. GetIntelR8(ST0, pop1);
  328. if (ST0->Tag == TAG_SPECIAL) {
  329. if (ST0->TagSpecial == TAG_SPECIAL_DENORM) {
  330. if (!(cpu->FpControlMask & FPCONTROL_DM)) {
  331. cpu->FpStatusES = 1; // Unmasked exception
  332. //
  333. // Instruction needs to be aborted due to unmasked
  334. // exception. We've already hosed ST0, so "correct"
  335. // it by popping the FP stack. Note that
  336. // the contents of the register have been lost, which
  337. // is a compatibility break with Intel.
  338. //
  339. POPFLT;
  340. }
  341. cpu->FpStatusExceptions |= FPCONTROL_DM;
  342. } else if (ST0->TagSpecial == TAG_SPECIAL_SNAN) {
  343. if (HandleSnan(cpu, ST0)) {
  344. //
  345. // Instruction needs to be aborted due to unmasked
  346. // exception. We've already hosed ST0, so "correct"
  347. // it by popping the FP stack. Note that
  348. // the contents of the register have been lost, which
  349. // is a compatibility break with Intel.
  350. //
  351. POPFLT;
  352. }
  353. }
  354. }
  355. }
  356. }
  357. FRAG0(FLD1)
  358. {
  359. PFPREG ST0;
  360. FpArithPreamble(cpu);
  361. cpu->FpStatusC1 = 0; // assume no error
  362. PUSHFLT(ST0);
  363. if (ST0->Tag != TAG_EMPTY) {
  364. HandleStackFull(cpu, ST0);
  365. } else {
  366. ST0->r64 = 1.0;
  367. ST0->Tag = TAG_VALID;
  368. }
  369. }
  370. FRAG0(FLDL2T)
  371. {
  372. PFPREG ST0;
  373. FpArithPreamble(cpu);
  374. cpu->FpStatusC1 = 0; // assume no error
  375. PUSHFLT(ST0);
  376. if (ST0->Tag != TAG_EMPTY) {
  377. HandleStackFull(cpu, ST0);
  378. } else {
  379. ST0->r64 = 2.3025850929940456840E0 / 6.9314718055994530942E-1; //log2(10) = ln10/ln2
  380. ST0->Tag = TAG_VALID;
  381. }
  382. }
  383. FRAG0(FLDL2E)
  384. {
  385. PFPREG ST0;
  386. FpArithPreamble(cpu);
  387. cpu->FpStatusC1 = 0; // assume no error
  388. PUSHFLT(ST0);
  389. if (ST0->Tag != TAG_EMPTY) {
  390. HandleStackFull(cpu, ST0);
  391. } else {
  392. ST0->r64 = 1.4426950408889634074E0;
  393. ST0->Tag = TAG_VALID;
  394. }
  395. }
  396. FRAG0(FLDPI)
  397. {
  398. PFPREG ST0;
  399. FpArithPreamble(cpu);
  400. cpu->FpStatusC1 = 0; // assume no error
  401. PUSHFLT(ST0);
  402. if (ST0->Tag != TAG_EMPTY) {
  403. HandleStackFull(cpu, ST0);
  404. } else {
  405. ST0->r64 = 3.14159265358979323846;
  406. ST0->Tag = TAG_VALID;
  407. }
  408. }
  409. FRAG0(FLDLG2)
  410. {
  411. PFPREG ST0;
  412. FpArithPreamble(cpu);
  413. cpu->FpStatusC1 = 0; // assume no error
  414. PUSHFLT(ST0);
  415. if (ST0->Tag != TAG_EMPTY) {
  416. HandleStackFull(cpu, ST0);
  417. } else {
  418. ST0->r64 = 6.9314718055994530942E-1 / 2.3025850929940456840E0;
  419. ST0->Tag = TAG_VALID;
  420. }
  421. }
  422. FRAG0(FLDLN2)
  423. {
  424. PFPREG ST0;
  425. FpArithPreamble(cpu);
  426. cpu->FpStatusC1 = 0; // assume no error
  427. PUSHFLT(ST0);
  428. if (ST0->Tag != TAG_EMPTY) {
  429. HandleStackFull(cpu, ST0);
  430. } else {
  431. ST0->r64 = 6.9314718055994530942E-1;
  432. ST0->Tag = TAG_VALID;
  433. }
  434. }
  435. FRAG1IMM(FLD_STi, INT)
  436. {
  437. PFPREG ST0;
  438. PFPREG STi;
  439. FpArithPreamble(cpu);
  440. cpu->FpStatusC1 = 0; // assume no error
  441. STi = &cpu->FpStack[ST(op1)];
  442. PUSHFLT(ST0);
  443. if (ST0->Tag != TAG_EMPTY) {
  444. HandleStackFull(cpu, ST0);
  445. } else {
  446. ST0->r64 = STi->r64;
  447. ST0->Tag = STi->Tag;
  448. ST0->TagSpecial = STi->TagSpecial;
  449. }
  450. }
  451. FRAG0(FLDZ)
  452. {
  453. PFPREG ST0;
  454. FpArithPreamble(cpu);
  455. cpu->FpStatusC1 = 0; // assume no error
  456. PUSHFLT(ST0);
  457. if (ST0->Tag != TAG_EMPTY) {
  458. HandleStackFull(cpu, ST0);
  459. } else {
  460. ST0->r64 = 0.0;
  461. ST0->Tag = TAG_ZERO;
  462. }
  463. }