fpu-glibc.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. /* FPU-related code for systems with GNU libc.
  2. Copyright (C) 2005-2015 Free Software Foundation, Inc.
  3. Contributed by Francois-Xavier Coudert <coudert@clipper.ens.fr>
  4. This file is part of the GNU Fortran runtime library (libgfortran).
  5. Libgfortran is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public
  7. License as published by the Free Software Foundation; either
  8. version 3 of the License, or (at your option) any later version.
  9. Libgfortran is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. Under Section 7 of GPL version 3, you are granted additional
  14. permissions described in the GCC Runtime Library Exception, version
  15. 3.1, as published by the Free Software Foundation.
  16. You should have received a copy of the GNU General Public License and
  17. a copy of the GCC Runtime Library Exception along with this program;
  18. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. <http://www.gnu.org/licenses/>. */
  20. /* FPU-related code for systems with the GNU libc, providing the
  21. feenableexcept function in fenv.h to set individual exceptions
  22. (there's nothing to do that in C99). */
  23. #ifdef HAVE_FENV_H
  24. #include <fenv.h>
  25. #endif
  26. /* Check we can actually store the FPU state in the allocated size. */
  27. _Static_assert (sizeof(fenv_t) <= (size_t) GFC_FPE_STATE_BUFFER_SIZE,
  28. "GFC_FPE_STATE_BUFFER_SIZE is too small");
  29. void set_fpu_trap_exceptions (int trap, int notrap)
  30. {
  31. #ifdef FE_INVALID
  32. if (trap & GFC_FPE_INVALID)
  33. feenableexcept (FE_INVALID);
  34. if (notrap & GFC_FPE_INVALID)
  35. fedisableexcept (FE_INVALID);
  36. #endif
  37. /* Some glibc targets (like alpha) have FE_DENORMAL, but not many. */
  38. #ifdef FE_DENORMAL
  39. if (trap & GFC_FPE_DENORMAL)
  40. feenableexcept (FE_DENORMAL);
  41. if (notrap & GFC_FPE_DENORMAL)
  42. fedisableexcept (FE_DENORMAL);
  43. #endif
  44. #ifdef FE_DIVBYZERO
  45. if (trap & GFC_FPE_ZERO)
  46. feenableexcept (FE_DIVBYZERO);
  47. if (notrap & GFC_FPE_ZERO)
  48. fedisableexcept (FE_DIVBYZERO);
  49. #endif
  50. #ifdef FE_OVERFLOW
  51. if (trap & GFC_FPE_OVERFLOW)
  52. feenableexcept (FE_OVERFLOW);
  53. if (notrap & GFC_FPE_OVERFLOW)
  54. fedisableexcept (FE_OVERFLOW);
  55. #endif
  56. #ifdef FE_UNDERFLOW
  57. if (trap & GFC_FPE_UNDERFLOW)
  58. feenableexcept (FE_UNDERFLOW);
  59. if (notrap & GFC_FPE_UNDERFLOW)
  60. fedisableexcept (FE_UNDERFLOW);
  61. #endif
  62. #ifdef FE_INEXACT
  63. if (trap & GFC_FPE_INEXACT)
  64. feenableexcept (FE_INEXACT);
  65. if (notrap & GFC_FPE_INEXACT)
  66. fedisableexcept (FE_INEXACT);
  67. #endif
  68. }
  69. int
  70. get_fpu_trap_exceptions (void)
  71. {
  72. int exceptions = fegetexcept ();
  73. int res = 0;
  74. #ifdef FE_INVALID
  75. if (exceptions & FE_INVALID) res |= GFC_FPE_INVALID;
  76. #endif
  77. #ifdef FE_DENORMAL
  78. if (exceptions & FE_DENORMAL) res |= GFC_FPE_DENORMAL;
  79. #endif
  80. #ifdef FE_DIVBYZERO
  81. if (exceptions & FE_DIVBYZERO) res |= GFC_FPE_ZERO;
  82. #endif
  83. #ifdef FE_OVERFLOW
  84. if (exceptions & FE_OVERFLOW) res |= GFC_FPE_OVERFLOW;
  85. #endif
  86. #ifdef FE_UNDERFLOW
  87. if (exceptions & FE_UNDERFLOW) res |= GFC_FPE_UNDERFLOW;
  88. #endif
  89. #ifdef FE_INEXACT
  90. if (exceptions & FE_INEXACT) res |= GFC_FPE_INEXACT;
  91. #endif
  92. return res;
  93. }
  94. int
  95. support_fpu_trap (int flag)
  96. {
  97. return support_fpu_flag (flag);
  98. }
  99. void set_fpu (void)
  100. {
  101. #ifndef FE_INVALID
  102. if (options.fpe & GFC_FPE_INVALID)
  103. estr_write ("Fortran runtime warning: IEEE 'invalid operation' "
  104. "exception not supported.\n");
  105. #endif
  106. #ifndef FE_DENORMAL
  107. if (options.fpe & GFC_FPE_DENORMAL)
  108. estr_write ("Fortran runtime warning: Floating point 'denormal operand' "
  109. "exception not supported.\n");
  110. #endif
  111. #ifndef FE_DIVBYZERO
  112. if (options.fpe & GFC_FPE_ZERO)
  113. estr_write ("Fortran runtime warning: IEEE 'division by zero' "
  114. "exception not supported.\n");
  115. #endif
  116. #ifndef FE_OVERFLOW
  117. if (options.fpe & GFC_FPE_OVERFLOW)
  118. estr_write ("Fortran runtime warning: IEEE 'overflow' "
  119. "exception not supported.\n");
  120. #endif
  121. #ifndef FE_UNDERFLOW
  122. if (options.fpe & GFC_FPE_UNDERFLOW)
  123. estr_write ("Fortran runtime warning: IEEE 'underflow' "
  124. "exception not supported.\n");
  125. #endif
  126. #ifndef FE_INEXACT
  127. if (options.fpe & GFC_FPE_INEXACT)
  128. estr_write ("Fortran runtime warning: IEEE 'inexact' "
  129. "exception not supported.\n");
  130. #endif
  131. set_fpu_trap_exceptions (options.fpe, 0);
  132. }
  133. int
  134. get_fpu_except_flags (void)
  135. {
  136. int result, set_excepts;
  137. result = 0;
  138. set_excepts = fetestexcept (FE_ALL_EXCEPT);
  139. #ifdef FE_INVALID
  140. if (set_excepts & FE_INVALID)
  141. result |= GFC_FPE_INVALID;
  142. #endif
  143. #ifdef FE_DIVBYZERO
  144. if (set_excepts & FE_DIVBYZERO)
  145. result |= GFC_FPE_ZERO;
  146. #endif
  147. #ifdef FE_OVERFLOW
  148. if (set_excepts & FE_OVERFLOW)
  149. result |= GFC_FPE_OVERFLOW;
  150. #endif
  151. #ifdef FE_UNDERFLOW
  152. if (set_excepts & FE_UNDERFLOW)
  153. result |= GFC_FPE_UNDERFLOW;
  154. #endif
  155. #ifdef FE_DENORMAL
  156. if (set_excepts & FE_DENORMAL)
  157. result |= GFC_FPE_DENORMAL;
  158. #endif
  159. #ifdef FE_INEXACT
  160. if (set_excepts & FE_INEXACT)
  161. result |= GFC_FPE_INEXACT;
  162. #endif
  163. return result;
  164. }
  165. void
  166. set_fpu_except_flags (int set, int clear)
  167. {
  168. int exc_set = 0, exc_clr = 0;
  169. #ifdef FE_INVALID
  170. if (set & GFC_FPE_INVALID)
  171. exc_set |= FE_INVALID;
  172. else if (clear & GFC_FPE_INVALID)
  173. exc_clr |= FE_INVALID;
  174. #endif
  175. #ifdef FE_DIVBYZERO
  176. if (set & GFC_FPE_ZERO)
  177. exc_set |= FE_DIVBYZERO;
  178. else if (clear & GFC_FPE_ZERO)
  179. exc_clr |= FE_DIVBYZERO;
  180. #endif
  181. #ifdef FE_OVERFLOW
  182. if (set & GFC_FPE_OVERFLOW)
  183. exc_set |= FE_OVERFLOW;
  184. else if (clear & GFC_FPE_OVERFLOW)
  185. exc_clr |= FE_OVERFLOW;
  186. #endif
  187. #ifdef FE_UNDERFLOW
  188. if (set & GFC_FPE_UNDERFLOW)
  189. exc_set |= FE_UNDERFLOW;
  190. else if (clear & GFC_FPE_UNDERFLOW)
  191. exc_clr |= FE_UNDERFLOW;
  192. #endif
  193. #ifdef FE_DENORMAL
  194. if (set & GFC_FPE_DENORMAL)
  195. exc_set |= FE_DENORMAL;
  196. else if (clear & GFC_FPE_DENORMAL)
  197. exc_clr |= FE_DENORMAL;
  198. #endif
  199. #ifdef FE_INEXACT
  200. if (set & GFC_FPE_INEXACT)
  201. exc_set |= FE_INEXACT;
  202. else if (clear & GFC_FPE_INEXACT)
  203. exc_clr |= FE_INEXACT;
  204. #endif
  205. feclearexcept (exc_clr);
  206. feraiseexcept (exc_set);
  207. }
  208. int
  209. support_fpu_flag (int flag)
  210. {
  211. if (flag & GFC_FPE_INVALID)
  212. {
  213. #ifndef FE_INVALID
  214. return 0;
  215. #endif
  216. }
  217. else if (flag & GFC_FPE_ZERO)
  218. {
  219. #ifndef FE_DIVBYZERO
  220. return 0;
  221. #endif
  222. }
  223. else if (flag & GFC_FPE_OVERFLOW)
  224. {
  225. #ifndef FE_OVERFLOW
  226. return 0;
  227. #endif
  228. }
  229. else if (flag & GFC_FPE_UNDERFLOW)
  230. {
  231. #ifndef FE_UNDERFLOW
  232. return 0;
  233. #endif
  234. }
  235. else if (flag & GFC_FPE_DENORMAL)
  236. {
  237. #ifndef FE_DENORMAL
  238. return 0;
  239. #endif
  240. }
  241. else if (flag & GFC_FPE_INEXACT)
  242. {
  243. #ifndef FE_INEXACT
  244. return 0;
  245. #endif
  246. }
  247. return 1;
  248. }
  249. int
  250. get_fpu_rounding_mode (void)
  251. {
  252. int rnd_mode;
  253. rnd_mode = fegetround ();
  254. switch (rnd_mode)
  255. {
  256. #ifdef FE_TONEAREST
  257. case FE_TONEAREST:
  258. return GFC_FPE_TONEAREST;
  259. #endif
  260. #ifdef FE_UPWARD
  261. case FE_UPWARD:
  262. return GFC_FPE_UPWARD;
  263. #endif
  264. #ifdef FE_DOWNWARD
  265. case FE_DOWNWARD:
  266. return GFC_FPE_DOWNWARD;
  267. #endif
  268. #ifdef FE_TOWARDZERO
  269. case FE_TOWARDZERO:
  270. return GFC_FPE_TOWARDZERO;
  271. #endif
  272. default:
  273. return 0; /* Should be unreachable. */
  274. }
  275. }
  276. void
  277. set_fpu_rounding_mode (int mode)
  278. {
  279. int rnd_mode;
  280. switch (mode)
  281. {
  282. #ifdef FE_TONEAREST
  283. case GFC_FPE_TONEAREST:
  284. rnd_mode = FE_TONEAREST;
  285. break;
  286. #endif
  287. #ifdef FE_UPWARD
  288. case GFC_FPE_UPWARD:
  289. rnd_mode = FE_UPWARD;
  290. break;
  291. #endif
  292. #ifdef FE_DOWNWARD
  293. case GFC_FPE_DOWNWARD:
  294. rnd_mode = FE_DOWNWARD;
  295. break;
  296. #endif
  297. #ifdef FE_TOWARDZERO
  298. case GFC_FPE_TOWARDZERO:
  299. rnd_mode = FE_TOWARDZERO;
  300. break;
  301. #endif
  302. default:
  303. return; /* Should be unreachable. */
  304. }
  305. fesetround (rnd_mode);
  306. }
  307. int
  308. support_fpu_rounding_mode (int mode)
  309. {
  310. switch (mode)
  311. {
  312. case GFC_FPE_TONEAREST:
  313. #ifdef FE_TONEAREST
  314. return 1;
  315. #else
  316. return 0;
  317. #endif
  318. case GFC_FPE_UPWARD:
  319. #ifdef FE_UPWARD
  320. return 1;
  321. #else
  322. return 0;
  323. #endif
  324. case GFC_FPE_DOWNWARD:
  325. #ifdef FE_DOWNWARD
  326. return 1;
  327. #else
  328. return 0;
  329. #endif
  330. case GFC_FPE_TOWARDZERO:
  331. #ifdef FE_TOWARDZERO
  332. return 1;
  333. #else
  334. return 0;
  335. #endif
  336. default:
  337. return 0; /* Should be unreachable. */
  338. }
  339. }
  340. void
  341. get_fpu_state (void *state)
  342. {
  343. fegetenv (state);
  344. }
  345. void
  346. set_fpu_state (void *state)
  347. {
  348. fesetenv (state);
  349. }
  350. /* Underflow in glibc is currently only supported on alpha, through
  351. the FE_MAP_UMZ macro and __ieee_set_fp_control() function call. */
  352. int
  353. support_fpu_underflow_control (int kind __attribute__((unused)))
  354. {
  355. #if defined(__alpha__) && defined(FE_MAP_UMZ)
  356. return (kind == 4 || kind == 8) ? 1 : 0;
  357. #else
  358. return 0;
  359. #endif
  360. }
  361. int
  362. get_fpu_underflow_mode (void)
  363. {
  364. #if defined(__alpha__) && defined(FE_MAP_UMZ)
  365. fenv_t state = __ieee_get_fp_control ();
  366. /* Return 0 for abrupt underflow (flush to zero), 1 for gradual underflow. */
  367. return (state & FE_MAP_UMZ) ? 0 : 1;
  368. #else
  369. return 0;
  370. #endif
  371. }
  372. void
  373. set_fpu_underflow_mode (int gradual __attribute__((unused)))
  374. {
  375. #if defined(__alpha__) && defined(FE_MAP_UMZ)
  376. fenv_t state = __ieee_get_fp_control ();
  377. if (gradual)
  378. state &= ~FE_MAP_UMZ;
  379. else
  380. state |= FE_MAP_UMZ;
  381. __ieee_set_fp_control (state);
  382. #endif
  383. }