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.

893 lines
21 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. fpexcept.c
  5. Abstract:
  6. This module handle boundary conditions while doing math operation.
  7. Need to reimplement or remove if not required.
  8. Author:
  9. Revision History:
  10. 29-sept-1999 ATM Shafiqul Khalid [askhalid] copied from rtl library.
  11. --*/
  12. #if defined(_NTSUBSET_) || defined (_POSIX_)
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #define _KERNEL32_ // Don't Export RaiseException
  17. #endif // _NTSUBSET_
  18. #define DEFINE_EXTERN_HERE
  19. #include <trans.h>
  20. #undef DEFINE_EXTERN_HERE
  21. #include <errno.h>
  22. #include <math.h>
  23. #include <windows.h>
  24. VOID ProxyRaiseException(
  25. IN DWORD dwExceptionCode,
  26. IN DWORD dwExceptionFlags,
  27. IN DWORD nNumberOfArguments,
  28. IN CONST ULONG_PTR *lpArguments
  29. );
  30. //
  31. // copy a double without generating floating point instructions
  32. // (avoid invalid operation on x87)
  33. //
  34. #define COPY_DOUBLE(pdest, psrc) \
  35. ( *(unsigned int *)pdest = *(unsigned int *)psrc, \
  36. *((unsigned int *)pdest+1) = *((unsigned int *)psrc+1) )
  37. //
  38. // _matherr_flag is a communal variable. It is equal to zero
  39. // if the user has redefined matherr(). Otherwise it has a
  40. // non zero value. The default matherr routine does nothing
  41. // and returns 0.
  42. //
  43. int _matherr_flag;
  44. //
  45. // a routine for artificially setting the fp status bits in order
  46. // to signal a software generated masked fp exception.
  47. //
  48. extern void _set_statfp(unsigned int);
  49. void _raise_exc(_FPIEEE_RECORD *prec,unsigned int *pcw,
  50. int flags, int opcode, double *parg1, double *presult);
  51. double _umatherr(int type, unsigned int opcode,
  52. double arg1, double arg2, double presult,
  53. unsigned int cw);
  54. static char *_get_fname(unsigned int opcode);
  55. /***
  56. * _handle_qnan1, _handle_qnan2 - handle quiet NaNs as function arguments
  57. *
  58. *Purpose:
  59. * Do all necessary work for handling the case where the argument
  60. * or one of the arguments of a floating point function is a quiet NaN
  61. *
  62. *Entry:
  63. * unsigned int opcode: The operation code of the fp function
  64. * double x: the fp function argument
  65. * double y: the fp function second argument (_handle_qnan2 only)
  66. * unsigned int savedcw: the user's control word
  67. *
  68. *Exit:
  69. * restore the user's control word, and
  70. * return the suggested return value for the fp function
  71. *
  72. *Exceptions:
  73. *
  74. *******************************************************************************/
  75. double _handle_qnan1(unsigned int opcode,
  76. double x,
  77. unsigned int savedcw)
  78. {
  79. if (! _matherr_flag) {
  80. //
  81. // QNaN arguments are treated as domain errors
  82. // invoke the user's matherr routine
  83. // _umatherr will take care of restoring the
  84. // user's control word
  85. //
  86. return _umatherr(_DOMAIN,opcode,x,0.0,x,savedcw);
  87. }
  88. else {
  89. SetMathError ( EDOM );
  90. _rstorfp(savedcw);
  91. return x;
  92. }
  93. }
  94. double _handle_qnan2(unsigned int opcode,
  95. double x,
  96. double y,
  97. unsigned int savedcw)
  98. {
  99. double result;
  100. //
  101. // NaN propagation should be handled by the underlying fp h/w
  102. //
  103. result = x+y;
  104. if (! _matherr_flag) {
  105. return _umatherr(_DOMAIN,opcode,x,y,result,savedcw);
  106. }
  107. else {
  108. SetMathError ( EDOM );
  109. _rstorfp(savedcw);
  110. return result;
  111. }
  112. }
  113. /***
  114. * _except1 - exception handling shell for fp functions with one argument
  115. *
  116. *Purpose:
  117. *
  118. *Entry:
  119. * int flags: the exception flags
  120. * int opcode: the operation code of the fp function that faulted
  121. * double arg: the argument of the fp function
  122. * double result: default result
  123. * unsigned int cw: user's fp control word
  124. *
  125. *Exit:
  126. * restore user's fp control word
  127. * and return the (possibly modified) result of the fp function
  128. *
  129. *Exceptions:
  130. *
  131. *******************************************************************************/
  132. double _except1(int flags,
  133. int opcode,
  134. double arg,
  135. double result,
  136. unsigned int cw)
  137. {
  138. int type;
  139. if (_handle_exc(flags, &result, cw) == 0) {
  140. //
  141. // At this point _handle_exception has failed to deal
  142. // with the error
  143. // An IEEE exception should be raised
  144. //
  145. _FPIEEE_RECORD rec;
  146. // The rec structure will be filled in by _raise_exc,
  147. // except for the Operand2 information
  148. rec.Operand2.OperandValid = 0;
  149. _raise_exc(&rec, &cw, flags, opcode, &arg, &result);
  150. }
  151. //
  152. // At this point we have either the masked response of the
  153. // exception, or a value supplied by the user's IEEE exception
  154. // handler. The _matherr mechanism is supported for backward
  155. // compatibility.
  156. //
  157. type = _errcode(flags);
  158. // Inexact result fp exception does not have a matherr counterpart;
  159. // in that case type is 0.
  160. if (! _matherr_flag && type) {
  161. return _umatherr(type, opcode, arg, 0.0, result, cw);
  162. }
  163. else {
  164. _set_errno(type);
  165. }
  166. RETURN(cw,result);
  167. }
  168. /***
  169. * _except2 - exception handling shell for fp functions with two arguments
  170. *
  171. *Purpose:
  172. *
  173. *Entry:
  174. * int flags: the exception flags
  175. * int opcode: the operation code of the fp function that faulted
  176. * double arg1: the first argument of the fp function
  177. * double arg2: the second argument of the fp function
  178. * double result: default result
  179. * unsigned int cw: user's fp control word
  180. *
  181. *Exit:
  182. * restore user's fp control word
  183. * and return the (possibly modified) result of the fp function
  184. *
  185. *Exceptions:
  186. *
  187. *******************************************************************************/
  188. double _except2(int flags,
  189. int opcode,
  190. double arg1,
  191. double arg2,
  192. double result,
  193. unsigned int cw)
  194. {
  195. int type;
  196. if (_handle_exc(flags, &result, cw) == 0) {
  197. //
  198. // trap should be taken
  199. //
  200. _FPIEEE_RECORD rec;
  201. //
  202. // fill in operand2 info. The rest of rec will be
  203. // filled in by _raise_exc
  204. //
  205. rec.Operand2.OperandValid = 1;
  206. rec.Operand2.Format = _FpFormatFp64;
  207. rec.Operand2.Value.Fp64Value = arg2;
  208. _raise_exc(&rec, &cw, flags, opcode, &arg1, &result);
  209. }
  210. type = _errcode(flags);
  211. if (! _matherr_flag && type) {
  212. return _umatherr(type, opcode, arg1, arg2, result, cw);
  213. }
  214. else {
  215. _set_errno(type);
  216. }
  217. RETURN(cw,result);
  218. }
  219. /***
  220. * _raise_exc - raise fp IEEE exception
  221. *
  222. *Purpose:
  223. * fill in an fp IEEE record struct and raise a fp exception
  224. *
  225. *
  226. *Entry / Exit:
  227. * IN _FPIEEE_RECORD prec pointer to an IEEE record
  228. * IN OUT unsigned int *pcw pointer to user's fp control word
  229. * IN int flags, exception flags
  230. * IN int opcode, fp operation code
  231. * IN double *parg1, pointer to first argument
  232. * IN double *presult) pointer to result
  233. *
  234. *Exceptions:
  235. *
  236. *******************************************************************************/
  237. void _raise_exc( _FPIEEE_RECORD *prec,
  238. unsigned int *pcw,
  239. int flags,
  240. int opcode,
  241. double *parg1,
  242. double *presult)
  243. {
  244. DWORD exc_code;
  245. unsigned int sw;
  246. //
  247. // reset all control bits
  248. //
  249. *(int *)&(prec->Cause) = 0;
  250. *(int *)&(prec->Enable) = 0;
  251. *(int *)&(prec->Status) = 0;
  252. //
  253. // Precision exception may only coincide with overflow
  254. // or underflow. If this is the case, overflow (or
  255. // underflow) take priority over precision exception.
  256. // The order of checks is from the least important
  257. // to the most important exception
  258. //
  259. if (flags & FP_P) {
  260. exc_code = (DWORD) STATUS_FLOAT_INEXACT_RESULT;
  261. prec->Cause.Inexact = 1;
  262. }
  263. if (flags & FP_U) {
  264. exc_code = (DWORD) STATUS_FLOAT_UNDERFLOW;
  265. prec->Cause.Underflow = 1;
  266. }
  267. if (flags & FP_O) {
  268. exc_code = (DWORD) STATUS_FLOAT_OVERFLOW;
  269. prec->Cause.Overflow = 1;
  270. }
  271. if (flags & FP_Z) {
  272. exc_code = (DWORD) STATUS_FLOAT_DIVIDE_BY_ZERO;
  273. prec->Cause.ZeroDivide = 1;
  274. }
  275. if (flags & FP_I) {
  276. exc_code = (DWORD) STATUS_FLOAT_INVALID_OPERATION;
  277. prec->Cause.InvalidOperation = 1;
  278. }
  279. //
  280. // Set exception enable bits
  281. //
  282. prec->Enable.InvalidOperation = (*pcw & IEM_INVALID) ? 0 : 1;
  283. prec->Enable.ZeroDivide = (*pcw & IEM_ZERODIVIDE) ? 0 : 1;
  284. prec->Enable.Overflow = (*pcw & IEM_OVERFLOW) ? 0 : 1;
  285. prec->Enable.Underflow = (*pcw & IEM_UNDERFLOW) ? 0 : 1;
  286. prec->Enable.Inexact = (*pcw & IEM_INEXACT) ? 0 : 1;
  287. //
  288. // Set status bits
  289. //
  290. sw = _statfp();
  291. if (sw & ISW_INVALID) {
  292. prec->Status.InvalidOperation = 1;
  293. }
  294. if (sw & ISW_ZERODIVIDE) {
  295. prec->Status.ZeroDivide = 1;
  296. }
  297. if (sw & ISW_OVERFLOW) {
  298. prec->Status.Overflow = 1;
  299. }
  300. if (sw & ISW_UNDERFLOW) {
  301. prec->Status.Underflow = 1;
  302. }
  303. if (sw & ISW_INEXACT) {
  304. prec->Status.Inexact = 1;
  305. }
  306. switch (*pcw & IMCW_RC) {
  307. case IRC_CHOP:
  308. prec->RoundingMode = _FpRoundChopped;
  309. break;
  310. case IRC_UP:
  311. prec->RoundingMode = _FpRoundPlusInfinity;
  312. break;
  313. case IRC_DOWN:
  314. prec->RoundingMode = _FpRoundMinusInfinity;
  315. break;
  316. case IRC_NEAR:
  317. prec->RoundingMode = _FpRoundNearest;
  318. break;
  319. }
  320. #ifdef _M_IX86
  321. switch (*pcw & IMCW_PC) {
  322. case IPC_64:
  323. prec->Precision = _FpPrecisionFull;
  324. break;
  325. case IPC_53:
  326. prec->Precision = _FpPrecision53;
  327. break;
  328. case IPC_24:
  329. prec->Precision = _FpPrecision24;
  330. break;
  331. }
  332. #endif
  333. #if defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_PPC)
  334. prec->Precision = _FpPrecision53;
  335. #endif
  336. prec->Operation = opcode;
  337. prec->Operand1.OperandValid = 1;
  338. prec->Operand1.Format = _FpFormatFp64;
  339. prec->Operand1.Value.Fp64Value = *parg1;
  340. prec->Result.OperandValid = 1;
  341. prec->Result.Format = _FpFormatFp64;
  342. prec->Result.Value.Fp64Value = *presult;
  343. //
  344. // By convention software exceptions use the first exception
  345. // parameter in order to pass a pointer to the _FPIEEE_RECORD
  346. // structure.
  347. //
  348. _clrfp();
  349. ProxyRaiseException(exc_code,0,1,(CONST ULONG_PTR *)&prec);
  350. //
  351. // user's trap handler may have changed either the fp environment
  352. // or the result
  353. //
  354. //
  355. // Update exception mask
  356. //
  357. if (prec->Enable.InvalidOperation)
  358. (*pcw) &= ~IEM_INVALID;
  359. if (prec->Enable.ZeroDivide)
  360. (*pcw) &= ~IEM_ZERODIVIDE;
  361. if (prec->Enable.Overflow)
  362. (*pcw) &= ~IEM_OVERFLOW;
  363. if (prec->Enable.Underflow)
  364. (*pcw) &= ~IEM_UNDERFLOW;
  365. if (prec->Enable.Inexact)
  366. (*pcw) &= ~IEM_INEXACT;
  367. //
  368. // Update Rounding mode
  369. //
  370. switch (prec->RoundingMode) {
  371. case _FpRoundChopped:
  372. *pcw = *pcw & ~IMCW_RC | IRC_CHOP;
  373. break;
  374. case _FpRoundPlusInfinity:
  375. *pcw = *pcw & ~IMCW_RC | IRC_UP;
  376. break;
  377. case _FpRoundMinusInfinity:
  378. *pcw = *pcw & ~IMCW_RC | IRC_DOWN;
  379. break;
  380. case _FpRoundNearest:
  381. *pcw = *pcw & ~IMCW_RC | IRC_NEAR;
  382. break;
  383. }
  384. #ifdef _M_IX86
  385. //
  386. // Update Precision Control
  387. //
  388. switch (prec->Precision) {
  389. case _FpPrecisionFull:
  390. *pcw = *pcw & ~IMCW_RC | IPC_64;
  391. break;
  392. case _FpPrecision53:
  393. *pcw = *pcw & ~IMCW_RC | IPC_53;
  394. break;
  395. case _FpPrecision24:
  396. *pcw = *pcw & ~IMCW_RC | IPC_24;
  397. break;
  398. }
  399. #endif
  400. //
  401. // Update result
  402. //
  403. *presult = prec->Result.Value.Fp64Value;
  404. }
  405. /***
  406. * _handle_exc - produce masked response for IEEE fp exception
  407. *
  408. *Purpose:
  409. *
  410. *Entry:
  411. * unsigned int flags the exception flags
  412. * double *presult the default result
  413. * unsigned int cw user's fp control word
  414. *
  415. *Exit:
  416. * returns 1 on successful handling, 0 on failure
  417. * On success, *presult becomes the masked response
  418. *
  419. *Exceptions:
  420. *
  421. *******************************************************************************/
  422. int _handle_exc(unsigned int flags, double * presult, unsigned int cw)
  423. {
  424. //
  425. // flags_p is useful for deciding whether there are still unhandled
  426. // exceptions in case multiple exceptions have occurred
  427. //
  428. int flags_p = flags & (FP_I | FP_Z | FP_O | FP_U | FP_P);
  429. if (flags & FP_I && cw & IEM_INVALID) {
  430. //
  431. // Masked response for invalid operation
  432. //
  433. _set_statfp(ISW_INVALID);
  434. flags_p &= ~FP_I;
  435. }
  436. else if (flags & FP_Z && cw & IEM_ZERODIVIDE) {
  437. //
  438. // Masked response for Division by zero
  439. // result should already have the proper value
  440. //
  441. _set_statfp( ISW_ZERODIVIDE);
  442. flags_p &= ~FP_Z;
  443. }
  444. else if (flags & FP_O && cw & IEM_OVERFLOW) {
  445. //
  446. // Masked response for Overflow
  447. //
  448. _set_statfp(ISW_OVERFLOW);
  449. switch (cw & IMCW_RC) {
  450. case IRC_NEAR:
  451. *presult = *presult > 0.0 ? D_INF : -D_INF;
  452. break;
  453. case IRC_UP:
  454. *presult = *presult > 0.0 ? D_INF : -D_MAX;
  455. break;
  456. case IRC_DOWN:
  457. *presult = *presult > 0.0 ? D_MAX : -D_INF;
  458. break;
  459. case IRC_CHOP:
  460. *presult = *presult > 0.0 ? D_MAX : -D_MAX;
  461. break;
  462. }
  463. flags_p &= ~FP_O;
  464. }
  465. else if (flags & FP_U && cw & IEM_UNDERFLOW) {
  466. //
  467. // Masked response for Underflow:
  468. // According to the IEEE standard, when the underflow trap is not
  469. // enabled, underflow shall be signaled only when both tininess
  470. // and loss of accuracy have been detected
  471. //
  472. int aloss=0; // loss of accuracy flag
  473. if (flags & FP_P) {
  474. aloss = 1;
  475. }
  476. //
  477. // a zero value in the result denotes
  478. // that even after ieee scaling, the exponent
  479. // was too small.
  480. // in this case the masked response is also
  481. // zero (sign is preserved)
  482. //
  483. if (*presult != 0.0) {
  484. double result;
  485. int expn, newexp;
  486. result = _decomp(*presult, &expn);
  487. newexp = expn - IEEE_ADJUST;
  488. if (newexp < MINEXP - 53) {
  489. result *= 0.0; // produce a signed zero
  490. aloss = 1;
  491. }
  492. else {
  493. int neg = result < 0; // save sign
  494. //
  495. // denormalize result
  496. //
  497. (*D_EXP(result)) &= 0x000f; /* clear exponent field */
  498. (*D_EXP(result)) |= 0x0010; /* set hidden bit */
  499. for (;newexp<MINEXP;newexp++) {
  500. if (*D_LO(result) & 0x1 && !aloss) {
  501. aloss = 1;
  502. }
  503. /* shift mantissa to the right */
  504. (*D_LO(result)) >>= 1;
  505. if (*D_HI(result) & 0x1) {
  506. (*D_LO(result)) |= 0x80000000;
  507. }
  508. (*D_HI(result)) >>= 1;
  509. }
  510. if (neg) {
  511. result = -result; // restore sign
  512. }
  513. }
  514. *presult = result;
  515. }
  516. else {
  517. aloss = 1;
  518. }
  519. if (aloss) {
  520. _set_statfp(ISW_UNDERFLOW);
  521. }
  522. flags_p &= ~FP_U;
  523. }
  524. //
  525. // Separate check for precision exception
  526. // (may coexist with overflow or underflow)
  527. //
  528. if (flags & FP_P && cw & IEM_INEXACT) {
  529. //
  530. // Masked response for inexact result
  531. //
  532. _set_statfp(ISW_INEXACT);
  533. flags_p &= ~FP_P;
  534. }
  535. return flags_p ? 0: 1;
  536. }
  537. /***
  538. * _umatherr - call user's matherr routine
  539. *
  540. *Purpose:
  541. * call user's matherr routine and set errno if appropriate
  542. *
  543. *
  544. *Entry:
  545. * int type type of excpetion
  546. * unsigned int opcode fp function that caused the exception
  547. * double arg1 first argument of the fp function
  548. * double arg2 second argument of the fp function
  549. * double retval return value of the fp function
  550. * unsigned int cw user's fp control word
  551. *
  552. *Exit:
  553. * fp control word becomes the user's fp cw
  554. * errno modified if user's matherr returns 0
  555. * return value the retval entered by the user in
  556. * the _exception matherr struct
  557. *
  558. *Exceptions:
  559. *
  560. *******************************************************************************/
  561. double _umatherr(
  562. int type,
  563. unsigned int opcode,
  564. double arg1,
  565. double arg2,
  566. double retval,
  567. unsigned int cw
  568. )
  569. {
  570. struct _exception exc;
  571. //
  572. // call matherr only if the name of the function
  573. // is registered in the table, i.e., only if exc.name is valid
  574. //
  575. if (exc.name = _get_fname(opcode)) {
  576. exc.type = type;
  577. COPY_DOUBLE(&exc.arg1,&arg1);
  578. COPY_DOUBLE(&exc.arg2,&arg2);
  579. COPY_DOUBLE(&exc.retval,&retval);
  580. _rstorfp(cw);
  581. //if (_matherr(&exc) == 0) {
  582. _set_errno(type);
  583. //}
  584. return exc.retval;
  585. }
  586. else {
  587. //
  588. // treat this case as if matherr returned 0
  589. //
  590. _rstorfp(cw);
  591. _set_errno(type);
  592. return retval;
  593. }
  594. }
  595. /***
  596. * _set_errno - set errno
  597. *
  598. *Purpose:
  599. * set correct error value for errno
  600. *
  601. *Entry:
  602. * int matherrtype: the type of math error
  603. *
  604. *Exit:
  605. * modifies errno
  606. *
  607. *Exceptions:
  608. *
  609. *******************************************************************************/
  610. void _set_errno(int matherrtype)
  611. {
  612. switch(matherrtype) {
  613. case _DOMAIN:
  614. SetMathError ( EDOM );
  615. break;
  616. case _OVERFLOW:
  617. case _SING:
  618. SetMathError ( ERANGE );
  619. break;
  620. }
  621. }
  622. /***
  623. * _get_fname - get function name
  624. *
  625. *Purpose:
  626. * returns the _matherr function name that corresponds to a
  627. * floating point opcode
  628. *
  629. *Entry:
  630. * _FP_OPERATION_CODE opcode
  631. *
  632. *Exit:
  633. * returns a pointer to a string
  634. *
  635. *Exceptions:
  636. *
  637. *******************************************************************************/
  638. #define OP_NUM 27 /* number of fp operations */
  639. static char *_get_fname(unsigned int opcode)
  640. {
  641. static struct {
  642. unsigned int opcode;
  643. char *name;
  644. } _names[OP_NUM] = {
  645. { OP_EXP, "exp" },
  646. { OP_POW, "pow" },
  647. { OP_LOG, "log" },
  648. { OP_LOG10, "log10"},
  649. { OP_SINH, "sinh"},
  650. { OP_COSH, "cosh"},
  651. { OP_TANH, "tanh"},
  652. { OP_ASIN, "asin"},
  653. { OP_ACOS, "acos"},
  654. { OP_ATAN, "atan"},
  655. { OP_ATAN2, "atan2"},
  656. { OP_SQRT, "sqrt"},
  657. { OP_SIN, "sin"},
  658. { OP_COS, "cos"},
  659. { OP_TAN, "tan"},
  660. { OP_CEIL, "ceil"},
  661. { OP_FLOOR, "floor"},
  662. { OP_ABS, "fabs"},
  663. { OP_MODF, "modf"},
  664. { OP_LDEXP, "ldexp"},
  665. { OP_CABS, "_cabs"},
  666. { OP_HYPOT, "_hypot"},
  667. { OP_FMOD, "fmod"},
  668. { OP_FREXP, "frexp"},
  669. { OP_Y0, "_y0"},
  670. { OP_Y1, "_y1"},
  671. { OP_YN, "_yn"}
  672. };
  673. int i;
  674. for (i=0;i<OP_NUM;i++) {
  675. if (_names[i].opcode == opcode)
  676. return _names[i].name;
  677. }
  678. return (char *)0;
  679. }
  680. /***
  681. * _errcode - get _matherr error code
  682. *
  683. *Purpose:
  684. * returns matherr type that corresponds to exception flags
  685. *
  686. *Entry:
  687. * flags: exception flags
  688. *
  689. *Exit:
  690. * returns matherr type
  691. *
  692. *Exceptions:
  693. *
  694. *******************************************************************************/
  695. int _errcode(unsigned int flags)
  696. {
  697. unsigned int errcode;
  698. if (flags & FP_TLOSS) {
  699. errcode = _TLOSS;
  700. }
  701. else if (flags & FP_I) {
  702. errcode = _DOMAIN;
  703. }
  704. else if (flags & FP_Z) {
  705. errcode = _SING;
  706. }
  707. else if (flags & FP_O) {
  708. errcode = _OVERFLOW;
  709. }
  710. else if (flags & FP_U) {
  711. errcode = _UNDERFLOW;
  712. }
  713. else {
  714. // FP_P
  715. errcode = 0;
  716. }
  717. return errcode;
  718. }