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