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.

485 lines
12 KiB

  1. /*++
  2. Copyright (c) 1995-1998 Microsoft Corporation
  3. Module Name:
  4. fpufprem.c
  5. Abstract:
  6. Floating point remainder fragments (FPREM, FPREM1)
  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 <errno.h>
  18. #include <stdio.h>
  19. #include "wx86.h"
  20. #include "fragp.h"
  21. #include "fpufrags.h"
  22. #include "fpufragp.h"
  23. //
  24. // Forward references
  25. //
  26. NPXFUNC2(FPREM_VALID_VALID);
  27. NPXFUNC2(FPREM_VALID_ZERO);
  28. NPXFUNC2(FPREM_VALID_SPECIAL);
  29. NPXFUNC2(FPREM_ZERO_VALIDORZERO);
  30. NPXFUNC2(FPREM_ZERO_SPECIAL);
  31. NPXFUNC2(FPREM_SPECIAL_VALIDORZERO);
  32. NPXFUNC2(FPREM_SPECIAL_SPECIAL);
  33. NPXFUNC2(FPREM_EMPTY_ANY);
  34. NPXFUNC2(FPREM_ANY_EMPTY);
  35. NPXFUNC2(FPREM1_VALID_VALID);
  36. //NPXFUNC2(FPREM1_VALID_ZERO); // same as FPREM_VALID_ZERO
  37. NPXFUNC2(FPREM1_VALID_SPECIAL);
  38. //NPXFUNC2(FPREM1_ZERO_VALIDORZERO); // same as FPREM_ZERO_VALIDORZERO
  39. NPXFUNC2(FPREM1_ZERO_SPECIAL);
  40. NPXFUNC2(FPREM1_SPECIAL_VALIDORZERO);
  41. NPXFUNC2(FPREM1_SPECIAL_SPECIAL);
  42. NPXFUNC2(FPREM1_EMPTY_ANY);
  43. NPXFUNC2(FPREM1_ANY_EMPTY);
  44. //
  45. // Jump tables
  46. //
  47. const NpxFunc2 FPREMTable[TAG_MAX][TAG_MAX] = {
  48. // left is TAG_VALID, right is ...
  49. { FPREM_VALID_VALID, FPREM_VALID_ZERO, FPREM_VALID_SPECIAL, FPREM_ANY_EMPTY },
  50. // left is TAG_ZERO, right is ...
  51. { FPREM_ZERO_VALIDORZERO, FPREM_ZERO_VALIDORZERO, FPREM_ZERO_SPECIAL, FPREM_ANY_EMPTY },
  52. // left is TAG_SPECIAL, right is ...
  53. { FPREM_SPECIAL_VALIDORZERO, FPREM_SPECIAL_VALIDORZERO, FPREM_SPECIAL_SPECIAL, FPREM_ANY_EMPTY },
  54. // left is TAG_EMPTY, right is ...
  55. { FPREM_EMPTY_ANY, FPREM_EMPTY_ANY, FPREM_EMPTY_ANY, FPREM_EMPTY_ANY }
  56. };
  57. const NpxFunc2 FPREM1Table[TAG_MAX][TAG_MAX] = {
  58. // left is TAG_VALID, right is ...
  59. { FPREM1_VALID_VALID, FPREM_VALID_ZERO, FPREM1_VALID_SPECIAL, FPREM1_ANY_EMPTY },
  60. // left is TAG_ZERO, right is ...
  61. { FPREM_ZERO_VALIDORZERO, FPREM_ZERO_VALIDORZERO, FPREM1_ZERO_SPECIAL, FPREM1_ANY_EMPTY },
  62. // left is TAG_SPECIAL, right is ...
  63. { FPREM1_SPECIAL_VALIDORZERO, FPREM1_SPECIAL_VALIDORZERO, FPREM1_SPECIAL_SPECIAL, FPREM1_ANY_EMPTY },
  64. // left is TAG_EMPTY, right is ...
  65. { FPREM1_EMPTY_ANY, FPREM1_EMPTY_ANY, FPREM1_EMPTY_ANY, FPREM1_EMPTY_ANY }
  66. };
  67. NPXFUNC2(FPREM_VALID_VALID)
  68. {
  69. int ExpL;
  70. int ExpR;
  71. int ExpDiff;
  72. LONG Q;
  73. double DQ;
  74. ExpL = (int)((l->rdw[1] >> 20) & 0x7ff) - 1023;
  75. ExpR = (int)((r->rdw[1] >> 20) & 0x7ff) - 1023;
  76. ExpDiff = abs(ExpL-ExpR);
  77. if (ExpDiff < 64) {
  78. // Do the division and chop the integer result towards zero
  79. DQ = r->r64 / l->r64;
  80. if (DQ < 0) {
  81. Q = (long)ceil(DQ);
  82. } else {
  83. Q = (long)floor(DQ);
  84. }
  85. // Store the remainder
  86. r->r64 -= (DOUBLE)Q * l->r64;
  87. SetTag(r);
  88. // Store the status bits
  89. if (Q < 0) {
  90. //
  91. // Take the absolute value of Q before returning the low 3 bits
  92. // of the quotient.
  93. //
  94. Q = -Q;
  95. }
  96. cpu->FpStatusC2 = 0; // indicate the final remainder is ready
  97. cpu->FpStatusC0 = (Q>>2) & 1;
  98. cpu->FpStatusC3 = (Q>>1) & 1;
  99. cpu->FpStatusC1 = Q & 1;
  100. } else {
  101. DOUBLE PowerOfTwo;
  102. cpu->FpStatusC2 = 1; // indicate the app must loop more
  103. PowerOfTwo = ldexp(1.0, ExpDiff-32); // get 2^(ExpDiff-32)
  104. // get Q by chopping towards zero
  105. DQ = (r->r64/PowerOfTwo) / (l->r64/PowerOfTwo);
  106. if (DQ < 0) {
  107. Q = (long)ceil(DQ);
  108. } else {
  109. Q = (long)floor(DQ);
  110. }
  111. r->r64 -= (DOUBLE)Q * l->r64 * PowerOfTwo;
  112. SetTag(r);
  113. }
  114. }
  115. NPXFUNC2(FPREM_VALID_ZERO)
  116. {
  117. // l is a number, but r is zero - return ST(0) unchanged
  118. cpu->FpStatusC2 = 0; // indicate the final remainder is ready
  119. // Q is 0, so store low 3 bits in the status word
  120. cpu->FpStatusC0 = 0;
  121. cpu->FpStatusC1 = 0;
  122. cpu->FpStatusC3 = 0;
  123. }
  124. NPXFUNC2(FPREM_VALID_SPECIAL)
  125. {
  126. switch (l->TagSpecial) {
  127. case TAG_SPECIAL_DENORM:
  128. FPREM_VALID_VALID(cpu, l, r);
  129. break;
  130. case TAG_SPECIAL_INFINITY:
  131. // Dividing infinity.
  132. SetIndefinite(r);
  133. break;
  134. case TAG_SPECIAL_SNAN:
  135. if (HandleSnan(cpu, r)) {
  136. return;
  137. }
  138. // else fall into QNAN case
  139. case TAG_SPECIAL_QNAN:
  140. case TAG_SPECIAL_INDEF:
  141. // r is the destination and it is a QNAN, while l is a VALID. Return
  142. // the QNAN as the result of the operation
  143. // x86 emulator leaves condition flags alone
  144. break;
  145. }
  146. }
  147. NPXFUNC2(FPREM_ZERO_VALIDORZERO)
  148. {
  149. // l is zero, and r is a number or zero - return INDEFINITE due to the
  150. // division by zero.
  151. if (!HandleInvalidOp(cpu)) {
  152. SetIndefinite(r);
  153. }
  154. }
  155. NPXFUNC2(FPREM_ZERO_SPECIAL)
  156. {
  157. if (r->TagSpecial == TAG_SPECIAL_INFINITY) {
  158. SetIndefinite(r);
  159. } else {
  160. FPREM_VALID_SPECIAL(cpu, l, r);
  161. }
  162. }
  163. NPXFUNC2(FPREM_SPECIAL_VALIDORZERO)
  164. {
  165. switch (l->TagSpecial) {
  166. case TAG_SPECIAL_DENORM:
  167. FPREM_VALID_VALID(cpu, l, r);
  168. break;
  169. case TAG_SPECIAL_INFINITY:
  170. // number / infinity - quotient == 0
  171. cpu->FpStatusC2 = 0;
  172. cpu->FpStatusC0 = 0;
  173. cpu->FpStatusC1 = 0;
  174. cpu->FpStatusC3 = 0;
  175. break;
  176. case TAG_SPECIAL_SNAN:
  177. if (HandleSnan(cpu, l)) {
  178. return;
  179. }
  180. // else fall into QNAN case
  181. case TAG_SPECIAL_QNAN:
  182. case TAG_SPECIAL_INDEF:
  183. // r is the destination and it is a VALID, while l is a NAN. Return
  184. // the NAN as the result of the operation
  185. r->r64 = l->r64;
  186. r->Tag = l->Tag;
  187. r->TagSpecial = l->TagSpecial;
  188. // x86 emulator leaves condition flags alone
  189. break;
  190. }
  191. }
  192. NPXFUNC2(FPREM_SPECIAL_SPECIAL)
  193. {
  194. if (l->TagSpecial == TAG_SPECIAL_DENORM) {
  195. FPREM_VALID_SPECIAL(cpu, l, r);
  196. return;
  197. }
  198. if (r->TagSpecial == TAG_SPECIAL_DENORM) {
  199. FPREM_SPECIAL_VALIDORZERO(cpu, l, r);
  200. }
  201. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  202. return;
  203. }
  204. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  205. return;
  206. }
  207. if (l->TagSpecial == TAG_SPECIAL_INFINITY) {
  208. if (r->TagSpecial == TAG_SPECIAL_INFINITY) {
  209. SetIndefinite(r);
  210. }
  211. //
  212. // r is a NAN of some sort, and l is infinity - return the NAN
  213. // which is already in r.
  214. //
  215. } else {
  216. //
  217. // l is a NAN, and r is either a NAN or INFINITY. Have the native
  218. // FPU return the largest NAN, and re-tag it as appropriate.
  219. //
  220. r->r64 = l->r64 + r->r64;
  221. SetTag(r);
  222. }
  223. }
  224. NPXFUNC2(FPREM_EMPTY_ANY)
  225. {
  226. if (HandleStackEmpty(cpu, l)) {
  227. return;
  228. }
  229. (*FPREMTable[l->Tag][r->Tag])(cpu, l, r);
  230. }
  231. NPXFUNC2(FPREM_ANY_EMPTY)
  232. {
  233. if (HandleStackEmpty(cpu, l)) {
  234. return;
  235. }
  236. (*FPREMTable[l->Tag][r->Tag])(cpu, l, r);
  237. }
  238. FRAG0(FPREM)
  239. {
  240. // get remainder of r/l
  241. PFPREG l = &cpu->FpStack[ST(1)];
  242. PFPREG r = cpu->FpST0;
  243. FpArithPreamble(cpu);
  244. (*FPREMTable[l->Tag][r->Tag])(cpu, l, r);
  245. }
  246. NPXFUNC2(FPREM1_VALID_VALID)
  247. {
  248. int ExpL;
  249. int ExpR;
  250. int ExpDiff;
  251. LONG Q;
  252. double DQ;
  253. double FloorQ, CeilQ;
  254. ExpL = (int)((l->rdw[1] >> 20) & 0x7ff) - 1023;
  255. ExpR = (int)((r->rdw[1] >> 20) & 0x7ff) - 1023;
  256. ExpDiff = abs(ExpL-ExpR);
  257. if (ExpDiff < 64) {
  258. // Do the division and get the integer nearest to the value
  259. DQ = r->r64 / l->r64;
  260. FloorQ = floor(DQ);
  261. CeilQ = ceil(DQ);
  262. if (DQ-FloorQ >= CeilQ-DQ) {
  263. // CeilQ is closer - use it
  264. Q = (long)CeilQ;
  265. } else {
  266. // FloorQ is closer - use it
  267. Q = (long)FloorQ;
  268. }
  269. // Store the remainder
  270. r->r64 -= (DOUBLE)Q * l->r64;
  271. SetTag(r);
  272. // Store the status bits
  273. if (Q < 0) {
  274. //
  275. // Take the absolute value of Q before returning the low 3 bits
  276. // of the quotient.
  277. //
  278. Q = -Q;
  279. }
  280. cpu->FpStatusC2 = 0; // indicate the final remainder is ready
  281. cpu->FpStatusC0 = (Q>>2) & 1;
  282. cpu->FpStatusC3 = (Q>>1) & 1;
  283. cpu->FpStatusC1 = Q & 1;
  284. } else {
  285. DOUBLE PowerOfTwo;
  286. cpu->FpStatusC2 = 1; // indicate the app must loop more
  287. PowerOfTwo = ldexp(1.0, ExpDiff-32); // get 2^(ExpDiff-32)
  288. // get Q by finding the integer nearest to the value
  289. DQ = (r->r64/PowerOfTwo) / (l->r64/PowerOfTwo);
  290. FloorQ = floor(DQ);
  291. CeilQ = ceil(DQ);
  292. if (DQ-FloorQ >= CeilQ-DQ) {
  293. // CeilQ is closer - use it
  294. Q = (long)CeilQ;
  295. } else {
  296. // FloorQ is closer - use it
  297. Q = (long)FloorQ;
  298. }
  299. r->r64 -= (DOUBLE)Q * l->r64 * PowerOfTwo;
  300. SetTag(r);
  301. }
  302. }
  303. NPXFUNC2(FPREM1_VALID_SPECIAL)
  304. {
  305. switch (l->TagSpecial) {
  306. case TAG_SPECIAL_DENORM:
  307. FPREM1_VALID_VALID(cpu, l, r);
  308. break;
  309. case TAG_SPECIAL_INFINITY:
  310. // dividing infinity
  311. SetIndefinite(r);
  312. break;
  313. case TAG_SPECIAL_SNAN:
  314. if (HandleSnan(cpu, r)) {
  315. return;
  316. }
  317. // else fall into QNAN case
  318. case TAG_SPECIAL_QNAN:
  319. case TAG_SPECIAL_INDEF:
  320. // r is the destination and it is a QNAN, while l is a VALID. Return
  321. // the QNAN as the result of the operation
  322. // x86 emulator leaves condition flags alone
  323. break;
  324. }
  325. }
  326. NPXFUNC2(FPREM1_ZERO_SPECIAL)
  327. {
  328. if (r->TagSpecial == TAG_SPECIAL_INFINITY) {
  329. SetIndefinite(r);
  330. } else {
  331. FPREM1_VALID_SPECIAL(cpu, l, r);
  332. }
  333. }
  334. NPXFUNC2(FPREM1_SPECIAL_VALIDORZERO)
  335. {
  336. switch (l->TagSpecial) {
  337. case TAG_SPECIAL_DENORM:
  338. FPREM1_VALID_VALID(cpu, l, r);
  339. break;
  340. case TAG_SPECIAL_INFINITY:
  341. // number / infinity - quotient == 0
  342. cpu->FpStatusC2 = 0;
  343. cpu->FpStatusC0 = 0;
  344. cpu->FpStatusC1 = 0;
  345. cpu->FpStatusC3 = 0;
  346. break;
  347. case TAG_SPECIAL_SNAN:
  348. if (HandleSnan(cpu, l)) {
  349. return;
  350. }
  351. // else fall into QNAN case
  352. case TAG_SPECIAL_QNAN:
  353. case TAG_SPECIAL_INDEF:
  354. // r is the destination and it is a VALID, while l is a NAN. Return
  355. // the NAN as the result of the operation
  356. r->r64 = l->r64;
  357. r->Tag = l->Tag;
  358. r->TagSpecial = l->TagSpecial;
  359. break;
  360. }
  361. }
  362. NPXFUNC2(FPREM1_SPECIAL_SPECIAL)
  363. {
  364. if (l->TagSpecial == TAG_SPECIAL_DENORM) {
  365. FPREM1_VALID_SPECIAL(cpu, l, r);
  366. return;
  367. }
  368. if (r->TagSpecial == TAG_SPECIAL_DENORM) {
  369. FPREM1_SPECIAL_VALIDORZERO(cpu, l, r);
  370. }
  371. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  372. return;
  373. }
  374. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  375. return;
  376. }
  377. if (l->TagSpecial == TAG_SPECIAL_INFINITY) {
  378. if (r->TagSpecial == TAG_SPECIAL_INFINITY) {
  379. SetIndefinite(r);
  380. }
  381. //
  382. // r is a NAN of some sort, and l is infinity - return the NAN
  383. // which is already in r.
  384. //
  385. } else {
  386. //
  387. // l is a NAN, and r is either a NAN or INFINITY. Have the native
  388. // FPU return the largest NAN, and re-tag it as appropriate.
  389. //
  390. r->r64 = l->r64 + r->r64;
  391. SetTag(r);
  392. }
  393. }
  394. NPXFUNC2(FPREM1_EMPTY_ANY)
  395. {
  396. if (HandleStackEmpty(cpu, l)) {
  397. return;
  398. }
  399. (*FPREM1Table[l->Tag][r->Tag])(cpu, l, r);
  400. }
  401. NPXFUNC2(FPREM1_ANY_EMPTY)
  402. {
  403. if (HandleStackEmpty(cpu, l)) {
  404. return;
  405. }
  406. (*FPREM1Table[l->Tag][r->Tag])(cpu, l, r);
  407. }
  408. FRAG0(FPREM1)
  409. {
  410. // get remainder of r/l
  411. PFPREG l = &cpu->FpStack[ST(1)];
  412. PFPREG r = cpu->FpST0;
  413. FpArithPreamble(cpu);
  414. (*FPREM1Table[l->Tag][r->Tag])(cpu, l, r);
  415. }