ieee_helper.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /* Helper functions in C for IEEE modules
  2. Copyright (C) 2013-2022 Free Software Foundation, Inc.
  3. Contributed by Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
  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. #include "libgfortran.h"
  21. /* Check support for issignaling macro. If not, we include our own
  22. fallback implementation. */
  23. #ifndef issignaling
  24. # include "issignaling_fallback.h"
  25. #endif
  26. /* Prototypes. */
  27. extern int ieee_class_helper_4 (GFC_REAL_4 *);
  28. internal_proto(ieee_class_helper_4);
  29. extern int ieee_class_helper_8 (GFC_REAL_8 *);
  30. internal_proto(ieee_class_helper_8);
  31. #ifdef HAVE_GFC_REAL_10
  32. extern int ieee_class_helper_10 (GFC_REAL_10 *);
  33. internal_proto(ieee_class_helper_10);
  34. #endif
  35. #ifdef HAVE_GFC_REAL_16
  36. extern int ieee_class_helper_16 (GFC_REAL_16 *);
  37. internal_proto(ieee_class_helper_16);
  38. #endif
  39. /* Enumeration of the possible floating-point types. These values
  40. correspond to the hidden arguments of the IEEE_CLASS_TYPE
  41. derived-type of IEEE_ARITHMETIC. */
  42. enum {
  43. IEEE_OTHER_VALUE = 0,
  44. IEEE_SIGNALING_NAN,
  45. IEEE_QUIET_NAN,
  46. IEEE_NEGATIVE_INF,
  47. IEEE_NEGATIVE_NORMAL,
  48. IEEE_NEGATIVE_DENORMAL,
  49. IEEE_NEGATIVE_SUBNORMAL = IEEE_NEGATIVE_DENORMAL,
  50. IEEE_NEGATIVE_ZERO,
  51. IEEE_POSITIVE_ZERO,
  52. IEEE_POSITIVE_DENORMAL,
  53. IEEE_POSITIVE_SUBNORMAL = IEEE_POSITIVE_DENORMAL,
  54. IEEE_POSITIVE_NORMAL,
  55. IEEE_POSITIVE_INF
  56. };
  57. #define CLASSMACRO(TYPE) \
  58. int ieee_class_helper_ ## TYPE (GFC_REAL_ ## TYPE *value) \
  59. { \
  60. int res = __builtin_fpclassify (IEEE_QUIET_NAN, IEEE_POSITIVE_INF, \
  61. IEEE_POSITIVE_NORMAL, \
  62. IEEE_POSITIVE_DENORMAL, \
  63. IEEE_POSITIVE_ZERO, *value); \
  64. \
  65. if (__builtin_signbit (*value)) \
  66. { \
  67. if (res == IEEE_POSITIVE_NORMAL) \
  68. return IEEE_NEGATIVE_NORMAL; \
  69. else if (res == IEEE_POSITIVE_DENORMAL) \
  70. return IEEE_NEGATIVE_DENORMAL; \
  71. else if (res == IEEE_POSITIVE_ZERO) \
  72. return IEEE_NEGATIVE_ZERO; \
  73. else if (res == IEEE_POSITIVE_INF) \
  74. return IEEE_NEGATIVE_INF; \
  75. } \
  76. \
  77. if (res == IEEE_QUIET_NAN) \
  78. { \
  79. if (issignaling (*value)) \
  80. return IEEE_SIGNALING_NAN; \
  81. else \
  82. return IEEE_QUIET_NAN; \
  83. } \
  84. \
  85. return res; \
  86. }
  87. CLASSMACRO(4)
  88. CLASSMACRO(8)
  89. #ifdef HAVE_GFC_REAL_10
  90. CLASSMACRO(10)
  91. #endif
  92. #ifdef HAVE_GFC_REAL_16
  93. CLASSMACRO(16)
  94. #endif
  95. extern GFC_REAL_4 ieee_value_helper_4 (int);
  96. internal_proto(ieee_value_helper_4);
  97. extern GFC_REAL_8 ieee_value_helper_8 (int);
  98. internal_proto(ieee_value_helper_8);
  99. #ifdef HAVE_GFC_REAL_10
  100. extern GFC_REAL_10 ieee_value_helper_10 (int);
  101. internal_proto(ieee_value_helper_10);
  102. #endif
  103. #ifdef HAVE_GFC_REAL_16
  104. extern GFC_REAL_16 ieee_value_helper_16 (int);
  105. internal_proto(ieee_value_helper_16);
  106. #endif
  107. #define VALUEMACRO(TYPE, SUFFIX) \
  108. GFC_REAL_ ## TYPE ieee_value_helper_ ## TYPE (int type) \
  109. { \
  110. switch (type) \
  111. { \
  112. case IEEE_SIGNALING_NAN: \
  113. return __builtin_nans ## SUFFIX (""); \
  114. \
  115. case IEEE_QUIET_NAN: \
  116. return __builtin_nan ## SUFFIX (""); \
  117. \
  118. case IEEE_NEGATIVE_INF: \
  119. return - __builtin_inf ## SUFFIX (); \
  120. \
  121. case IEEE_NEGATIVE_NORMAL: \
  122. return -42; \
  123. \
  124. case IEEE_NEGATIVE_DENORMAL: \
  125. return -(GFC_REAL_ ## TYPE ## _TINY) / 2; \
  126. \
  127. case IEEE_NEGATIVE_ZERO: \
  128. return -(GFC_REAL_ ## TYPE) 0; \
  129. \
  130. case IEEE_POSITIVE_ZERO: \
  131. return 0; \
  132. \
  133. case IEEE_POSITIVE_DENORMAL: \
  134. return (GFC_REAL_ ## TYPE ## _TINY) / 2; \
  135. \
  136. case IEEE_POSITIVE_NORMAL: \
  137. return 42; \
  138. \
  139. case IEEE_POSITIVE_INF: \
  140. return __builtin_inf ## SUFFIX (); \
  141. \
  142. default: \
  143. return 0; \
  144. } \
  145. }
  146. VALUEMACRO(4, f)
  147. VALUEMACRO(8, )
  148. #ifdef HAVE_GFC_REAL_10
  149. VALUEMACRO(10, l)
  150. #endif
  151. #ifdef HAVE_GFC_REAL_16
  152. # ifdef GFC_REAL_16_IS_FLOAT128
  153. VALUEMACRO(16, f128)
  154. # else
  155. VALUEMACRO(16, l)
  156. # endif
  157. #endif
  158. #define GFC_FPE_ALL (GFC_FPE_INVALID | GFC_FPE_DENORMAL | \
  159. GFC_FPE_ZERO | GFC_FPE_OVERFLOW | \
  160. GFC_FPE_UNDERFLOW | GFC_FPE_INEXACT)
  161. /* Functions to save and restore floating-point state, clear and restore
  162. exceptions on procedure entry/exit. The rules we follow are set
  163. in Fortran 2008's 14.3 paragraph 3, note 14.4, 14.4 paragraph 4,
  164. 14.5 paragraph 2, and 14.6 paragraph 1. */
  165. void ieee_procedure_entry (void *);
  166. export_proto(ieee_procedure_entry);
  167. void
  168. ieee_procedure_entry (void *state)
  169. {
  170. /* Save the floating-point state in the space provided by the caller. */
  171. get_fpu_state (state);
  172. /* Clear the floating-point exceptions. */
  173. set_fpu_except_flags (0, GFC_FPE_ALL);
  174. }
  175. void ieee_procedure_exit (void *);
  176. export_proto(ieee_procedure_exit);
  177. void
  178. ieee_procedure_exit (void *state)
  179. {
  180. /* Get the flags currently signaling. */
  181. int flags = get_fpu_except_flags ();
  182. /* Restore the floating-point state we had on entry. */
  183. set_fpu_state (state);
  184. /* And re-raised the flags that were raised since entry. */
  185. set_fpu_except_flags (flags, 0);
  186. }