fenv.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*-
  2. * Copyright (c) 2004-2005 David Schultz <[email protected]>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24. * SUCH DAMAGE.
  25. *
  26. * $FreeBSD: src/lib/msun/i387/fenv.c,v 1.8 2011/10/21 06:25:31 das Exp $
  27. */
  28. #include "cdefs-compat.h"
  29. #include "types-compat.h"
  30. #include "math_private.h"
  31. #include "i387/bsd_npx.h"
  32. #define __fenv_static
  33. #include <openlibm_fenv.h>
  34. #ifdef __GNUC_GNU_INLINE__
  35. #error "This file must be compiled with C99 'inline' semantics"
  36. #endif
  37. const fenv_t __fe_dfl_env = {
  38. __INITIAL_NPXCW__,
  39. 0x0000,
  40. 0x0000,
  41. 0x1f80,
  42. 0xffffffff,
  43. { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  44. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }
  45. };
  46. enum __sse_support __has_sse =
  47. #ifdef __SSE__
  48. __SSE_YES;
  49. #else
  50. __SSE_UNK;
  51. #endif
  52. #define getfl(x) __asm __volatile("pushfl\n\tpopl %0" : "=mr" (*(x)))
  53. #define setfl(x) __asm __volatile("pushl %0\n\tpopfl" : : "g" (x))
  54. #define cpuid_dx(x) __asm __volatile("pushl %%ebx\n\tmovl $1, %%eax\n\t" \
  55. "cpuid\n\tpopl %%ebx" \
  56. : "=d" (*(x)) : : "eax", "ecx")
  57. /*
  58. * Test for SSE support on this processor. We need to do this because
  59. * we need to use ldmxcsr/stmxcsr to get correct results if any part
  60. * of the program was compiled to use SSE floating-point, but we can't
  61. * use SSE on older processors.
  62. */
  63. int
  64. __test_sse(void)
  65. {
  66. int flag, nflag;
  67. int dx_features;
  68. /* Am I a 486? */
  69. getfl(&flag);
  70. nflag = flag ^ 0x200000;
  71. setfl(nflag);
  72. getfl(&nflag);
  73. if (flag != nflag) {
  74. /* Not a 486, so CPUID should work. */
  75. cpuid_dx(&dx_features);
  76. if (dx_features & 0x2000000) {
  77. __has_sse = __SSE_YES;
  78. return (1);
  79. }
  80. }
  81. __has_sse = __SSE_NO;
  82. return (0);
  83. }
  84. extern inline OLM_DLLEXPORT int feclearexcept(int __excepts);
  85. extern inline OLM_DLLEXPORT int fegetexceptflag(fexcept_t *__flagp, int __excepts);
  86. OLM_DLLEXPORT int
  87. fesetexceptflag(const fexcept_t *flagp, int excepts)
  88. {
  89. fenv_t env;
  90. uint32_t mxcsr;
  91. __fnstenv(&env);
  92. env.__status &= ~excepts;
  93. env.__status |= *flagp & excepts;
  94. __fldenv(env);
  95. if (__HAS_SSE()) {
  96. __stmxcsr(&mxcsr);
  97. mxcsr &= ~excepts;
  98. mxcsr |= *flagp & excepts;
  99. __ldmxcsr(mxcsr);
  100. }
  101. return (0);
  102. }
  103. OLM_DLLEXPORT int
  104. feraiseexcept(int excepts)
  105. {
  106. fexcept_t ex = excepts;
  107. fesetexceptflag(&ex, excepts);
  108. __fwait();
  109. return (0);
  110. }
  111. extern inline OLM_DLLEXPORT int fetestexcept(int __excepts);
  112. extern inline OLM_DLLEXPORT int fegetround(void);
  113. extern inline OLM_DLLEXPORT int fesetround(int __round);
  114. int
  115. fegetenv(fenv_t *envp)
  116. {
  117. uint32_t mxcsr;
  118. __fnstenv(envp);
  119. /*
  120. * fnstenv masks all exceptions, so we need to restore
  121. * the old control word to avoid this side effect.
  122. */
  123. __fldcw(envp->__control);
  124. if (__HAS_SSE()) {
  125. __stmxcsr(&mxcsr);
  126. __set_mxcsr(*envp, mxcsr);
  127. }
  128. return (0);
  129. }
  130. int
  131. feholdexcept(fenv_t *envp)
  132. {
  133. uint32_t mxcsr;
  134. __fnstenv(envp);
  135. __fnclex();
  136. if (__HAS_SSE()) {
  137. __stmxcsr(&mxcsr);
  138. __set_mxcsr(*envp, mxcsr);
  139. mxcsr &= ~FE_ALL_EXCEPT;
  140. mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT;
  141. __ldmxcsr(mxcsr);
  142. }
  143. return (0);
  144. }
  145. extern inline OLM_DLLEXPORT int fesetenv(const fenv_t *__envp);
  146. OLM_DLLEXPORT int
  147. feupdateenv(const fenv_t *envp)
  148. {
  149. uint32_t mxcsr;
  150. uint16_t status;
  151. __fnstsw(&status);
  152. if (__HAS_SSE())
  153. __stmxcsr(&mxcsr);
  154. else
  155. mxcsr = 0;
  156. fesetenv(envp);
  157. feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT);
  158. return (0);
  159. }
  160. int
  161. feenableexcept(int mask)
  162. {
  163. uint32_t mxcsr, omask;
  164. uint16_t control;
  165. mask &= FE_ALL_EXCEPT;
  166. __fnstcw(&control);
  167. if (__HAS_SSE())
  168. __stmxcsr(&mxcsr);
  169. else
  170. mxcsr = 0;
  171. omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
  172. control &= ~mask;
  173. __fldcw(control);
  174. if (__HAS_SSE()) {
  175. mxcsr &= ~(mask << _SSE_EMASK_SHIFT);
  176. __ldmxcsr(mxcsr);
  177. }
  178. return (omask);
  179. }
  180. int
  181. fedisableexcept(int mask)
  182. {
  183. uint32_t mxcsr, omask;
  184. uint16_t control;
  185. mask &= FE_ALL_EXCEPT;
  186. __fnstcw(&control);
  187. if (__HAS_SSE())
  188. __stmxcsr(&mxcsr);
  189. else
  190. mxcsr = 0;
  191. omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
  192. control |= mask;
  193. __fldcw(control);
  194. if (__HAS_SSE()) {
  195. mxcsr |= mask << _SSE_EMASK_SHIFT;
  196. __ldmxcsr(mxcsr);
  197. }
  198. return (omask);
  199. }