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.

589 lines
14 KiB

  1. /*++
  2. Copyright (c) 1995-1998 Microsoft Corporation
  3. Module Name:
  4. fpustore.c
  5. Abstract:
  6. Floating point store 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. //
  25. // Forward declarations
  26. //
  27. __int64 CastDoubleToInt64(double d); // in alpha\fphelp.s
  28. #if !NATIVE_NAN_IS_INTEL_FORMAT
  29. //
  30. // Forward declarations
  31. //
  32. NPXPUTINTELR4(PutIntelR4_VALID);
  33. NPXPUTINTELR4(PutIntelR4_ZERO);
  34. NPXPUTINTELR4(PutIntelR4_SPECIAL);
  35. NPXPUTINTELR4(PutIntelR4_EMPTY);
  36. NPXPUTINTELR8(PutIntelR8_VALID);
  37. NPXPUTINTELR8(PutIntelR8_ZERO);
  38. NPXPUTINTELR8(PutIntelR8_SPECIAL);
  39. NPXPUTINTELR8(PutIntelR8_EMPTY);
  40. //
  41. // Jump tables
  42. //
  43. const NpxPutIntelR4 PutIntelR4Table[TAG_MAX] = {
  44. PutIntelR4_VALID,
  45. PutIntelR4_ZERO,
  46. PutIntelR4_SPECIAL,
  47. PutIntelR4_EMPTY
  48. };
  49. const NpxPutIntelR8 PutIntelR8Table[TAG_MAX] = {
  50. PutIntelR8_VALID,
  51. PutIntelR8_ZERO,
  52. PutIntelR8_SPECIAL,
  53. PutIntelR8_EMPTY
  54. };
  55. NPXPUTINTELR4(PutIntelR4_VALID)
  56. {
  57. FLOAT f = (FLOAT)Fp->r64;
  58. PUT_LONG(pIntelReal, *(DWORD *)&f);
  59. }
  60. NPXPUTINTELR4(PutIntelR4_ZERO)
  61. {
  62. //
  63. // This cannot simply write a constant 0.0 to memory as it must
  64. // copy the correct sign from the 0.0 in the FP register.
  65. //
  66. PUT_LONG(pIntelReal, Fp->rdw[1]);
  67. }
  68. NPXPUTINTELR4(PutIntelR4_SPECIAL)
  69. {
  70. switch (Fp->TagSpecial) {
  71. default:
  72. CPUASSERT(FALSE); // unknown tag - fall into TAG_INDEF
  73. case TAG_SPECIAL_INFINITY:
  74. case TAG_SPECIAL_DENORM:
  75. PutIntelR4_VALID(pIntelReal, Fp);
  76. break;
  77. case TAG_SPECIAL_INDEF:
  78. // Write out the R4 indefinite bit pattern
  79. PUT_LONG(pIntelReal, 0xffc00000);
  80. break;
  81. case TAG_SPECIAL_QNAN:
  82. case TAG_SPECIAL_SNAN: {
  83. DWORD d[2];
  84. FLOAT f;
  85. //
  86. // Truncate the R8 to an R4, and toggle the top bit of the mantissa
  87. // to form an Intel QNAN/SNAN (which is different than a native
  88. // QNAN/SNAN).
  89. //
  90. d[0] = Fp->rdw[0];
  91. d[1] = Fp->rdw[1] ^ 0x00400000;
  92. f = *(FLOAT *)d;
  93. PUT_LONG(pIntelReal, *(DWORD *)&f);
  94. }
  95. break;
  96. }
  97. }
  98. NPXPUTINTELR4(PutIntelR4_EMPTY)
  99. {
  100. //
  101. // It is assumed that callers of PutIntelR4() have already handled
  102. // TAG_EMPTY by raising an exception or converting it to TAG_INDEF.
  103. //
  104. CPUASSERT(FALSE);
  105. }
  106. NPXPUTINTELR8(PutIntelR8_VALID)
  107. {
  108. *(UNALIGNED DOUBLE *)pIntelReal = Fp->r64;
  109. }
  110. NPXPUTINTELR8(PutIntelR8_ZERO)
  111. {
  112. //
  113. // This cannot simply write a constant 0.0 to memory as it must
  114. // copy the correct sign from the 0.0 in the FP register.
  115. //
  116. *(UNALIGNED DOUBLE *)pIntelReal = Fp->r64;
  117. }
  118. NPXPUTINTELR8(PutIntelR8_SPECIAL)
  119. {
  120. DWORD *pdw = (DWORD *)pIntelReal;
  121. switch (Fp->TagSpecial) {
  122. default:
  123. CPUASSERT(FALSE); // unknown tag - fall into TAG_INDEF
  124. case TAG_SPECIAL_DENORM:
  125. case TAG_SPECIAL_INFINITY:
  126. // Both can be done as a simple R8-toR8 copy
  127. PutIntelR8_VALID(pIntelReal, Fp);
  128. break;
  129. case TAG_SPECIAL_INDEF:
  130. // Write out an Intel Indefinite
  131. PUT_LONG(pdw, 0);
  132. PUT_LONG((pdw+1), 0xfff80000);
  133. break;
  134. case TAG_SPECIAL_QNAN:
  135. case TAG_SPECIAL_SNAN:
  136. //
  137. // Toggle the top bit of the mantissa to form an Intel QNAN/SNAN
  138. // (which is different than a native QNAN/SNAN).
  139. //
  140. PUT_LONG(pdw, Fp->rdw[0]);
  141. PUT_LONG((pdw+1), Fp->rdw[1] ^ 0x00080000);
  142. break;
  143. }
  144. }
  145. NPXPUTINTELR8(PutIntelR8_EMPTY)
  146. {
  147. //
  148. // It is assumed that callers of PutIntelR8() have already handled
  149. // TAG_EMPTY by raising an exception or converting it to TAG_INDEF.
  150. //
  151. CPUASSERT(FALSE);
  152. }
  153. #endif //!NATIVE_NAN_IS_INTEL_FORMAT
  154. FRAG1(FIST16, SHORT) // FIST m16int
  155. {
  156. PFPREG ST0 = cpu->FpST0;
  157. __int64 i64;
  158. int Exponent;
  159. SHORT i16;
  160. FpArithDataPreamble(cpu, pop1);
  161. switch (ST0->Tag) {
  162. case TAG_VALID:
  163. Exponent = (int)((ST0->rdw[1] >> 20) & 0x7ff) - 1023;
  164. //
  165. if (Exponent >= 64) {
  166. //
  167. // Exponent is too big - this cannot be converted to an __int64
  168. // Raise I exception on overflow, or write 0x8000 for masked
  169. // exception.
  170. //
  171. IntOverflow:
  172. if (HandleInvalidOp(cpu)) {
  173. return;
  174. }
  175. PUT_SHORT(pop1, 0x8000);
  176. } else {
  177. i64 = CastDoubleToInt64(ST0->r64);
  178. i16 = (SHORT)i64;
  179. if ((__int64)i16 != i64) {
  180. goto IntOverflow;
  181. }
  182. PUT_SHORT(pop1, i16);
  183. }
  184. break;
  185. case TAG_ZERO:
  186. PUT_SHORT(pop1, 0);
  187. break;
  188. case TAG_SPECIAL:
  189. if (ST0->TagSpecial == TAG_SPECIAL_DENORM) {
  190. i64 = CastDoubleToInt64(ST0->r64);
  191. PUT_SHORT(pop1, (SHORT)i64);
  192. } else if (!HandleInvalidOp(cpu)) {
  193. // INFINITY and NANs are all invalid operations, and the masked
  194. // behavior is to write 0x8000
  195. PUT_SHORT(pop1, 0x8000);
  196. }
  197. break;
  198. case TAG_EMPTY:
  199. if (!HandleStackEmpty(cpu, ST0)) {
  200. PUT_SHORT(pop1, 0x8000);
  201. }
  202. break;
  203. }
  204. }
  205. FRAG1(FISTP16, SHORT) // FISTP m16int
  206. {
  207. PFPREG ST0 = cpu->FpST0;
  208. __int64 i64;
  209. int Exponent;
  210. SHORT i16;
  211. FpArithDataPreamble(cpu, pop1);
  212. switch (ST0->Tag) {
  213. case TAG_VALID:
  214. Exponent = (int)((ST0->rdw[1] >> 20) & 0x7ff) - 1023;
  215. if (Exponent >= 64) {
  216. //
  217. // Exponent is too big - this cannot be converted to an __int64
  218. // Raise I exception on overflow, or write 0x8000 for masked
  219. // exception.
  220. //
  221. IntOverflow:
  222. if (HandleInvalidOp(cpu)) {
  223. return;
  224. }
  225. PUT_SHORT(pop1, 0x8000);
  226. } else {
  227. i64 = CastDoubleToInt64(ST0->r64);
  228. i16 = (SHORT)i64;
  229. if ((__int64)i16 != i64) {
  230. goto IntOverflow;
  231. }
  232. PUT_SHORT(pop1, i16);
  233. }
  234. POPFLT;
  235. break;
  236. case TAG_ZERO:
  237. PUT_SHORT(pop1, 0);
  238. break;
  239. case TAG_SPECIAL:
  240. if (ST0->TagSpecial == TAG_SPECIAL_DENORM) {
  241. i64 = CastDoubleToInt64(ST0->r64);
  242. PUT_SHORT(pop1, (SHORT)i64);
  243. } else if (!HandleInvalidOp(cpu)) {
  244. // INFINITY and NANs are all invalid operations, and the masked
  245. // behavior is to write 0x8000
  246. PUT_SHORT(pop1, 0x8000);
  247. }
  248. POPFLT;
  249. break;
  250. case TAG_EMPTY:
  251. if (!HandleStackEmpty(cpu, ST0)) {
  252. PUT_SHORT(pop1, 0x8000);
  253. POPFLT;
  254. }
  255. break;
  256. }
  257. }
  258. FRAG1(FIST32, LONG) // FIST m32int
  259. {
  260. PFPREG ST0 = cpu->FpST0;
  261. __int64 i64;
  262. int Exponent;
  263. LONG i32;
  264. FpArithDataPreamble(cpu, pop1);
  265. switch (ST0->Tag) {
  266. case TAG_VALID:
  267. Exponent = (int)((ST0->rdw[1] >> 20) & 0x7ff) - 1023;
  268. if (Exponent >= 64) {
  269. //
  270. // Exponent is too big - this cannot be converted to an __int64
  271. // Raise I exception on overflow, or write 0x80000000 for masked
  272. // exception.
  273. //
  274. IntOverflow:
  275. if (HandleInvalidOp(cpu)) {
  276. return;
  277. }
  278. PUT_LONG(pop1, 0x80000000);
  279. } else {
  280. i64 = CastDoubleToInt64(ST0->r64);
  281. i32 = (LONG)i64;
  282. if ((__int64)i32 != i64) {
  283. goto IntOverflow;
  284. }
  285. PUT_LONG(pop1, i32);
  286. }
  287. break;
  288. case TAG_ZERO:
  289. PUT_LONG(pop1, 0);
  290. break;
  291. case TAG_SPECIAL:
  292. if (ST0->TagSpecial == TAG_SPECIAL_DENORM) {
  293. i64 = CastDoubleToInt64(ST0->r64);
  294. PUT_LONG(pop1, (LONG)i64);
  295. } else if (!HandleInvalidOp(cpu)) {
  296. // INFINITY and NANs are all invalid operations, and the masked
  297. // behavior is to write 0x80000000
  298. PUT_LONG(pop1, 0x80000000);
  299. }
  300. break;
  301. case TAG_EMPTY:
  302. if (!HandleStackEmpty(cpu, ST0)) {
  303. PUT_LONG(pop1, 0x80000000);
  304. POPFLT;
  305. }
  306. break;
  307. }
  308. }
  309. FRAG1(FISTP32, LONG) // FISTP m32int
  310. {
  311. PFPREG ST0 = cpu->FpST0;
  312. __int64 i64;
  313. int Exponent;
  314. LONG i32;
  315. FpArithDataPreamble(cpu, pop1);
  316. switch (ST0->Tag) {
  317. case TAG_VALID:
  318. Exponent = (int)((ST0->rdw[1] >> 20) & 0x7ff) - 1023;
  319. if (Exponent >= 64) {
  320. //
  321. // Exponent is too big - this cannot be converted to an __int64
  322. // Raise I exception on overflow, or write 0x80000000 for masked
  323. // exception.
  324. //
  325. IntOverflow:
  326. if (HandleInvalidOp(cpu)) {
  327. return;
  328. }
  329. PUT_LONG(pop1, 0x80000000);
  330. } else {
  331. i64 = CastDoubleToInt64(ST0->r64);
  332. i32 = (LONG)i64;
  333. if ((__int64)i32 != i64) {
  334. goto IntOverflow;
  335. }
  336. PUT_LONG(pop1, i32);
  337. }
  338. POPFLT;
  339. break;
  340. case TAG_ZERO:
  341. PUT_LONG(pop1, 0);
  342. POPFLT;
  343. break;
  344. case TAG_SPECIAL:
  345. if (ST0->TagSpecial == TAG_SPECIAL_DENORM) {
  346. i64 = CastDoubleToInt64(ST0->r64);
  347. PUT_LONG(pop1, (LONG)i64);
  348. } else if (!HandleInvalidOp(cpu)) {
  349. // INFINITY and NANs are all invalid operations, and the masked
  350. // behavior is to write 0x80000000
  351. PUT_LONG(pop1, 0x80000000);
  352. }
  353. POPFLT;
  354. break;
  355. case TAG_EMPTY:
  356. if (!HandleStackEmpty(cpu, ST0)) {
  357. PUT_LONG(pop1, 0x80000000);
  358. POPFLT;
  359. }
  360. break;
  361. }
  362. }
  363. FRAG1(FISTP64, LONGLONG) // FISTP m64int
  364. {
  365. PFPREG ST0 = cpu->FpST0;
  366. __int64 i64;
  367. int Exponent;
  368. FpArithDataPreamble(cpu, pop1);
  369. switch (ST0->Tag) {
  370. case TAG_VALID:
  371. Exponent = (int)((ST0->rdw[1] >> 20) & 0x7ff) - 1023;
  372. if (Exponent >= 64) {
  373. //
  374. // Exponent is too big - this cannot be converted to an __int64,
  375. // Raise I exception on overflow, or write 0x800...0 for masked
  376. // exception
  377. //
  378. if (HandleInvalidOp(cpu)) {
  379. return;
  380. }
  381. i64 = (__int64)0x8000000000000000i64;
  382. } else {
  383. i64 = CastDoubleToInt64(ST0->r64);
  384. }
  385. *(UNALIGNED LONGLONG *)pop1 = (LONGLONG)i64;
  386. POPFLT;
  387. break;
  388. case TAG_ZERO:
  389. *(UNALIGNED LONGLONG *)pop1 = 0;
  390. POPFLT;
  391. break;
  392. case TAG_SPECIAL:
  393. if (ST0->TagSpecial == TAG_SPECIAL_DENORM) {
  394. i64 = CastDoubleToInt64(ST0->r64);
  395. *(UNALIGNED LONGLONG *)pop1 = (LONGLONG)i64;
  396. } else if (!HandleInvalidOp(cpu)) {
  397. DWORD *pdw = (DWORD *)pop1;
  398. // INFINITY and NANs are all invalid operations, and the masked
  399. // behavior is to write 0x80000000
  400. PUT_LONG(pdw, 0x00000000);
  401. PUT_LONG((pdw+1), 0x80000000);
  402. }
  403. POPFLT;
  404. break;
  405. case TAG_EMPTY:
  406. if (!HandleStackEmpty(cpu, ST0)) {
  407. DWORD *pdw = (DWORD *)pop1;
  408. PUT_LONG(pdw, 0x00000000);
  409. PUT_LONG((pdw+1), 0x80000000);
  410. POPFLT;
  411. }
  412. break;
  413. }
  414. }
  415. FRAG1(FST32, FLOAT) // FST m32real
  416. {
  417. FpArithDataPreamble(cpu, pop1);
  418. if (cpu->FpST0->Tag == TAG_EMPTY) {
  419. if (HandleStackEmpty(cpu, cpu->FpST0)) {
  420. // unmasked exception - abort the instruction
  421. return;
  422. }
  423. }
  424. PutIntelR4(pop1, cpu->FpST0);
  425. }
  426. FRAG1(FSTP32, FLOAT) // FSTP m32real
  427. {
  428. FpArithDataPreamble(cpu, pop1);
  429. if (cpu->FpST0->Tag == TAG_EMPTY) {
  430. if (HandleStackEmpty(cpu, cpu->FpST0)) {
  431. // unmasked exception - abort the instruction
  432. return;
  433. }
  434. }
  435. PutIntelR4(pop1, cpu->FpST0);
  436. POPFLT;
  437. }
  438. FRAG1(FST64, DOUBLE) // FST m64real
  439. {
  440. FpArithDataPreamble(cpu, pop1);
  441. if (cpu->FpST0->Tag == TAG_EMPTY) {
  442. if (HandleStackEmpty(cpu, cpu->FpST0)) {
  443. // unmasked exception - abort the instruction
  444. return;
  445. }
  446. }
  447. PutIntelR8(pop1, cpu->FpST0);
  448. }
  449. FRAG1(FSTP64, DOUBLE) // FSTP m64real
  450. {
  451. FpArithDataPreamble(cpu, pop1);
  452. if (cpu->FpST0->Tag == TAG_EMPTY) {
  453. if (HandleStackEmpty(cpu, cpu->FpST0)) {
  454. // unmasked exception - abort the instruction
  455. return;
  456. }
  457. }
  458. PutIntelR8(pop1, cpu->FpST0);
  459. POPFLT;
  460. }
  461. FRAG1IMM(FST_STi, INT) // FST ST(i)
  462. {
  463. FpArithPreamble(cpu);
  464. CPUASSERT( (op1 & 0x07) == op1);
  465. if (cpu->FpST0->Tag == TAG_EMPTY) {
  466. if (HandleStackEmpty(cpu, cpu->FpST0)) {
  467. // unmasked exception - abort the instruction
  468. return;
  469. }
  470. }
  471. cpu->FpStack[ST(op1)] = *cpu->FpST0;
  472. }
  473. FRAG1IMM(FSTP_STi, INT) // FSTP ST(i)
  474. {
  475. FpArithPreamble(cpu);
  476. CPUASSERT( (op1 & 0x07) == op1);
  477. if (cpu->FpST0->Tag == TAG_EMPTY) {
  478. if (HandleStackEmpty(cpu, cpu->FpST0)) {
  479. // unmasked exception - abort the instruction
  480. return;
  481. }
  482. }
  483. //CONSIDER: According to TimP, FSTP ST(0) is commonly used to pop the
  484. // stack. It may be worthwhile to test if op1==0 and skip the
  485. // assignment and go right to the POPFLT.
  486. cpu->FpStack[ST(op1)] = *cpu->FpST0;
  487. POPFLT;
  488. }
  489. FRAG0(OPT_FSTP_ST0) // FSTP ST(0)
  490. {
  491. FpArithPreamble(cpu);
  492. if (cpu->FpST0->Tag == TAG_EMPTY) {
  493. if (HandleStackEmpty(cpu, cpu->FpST0)) {
  494. // unmasked exception - abort the instruction
  495. return;
  496. }
  497. }
  498. POPFLT;
  499. }