fenv_private.h 9.8 KB

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