fenv_private.h 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. /* Optimized inline fenv.h functions for libm. Generic version.
  2. Copyright (C) 2011-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #ifndef _FENV_PRIVATE_H
  16. #define _FENV_PRIVATE_H 1
  17. #include <fenv.h>
  18. #include <get-rounding-mode.h>
  19. /* The standards only specify one variant of the fenv.h interfaces.
  20. But at least for some architectures we can be more efficient if we
  21. know what operations are going to be performed. Therefore we
  22. define additional interfaces. By default they refer to the normal
  23. interfaces. */
  24. static __always_inline void
  25. default_libc_feholdexcept (fenv_t *e)
  26. {
  27. (void) __feholdexcept (e);
  28. }
  29. #ifndef libc_feholdexcept
  30. # define libc_feholdexcept default_libc_feholdexcept
  31. #endif
  32. #ifndef libc_feholdexceptf
  33. # define libc_feholdexceptf default_libc_feholdexcept
  34. #endif
  35. #ifndef libc_feholdexceptl
  36. # define libc_feholdexceptl default_libc_feholdexcept
  37. #endif
  38. static __always_inline void
  39. default_libc_fesetround (int r)
  40. {
  41. (void) __fesetround (r);
  42. }
  43. #ifndef libc_fesetround
  44. # define libc_fesetround default_libc_fesetround
  45. #endif
  46. #ifndef libc_fesetroundf
  47. # define libc_fesetroundf default_libc_fesetround
  48. #endif
  49. #ifndef libc_fesetroundl
  50. # define libc_fesetroundl default_libc_fesetround
  51. #endif
  52. static __always_inline void
  53. default_libc_feholdexcept_setround (fenv_t *e, int r)
  54. {
  55. __feholdexcept (e);
  56. __fesetround (r);
  57. }
  58. #ifndef libc_feholdexcept_setround
  59. # define libc_feholdexcept_setround default_libc_feholdexcept_setround
  60. #endif
  61. #ifndef libc_feholdexcept_setroundf
  62. # define libc_feholdexcept_setroundf default_libc_feholdexcept_setround
  63. #endif
  64. #ifndef libc_feholdexcept_setroundl
  65. # define libc_feholdexcept_setroundl default_libc_feholdexcept_setround
  66. #endif
  67. #ifndef libc_feholdsetround_53bit
  68. # define libc_feholdsetround_53bit libc_feholdsetround
  69. #endif
  70. #ifndef libc_fetestexcept
  71. # define libc_fetestexcept fetestexcept
  72. #endif
  73. #ifndef libc_fetestexceptf
  74. # define libc_fetestexceptf fetestexcept
  75. #endif
  76. #ifndef libc_fetestexceptl
  77. # define libc_fetestexceptl fetestexcept
  78. #endif
  79. static __always_inline void
  80. default_libc_fesetenv (fenv_t *e)
  81. {
  82. (void) __fesetenv (e);
  83. }
  84. #ifndef libc_fesetenv
  85. # define libc_fesetenv default_libc_fesetenv
  86. #endif
  87. #ifndef libc_fesetenvf
  88. # define libc_fesetenvf default_libc_fesetenv
  89. #endif
  90. #ifndef libc_fesetenvl
  91. # define libc_fesetenvl default_libc_fesetenv
  92. #endif
  93. static __always_inline void
  94. default_libc_feupdateenv (fenv_t *e)
  95. {
  96. (void) __feupdateenv (e);
  97. }
  98. #ifndef libc_feupdateenv
  99. # define libc_feupdateenv default_libc_feupdateenv
  100. #endif
  101. #ifndef libc_feupdateenvf
  102. # define libc_feupdateenvf default_libc_feupdateenv
  103. #endif
  104. #ifndef libc_feupdateenvl
  105. # define libc_feupdateenvl default_libc_feupdateenv
  106. #endif
  107. #ifndef libc_feresetround_53bit
  108. # define libc_feresetround_53bit libc_feresetround
  109. #endif
  110. static __always_inline int
  111. default_libc_feupdateenv_test (fenv_t *e, int ex)
  112. {
  113. int ret = fetestexcept (ex);
  114. __feupdateenv (e);
  115. return ret;
  116. }
  117. #ifndef libc_feupdateenv_test
  118. # define libc_feupdateenv_test default_libc_feupdateenv_test
  119. #endif
  120. #ifndef libc_feupdateenv_testf
  121. # define libc_feupdateenv_testf default_libc_feupdateenv_test
  122. #endif
  123. #ifndef libc_feupdateenv_testl
  124. # define libc_feupdateenv_testl default_libc_feupdateenv_test
  125. #endif
  126. /* Save and set the rounding mode. The use of fenv_t to store the old mode
  127. allows a target-specific version of this function to avoid converting the
  128. rounding mode from the fpu format. By default we have no choice but to
  129. manipulate the entire env. */
  130. #ifndef libc_feholdsetround
  131. # define libc_feholdsetround libc_feholdexcept_setround
  132. #endif
  133. #ifndef libc_feholdsetroundf
  134. # define libc_feholdsetroundf libc_feholdexcept_setroundf
  135. #endif
  136. #ifndef libc_feholdsetroundl
  137. # define libc_feholdsetroundl libc_feholdexcept_setroundl
  138. #endif
  139. /* ... and the reverse. */
  140. #ifndef libc_feresetround
  141. # define libc_feresetround libc_feupdateenv
  142. #endif
  143. #ifndef libc_feresetroundf
  144. # define libc_feresetroundf libc_feupdateenvf
  145. #endif
  146. #ifndef libc_feresetroundl
  147. # define libc_feresetroundl libc_feupdateenvl
  148. #endif
  149. /* ... and a version that also discards exceptions. */
  150. #ifndef libc_feresetround_noex
  151. # define libc_feresetround_noex libc_fesetenv
  152. #endif
  153. #ifndef libc_feresetround_noexf
  154. # define libc_feresetround_noexf libc_fesetenvf
  155. #endif
  156. #ifndef libc_feresetround_noexl
  157. # define libc_feresetround_noexl libc_fesetenvl
  158. #endif
  159. #ifndef HAVE_RM_CTX
  160. # define HAVE_RM_CTX 0
  161. #endif
  162. /* Default implementation using standard fenv functions.
  163. Avoid unnecessary rounding mode changes by first checking the
  164. current rounding mode. Note the use of __glibc_unlikely is
  165. important for performance. */
  166. static __always_inline void
  167. default_libc_feholdsetround_ctx (struct rm_ctx *ctx, int round)
  168. {
  169. ctx->updated_status = false;
  170. /* Update rounding mode only if different. */
  171. if (__glibc_unlikely (round != get_rounding_mode ()))
  172. {
  173. ctx->updated_status = true;
  174. __fegetenv (&ctx->env);
  175. __fesetround (round);
  176. }
  177. }
  178. static __always_inline void
  179. default_libc_feresetround_ctx (struct rm_ctx *ctx)
  180. {
  181. /* Restore the rounding mode if updated. */
  182. if (__glibc_unlikely (ctx->updated_status))
  183. __feupdateenv (&ctx->env);
  184. }
  185. static __always_inline void
  186. default_libc_feholdsetround_noex_ctx (struct rm_ctx *ctx, int round)
  187. {
  188. /* Save exception flags and rounding mode, and disable exception
  189. traps. */
  190. __feholdexcept (&ctx->env);
  191. /* Update rounding mode only if different. */
  192. if (__glibc_unlikely (round != get_rounding_mode ()))
  193. __fesetround (round);
  194. }
  195. static __always_inline void
  196. default_libc_feresetround_noex_ctx (struct rm_ctx *ctx)
  197. {
  198. /* Restore exception flags and rounding mode. */
  199. __fesetenv (&ctx->env);
  200. }
  201. #if HAVE_RM_CTX
  202. /* Set/Restore Rounding Modes only when necessary. If defined, these functions
  203. set/restore floating point state only if the state needed within the lexical
  204. block is different from the current state. This saves a lot of time when
  205. the floating point unit is much slower than the fixed point units. */
  206. # ifndef libc_feholdsetround_noex_ctx
  207. # define libc_feholdsetround_noex_ctx libc_feholdsetround_ctx
  208. # endif
  209. # ifndef libc_feholdsetround_noexf_ctx
  210. # define libc_feholdsetround_noexf_ctx libc_feholdsetroundf_ctx
  211. # endif
  212. # ifndef libc_feholdsetround_noexl_ctx
  213. # define libc_feholdsetround_noexl_ctx libc_feholdsetroundl_ctx
  214. # endif
  215. # ifndef libc_feresetround_noex_ctx
  216. # define libc_feresetround_noex_ctx libc_fesetenv_ctx
  217. # endif
  218. # ifndef libc_feresetround_noexf_ctx
  219. # define libc_feresetround_noexf_ctx libc_fesetenvf_ctx
  220. # endif
  221. # ifndef libc_feresetround_noexl_ctx
  222. # define libc_feresetround_noexl_ctx libc_fesetenvl_ctx
  223. # endif
  224. #else
  225. # define libc_feholdsetround_ctx default_libc_feholdsetround_ctx
  226. # define libc_feresetround_ctx default_libc_feresetround_ctx
  227. # define libc_feholdsetround_noex_ctx default_libc_feholdsetround_noex_ctx
  228. # define libc_feresetround_noex_ctx default_libc_feresetround_noex_ctx
  229. # define libc_feholdsetroundf_ctx libc_feholdsetround_ctx
  230. # define libc_feholdsetroundl_ctx libc_feholdsetround_ctx
  231. # define libc_feresetroundf_ctx libc_feresetround_ctx
  232. # define libc_feresetroundl_ctx libc_feresetround_ctx
  233. # define libc_feholdsetround_noexf_ctx libc_feholdsetround_noex_ctx
  234. # define libc_feholdsetround_noexl_ctx libc_feholdsetround_noex_ctx
  235. # define libc_feresetround_noexf_ctx libc_feresetround_noex_ctx
  236. # define libc_feresetround_noexl_ctx libc_feresetround_noex_ctx
  237. #endif
  238. #ifndef libc_feholdsetround_53bit_ctx
  239. # define libc_feholdsetround_53bit_ctx libc_feholdsetround_ctx
  240. #endif
  241. #ifndef libc_feresetround_53bit_ctx
  242. # define libc_feresetround_53bit_ctx libc_feresetround_ctx
  243. #endif
  244. #define SET_RESTORE_ROUND_GENERIC(RM,ROUNDFUNC,CLEANUPFUNC) \
  245. struct rm_ctx ctx __attribute__((cleanup (CLEANUPFUNC ## _ctx))); \
  246. ROUNDFUNC ## _ctx (&ctx, (RM))
  247. /* Set the rounding mode within a lexical block. Restore the rounding mode to
  248. the value at the start of the block. The exception mode must be preserved.
  249. Exceptions raised within the block must be set in the exception flags.
  250. Non-stop mode may be enabled inside the block. */
  251. #define SET_RESTORE_ROUND(RM) \
  252. SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround, libc_feresetround)
  253. #define SET_RESTORE_ROUNDF(RM) \
  254. SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetroundf, libc_feresetroundf)
  255. #define SET_RESTORE_ROUNDL(RM) \
  256. SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetroundl, libc_feresetroundl)
  257. /* Set the rounding mode within a lexical block. Restore the rounding mode to
  258. the value at the start of the block. The exception mode must be preserved.
  259. Exceptions raised within the block must be discarded, and exception flags
  260. are restored to the value at the start of the block.
  261. Non-stop mode must be enabled inside the block. */
  262. #define SET_RESTORE_ROUND_NOEX(RM) \
  263. SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_noex, \
  264. libc_feresetround_noex)
  265. #define SET_RESTORE_ROUND_NOEXF(RM) \
  266. SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_noexf, \
  267. libc_feresetround_noexf)
  268. #define SET_RESTORE_ROUND_NOEXL(RM) \
  269. SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_noexl, \
  270. libc_feresetround_noexl)
  271. /* Like SET_RESTORE_ROUND, but also set rounding precision to 53 bits. */
  272. #define SET_RESTORE_ROUND_53BIT(RM) \
  273. SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_53bit, \
  274. libc_feresetround_53bit)
  275. #endif /* fenv_private.h. */