]>
Commit | Line | Data |
---|---|---|
63716ab2 | 1 | /* Helper macros for functions returning a narrower type. |
6d7e8eda | 2 | Copyright (C) 2018-2023 Free Software Foundation, Inc. |
63716ab2 JM |
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 | |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
63716ab2 JM |
18 | |
19 | #ifndef _MATH_NARROW_H | |
20 | #define _MATH_NARROW_H 1 | |
21 | ||
22 | #include <bits/floatn.h> | |
23 | #include <bits/long-double.h> | |
24 | #include <errno.h> | |
25 | #include <fenv.h> | |
26 | #include <ieee754.h> | |
b4d5b8b0 | 27 | #include <math-barriers.h> |
63716ab2 | 28 | #include <math_private.h> |
70e2ba33 | 29 | #include <fenv_private.h> |
abd38358 | 30 | #include <math-narrow-alias.h> |
1356f38d | 31 | #include <stdbool.h> |
63716ab2 JM |
32 | |
33 | /* Carry out a computation using round-to-odd. The computation is | |
34 | EXPR; the union type in which to store the result is UNION and the | |
35 | subfield of the "ieee" field of that union with the low part of the | |
abd38358 JM |
36 | mantissa is MANTISSA; SUFFIX is the suffix for both underlying libm |
37 | functions for the argument type (for computations where a libm | |
38 | function rather than a C operator is used when argument and result | |
39 | types are the same) and the libc_fe* macros to ensure that the | |
40 | correct rounding mode is used, for platforms with multiple rounding | |
1356f38d JM |
41 | modes where those macros set only the relevant mode. |
42 | CLEAR_UNDERFLOW indicates whether underflow exceptions must be | |
43 | cleared (in the case where a round-toward-zero underflow might not | |
44 | indicate an underflow after narrowing, when that narrowing only | |
45 | reduces precision not exponent range and the architecture uses | |
46 | before-rounding tininess detection). This macro does not work | |
47 | correctly if the sign of an exact zero result depends on the | |
48 | rounding mode, so that case must be checked for separately. */ | |
49 | #define ROUND_TO_ODD(EXPR, UNION, SUFFIX, MANTISSA, CLEAR_UNDERFLOW) \ | |
63716ab2 JM |
50 | ({ \ |
51 | fenv_t env; \ | |
52 | UNION u; \ | |
53 | \ | |
54 | libc_feholdexcept_setround ## SUFFIX (&env, FE_TOWARDZERO); \ | |
55 | u.d = (EXPR); \ | |
56 | math_force_eval (u.d); \ | |
1356f38d JM |
57 | if (CLEAR_UNDERFLOW) \ |
58 | feclearexcept (FE_UNDERFLOW); \ | |
63716ab2 JM |
59 | u.ieee.MANTISSA \ |
60 | |= libc_feupdateenv_test ## SUFFIX (&env, FE_INEXACT) != 0; \ | |
61 | \ | |
62 | u.d; \ | |
63 | }) | |
64 | ||
d8742dd8 JM |
65 | /* Check for error conditions from a narrowing add function returning |
66 | RET with arguments X and Y and set errno as needed. Overflow and | |
67 | underflow can occur for finite arguments and a domain error for | |
68 | infinite ones. */ | |
69 | #define CHECK_NARROW_ADD(RET, X, Y) \ | |
70 | do \ | |
71 | { \ | |
72 | if (!isfinite (RET)) \ | |
73 | { \ | |
74 | if (isnan (RET)) \ | |
75 | { \ | |
76 | if (!isnan (X) && !isnan (Y)) \ | |
77 | __set_errno (EDOM); \ | |
78 | } \ | |
79 | else if (isfinite (X) && isfinite (Y)) \ | |
80 | __set_errno (ERANGE); \ | |
81 | } \ | |
82 | else if ((RET) == 0 && (X) != -(Y)) \ | |
83 | __set_errno (ERANGE); \ | |
84 | } \ | |
85 | while (0) | |
86 | ||
87 | /* Implement narrowing add using round-to-odd. The arguments are X | |
88 | and Y, the return type is TYPE and UNION, MANTISSA and SUFFIX are | |
89 | as for ROUND_TO_ODD. */ | |
90 | #define NARROW_ADD_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA) \ | |
91 | do \ | |
92 | { \ | |
93 | TYPE ret; \ | |
94 | \ | |
95 | /* Ensure a zero result is computed in the original rounding \ | |
96 | mode. */ \ | |
97 | if ((X) == -(Y)) \ | |
98 | ret = (TYPE) ((X) + (Y)); \ | |
99 | else \ | |
100 | ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) + (Y), \ | |
1356f38d | 101 | UNION, SUFFIX, MANTISSA, false); \ |
d8742dd8 JM |
102 | \ |
103 | CHECK_NARROW_ADD (ret, (X), (Y)); \ | |
104 | return ret; \ | |
105 | } \ | |
106 | while (0) | |
107 | ||
108 | /* Implement a narrowing add function that is not actually narrowing | |
109 | or where no attempt is made to be correctly rounding (the latter | |
110 | only applies to IBM long double). The arguments are X and Y and | |
111 | the return type is TYPE. */ | |
112 | #define NARROW_ADD_TRIVIAL(X, Y, TYPE) \ | |
113 | do \ | |
114 | { \ | |
115 | TYPE ret; \ | |
116 | \ | |
117 | ret = (TYPE) ((X) + (Y)); \ | |
118 | CHECK_NARROW_ADD (ret, (X), (Y)); \ | |
119 | return ret; \ | |
120 | } \ | |
121 | while (0) | |
122 | ||
8d3f9e85 JM |
123 | /* Check for error conditions from a narrowing subtract function |
124 | returning RET with arguments X and Y and set errno as needed. | |
125 | Overflow and underflow can occur for finite arguments and a domain | |
126 | error for infinite ones. */ | |
127 | #define CHECK_NARROW_SUB(RET, X, Y) \ | |
128 | do \ | |
129 | { \ | |
130 | if (!isfinite (RET)) \ | |
131 | { \ | |
132 | if (isnan (RET)) \ | |
133 | { \ | |
134 | if (!isnan (X) && !isnan (Y)) \ | |
135 | __set_errno (EDOM); \ | |
136 | } \ | |
137 | else if (isfinite (X) && isfinite (Y)) \ | |
138 | __set_errno (ERANGE); \ | |
139 | } \ | |
140 | else if ((RET) == 0 && (X) != (Y)) \ | |
141 | __set_errno (ERANGE); \ | |
142 | } \ | |
143 | while (0) | |
144 | ||
145 | /* Implement narrowing subtract using round-to-odd. The arguments are | |
146 | X and Y, the return type is TYPE and UNION, MANTISSA and SUFFIX are | |
147 | as for ROUND_TO_ODD. */ | |
148 | #define NARROW_SUB_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA) \ | |
149 | do \ | |
150 | { \ | |
151 | TYPE ret; \ | |
152 | \ | |
153 | /* Ensure a zero result is computed in the original rounding \ | |
154 | mode. */ \ | |
155 | if ((X) == (Y)) \ | |
156 | ret = (TYPE) ((X) - (Y)); \ | |
157 | else \ | |
158 | ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) - (Y), \ | |
1356f38d | 159 | UNION, SUFFIX, MANTISSA, false); \ |
8d3f9e85 JM |
160 | \ |
161 | CHECK_NARROW_SUB (ret, (X), (Y)); \ | |
162 | return ret; \ | |
163 | } \ | |
164 | while (0) | |
165 | ||
166 | /* Implement a narrowing subtract function that is not actually | |
167 | narrowing or where no attempt is made to be correctly rounding (the | |
168 | latter only applies to IBM long double). The arguments are X and Y | |
169 | and the return type is TYPE. */ | |
170 | #define NARROW_SUB_TRIVIAL(X, Y, TYPE) \ | |
171 | do \ | |
172 | { \ | |
173 | TYPE ret; \ | |
174 | \ | |
175 | ret = (TYPE) ((X) - (Y)); \ | |
176 | CHECK_NARROW_SUB (ret, (X), (Y)); \ | |
177 | return ret; \ | |
178 | } \ | |
179 | while (0) | |
180 | ||
69a01461 JM |
181 | /* Check for error conditions from a narrowing multiply function |
182 | returning RET with arguments X and Y and set errno as needed. | |
183 | Overflow and underflow can occur for finite arguments and a domain | |
184 | error for Inf * 0. */ | |
185 | #define CHECK_NARROW_MUL(RET, X, Y) \ | |
186 | do \ | |
187 | { \ | |
188 | if (!isfinite (RET)) \ | |
189 | { \ | |
190 | if (isnan (RET)) \ | |
191 | { \ | |
192 | if (!isnan (X) && !isnan (Y)) \ | |
193 | __set_errno (EDOM); \ | |
194 | } \ | |
195 | else if (isfinite (X) && isfinite (Y)) \ | |
196 | __set_errno (ERANGE); \ | |
197 | } \ | |
198 | else if ((RET) == 0 && (X) != 0 && (Y) != 0) \ | |
199 | __set_errno (ERANGE); \ | |
200 | } \ | |
201 | while (0) | |
202 | ||
203 | /* Implement narrowing multiply using round-to-odd. The arguments are | |
1356f38d JM |
204 | X and Y, the return type is TYPE and UNION, MANTISSA, SUFFIX and |
205 | CLEAR_UNDERFLOW are as for ROUND_TO_ODD. */ | |
206 | #define NARROW_MUL_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA, \ | |
207 | CLEAR_UNDERFLOW) \ | |
69a01461 JM |
208 | do \ |
209 | { \ | |
210 | TYPE ret; \ | |
211 | \ | |
212 | ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) * (Y), \ | |
1356f38d JM |
213 | UNION, SUFFIX, MANTISSA, \ |
214 | CLEAR_UNDERFLOW); \ | |
69a01461 JM |
215 | \ |
216 | CHECK_NARROW_MUL (ret, (X), (Y)); \ | |
217 | return ret; \ | |
218 | } \ | |
219 | while (0) | |
220 | ||
221 | /* Implement a narrowing multiply function that is not actually | |
222 | narrowing or where no attempt is made to be correctly rounding (the | |
223 | latter only applies to IBM long double). The arguments are X and Y | |
224 | and the return type is TYPE. */ | |
225 | #define NARROW_MUL_TRIVIAL(X, Y, TYPE) \ | |
226 | do \ | |
227 | { \ | |
228 | TYPE ret; \ | |
229 | \ | |
230 | ret = (TYPE) ((X) * (Y)); \ | |
231 | CHECK_NARROW_MUL (ret, (X), (Y)); \ | |
232 | return ret; \ | |
233 | } \ | |
234 | while (0) | |
235 | ||
632a6cbe JM |
236 | /* Check for error conditions from a narrowing divide function |
237 | returning RET with arguments X and Y and set errno as needed. | |
238 | Overflow, underflow and divide-by-zero can occur for finite | |
239 | arguments and a domain error for Inf / Inf and 0 / 0. */ | |
240 | #define CHECK_NARROW_DIV(RET, X, Y) \ | |
241 | do \ | |
242 | { \ | |
243 | if (!isfinite (RET)) \ | |
244 | { \ | |
245 | if (isnan (RET)) \ | |
246 | { \ | |
247 | if (!isnan (X) && !isnan (Y)) \ | |
248 | __set_errno (EDOM); \ | |
249 | } \ | |
250 | else if (isfinite (X)) \ | |
251 | __set_errno (ERANGE); \ | |
252 | } \ | |
253 | else if ((RET) == 0 && (X) != 0 && !isinf (Y)) \ | |
254 | __set_errno (ERANGE); \ | |
255 | } \ | |
256 | while (0) | |
257 | ||
1356f38d JM |
258 | /* Implement narrowing divide using round-to-odd. The arguments are X |
259 | and Y, the return type is TYPE and UNION, MANTISSA, SUFFIX and | |
260 | CLEAR_UNDERFLOW are as for ROUND_TO_ODD. */ | |
261 | #define NARROW_DIV_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA, \ | |
262 | CLEAR_UNDERFLOW) \ | |
632a6cbe JM |
263 | do \ |
264 | { \ | |
265 | TYPE ret; \ | |
266 | \ | |
267 | ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) / (Y), \ | |
1356f38d JM |
268 | UNION, SUFFIX, MANTISSA, \ |
269 | CLEAR_UNDERFLOW); \ | |
632a6cbe JM |
270 | \ |
271 | CHECK_NARROW_DIV (ret, (X), (Y)); \ | |
272 | return ret; \ | |
273 | } \ | |
274 | while (0) | |
275 | ||
276 | /* Implement a narrowing divide function that is not actually | |
277 | narrowing or where no attempt is made to be correctly rounding (the | |
278 | latter only applies to IBM long double). The arguments are X and Y | |
279 | and the return type is TYPE. */ | |
280 | #define NARROW_DIV_TRIVIAL(X, Y, TYPE) \ | |
281 | do \ | |
282 | { \ | |
283 | TYPE ret; \ | |
284 | \ | |
285 | ret = (TYPE) ((X) / (Y)); \ | |
286 | CHECK_NARROW_DIV (ret, (X), (Y)); \ | |
287 | return ret; \ | |
288 | } \ | |
289 | while (0) | |
290 | ||
abd38358 JM |
291 | /* Check for error conditions from a narrowing square root function |
292 | returning RET with argument X and set errno as needed. Overflow | |
293 | and underflow can occur for finite positive arguments and a domain | |
294 | error for negative arguments. */ | |
295 | #define CHECK_NARROW_SQRT(RET, X) \ | |
296 | do \ | |
297 | { \ | |
298 | if (!isfinite (RET)) \ | |
299 | { \ | |
300 | if (isnan (RET)) \ | |
301 | { \ | |
302 | if (!isnan (X)) \ | |
303 | __set_errno (EDOM); \ | |
304 | } \ | |
305 | else if (isfinite (X)) \ | |
306 | __set_errno (ERANGE); \ | |
307 | } \ | |
308 | else if ((RET) == 0 && (X) != 0) \ | |
309 | __set_errno (ERANGE); \ | |
310 | } \ | |
311 | while (0) | |
63716ab2 | 312 | |
abd38358 JM |
313 | /* Implement narrowing square root using round-to-odd. The argument |
314 | is X, the return type is TYPE and UNION, MANTISSA and SUFFIX are as | |
315 | for ROUND_TO_ODD. */ | |
316 | #define NARROW_SQRT_ROUND_TO_ODD(X, TYPE, UNION, SUFFIX, MANTISSA) \ | |
317 | do \ | |
318 | { \ | |
319 | TYPE ret; \ | |
320 | \ | |
321 | ret = (TYPE) ROUND_TO_ODD (sqrt ## SUFFIX (math_opt_barrier (X)), \ | |
1356f38d | 322 | UNION, SUFFIX, MANTISSA, false); \ |
abd38358 JM |
323 | \ |
324 | CHECK_NARROW_SQRT (ret, (X)); \ | |
325 | return ret; \ | |
326 | } \ | |
327 | while (0) | |
63716ab2 | 328 | |
abd38358 JM |
329 | /* Implement a narrowing square root function where no attempt is made |
330 | to be correctly rounding (this only applies to IBM long double; the | |
331 | case where the function is not actually narrowing is handled by | |
332 | aliasing other sqrt functions in libm, not using this macro). The | |
333 | argument is X and the return type is TYPE. */ | |
334 | #define NARROW_SQRT_TRIVIAL(X, TYPE, SUFFIX) \ | |
335 | do \ | |
336 | { \ | |
337 | TYPE ret; \ | |
338 | \ | |
339 | ret = (TYPE) (sqrt ## SUFFIX (X)); \ | |
340 | CHECK_NARROW_SQRT (ret, (X)); \ | |
341 | return ret; \ | |
342 | } \ | |
343 | while (0) | |
63716ab2 | 344 | |
b3f27d81 JM |
345 | /* Check for error conditions from a narrowing fused multiply-add |
346 | function returning RET with arguments X, Y and Z and set errno as | |
347 | needed. Checking for error conditions for fma (either narrowing or | |
348 | not) and setting errno is not currently implemented. See bug | |
349 | 6801. */ | |
350 | #define CHECK_NARROW_FMA(RET, X, Y, Z) \ | |
351 | do \ | |
352 | { \ | |
353 | } \ | |
354 | while (0) | |
355 | ||
356 | /* Implement narrowing fused multiply-add using round-to-odd. The | |
357 | arguments are X, Y and Z, the return type is TYPE and UNION, | |
358 | MANTISSA, SUFFIX and CLEAR_UNDERFLOW are as for ROUND_TO_ODD. */ | |
359 | #define NARROW_FMA_ROUND_TO_ODD(X, Y, Z, TYPE, UNION, SUFFIX, MANTISSA, \ | |
360 | CLEAR_UNDERFLOW) \ | |
361 | do \ | |
362 | { \ | |
363 | typeof (X) tmp; \ | |
364 | TYPE ret; \ | |
365 | \ | |
366 | tmp = ROUND_TO_ODD (fma ## SUFFIX (math_opt_barrier (X), (Y), \ | |
367 | (Z)), \ | |
368 | UNION, SUFFIX, MANTISSA, CLEAR_UNDERFLOW); \ | |
369 | /* If the round-to-odd result is zero, the result is an exact \ | |
370 | zero and must be recomputed in the original rounding mode. */ \ | |
371 | if (tmp == 0) \ | |
372 | ret = (TYPE) (math_opt_barrier (X) * (Y) + (Z)); \ | |
373 | else \ | |
374 | ret = (TYPE) tmp; \ | |
375 | \ | |
376 | CHECK_NARROW_FMA (ret, (X), (Y), (Z)); \ | |
377 | return ret; \ | |
378 | } \ | |
379 | while (0) | |
380 | ||
381 | /* Implement a narrowing fused multiply-add function where no attempt | |
382 | is made to be correctly rounding (this only applies to IBM long | |
383 | double; the case where the function is not actually narrowing is | |
384 | handled by aliasing other fma functions in libm, not using this | |
385 | macro). The arguments are X, Y and Z and the return type is | |
386 | TYPE. */ | |
387 | #define NARROW_FMA_TRIVIAL(X, Y, Z, TYPE, SUFFIX) \ | |
388 | do \ | |
389 | { \ | |
390 | TYPE ret; \ | |
391 | \ | |
392 | ret = (TYPE) (fma ## SUFFIX ((X), (Y), (Z))); \ | |
393 | CHECK_NARROW_FMA (ret, (X), (Y), (Z)); \ | |
394 | return ret; \ | |
395 | } \ | |
396 | while (0) | |
397 | ||
63716ab2 | 398 | #endif /* math-narrow.h. */ |