1 /* Optimized inline fenv.h functions for libm. Generic version.
2 Copyright (C) 2011-2022 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
default_libc_feholdexcept(fenv_t * e)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
default_libc_fesetround(int r)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
default_libc_feholdexcept_setround(fenv_t * e,int r)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
default_libc_fesetenv(fenv_t * e)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
default_libc_feupdateenv(fenv_t * e)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
default_libc_feupdateenv_test(fenv_t * e,int ex)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
default_libc_feholdsetround_ctx(struct rm_ctx * ctx,int round)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
default_libc_feresetround_ctx(struct rm_ctx * ctx)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
default_libc_feholdsetround_noex_ctx(struct rm_ctx * ctx,int round)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
default_libc_feresetround_noex_ctx(struct rm_ctx * ctx)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