1 | /* Helper macros for functions returning a narrower type. |
2 | Copyright (C) 2018 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 | <http://www.gnu.org/licenses/>. */ |
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> |
27 | #include <math-barriers.h> |
28 | #include <math_private.h> |
29 | |
30 | /* Carry out a computation using round-to-odd. The computation is |
31 | EXPR; the union type in which to store the result is UNION and the |
32 | subfield of the "ieee" field of that union with the low part of the |
33 | mantissa is MANTISSA; SUFFIX is the suffix for the libc_fe* macros |
34 | to ensure that the correct rounding mode is used, for platforms |
35 | with multiple rounding modes where those macros set only the |
36 | relevant mode. This macro does not work correctly if the sign of |
37 | an exact zero result depends on the rounding mode, so that case |
38 | must be checked for separately. */ |
39 | #define ROUND_TO_ODD(EXPR, UNION, SUFFIX, MANTISSA) \ |
40 | ({ \ |
41 | fenv_t env; \ |
42 | UNION u; \ |
43 | \ |
44 | libc_feholdexcept_setround ## SUFFIX (&env, FE_TOWARDZERO); \ |
45 | u.d = (EXPR); \ |
46 | math_force_eval (u.d); \ |
47 | u.ieee.MANTISSA \ |
48 | |= libc_feupdateenv_test ## SUFFIX (&env, FE_INEXACT) != 0; \ |
49 | \ |
50 | u.d; \ |
51 | }) |
52 | |
53 | /* Check for error conditions from a narrowing add function returning |
54 | RET with arguments X and Y and set errno as needed. Overflow and |
55 | underflow can occur for finite arguments and a domain error for |
56 | infinite ones. */ |
57 | #define CHECK_NARROW_ADD(RET, X, Y) \ |
58 | do \ |
59 | { \ |
60 | if (!isfinite (RET)) \ |
61 | { \ |
62 | if (isnan (RET)) \ |
63 | { \ |
64 | if (!isnan (X) && !isnan (Y)) \ |
65 | __set_errno (EDOM); \ |
66 | } \ |
67 | else if (isfinite (X) && isfinite (Y)) \ |
68 | __set_errno (ERANGE); \ |
69 | } \ |
70 | else if ((RET) == 0 && (X) != -(Y)) \ |
71 | __set_errno (ERANGE); \ |
72 | } \ |
73 | while (0) |
74 | |
75 | /* Implement narrowing add using round-to-odd. The arguments are X |
76 | and Y, the return type is TYPE and UNION, MANTISSA and SUFFIX are |
77 | as for ROUND_TO_ODD. */ |
78 | #define NARROW_ADD_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA) \ |
79 | do \ |
80 | { \ |
81 | TYPE ret; \ |
82 | \ |
83 | /* Ensure a zero result is computed in the original rounding \ |
84 | mode. */ \ |
85 | if ((X) == -(Y)) \ |
86 | ret = (TYPE) ((X) + (Y)); \ |
87 | else \ |
88 | ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) + (Y), \ |
89 | UNION, SUFFIX, MANTISSA); \ |
90 | \ |
91 | CHECK_NARROW_ADD (ret, (X), (Y)); \ |
92 | return ret; \ |
93 | } \ |
94 | while (0) |
95 | |
96 | /* Implement a narrowing add function that is not actually narrowing |
97 | or where no attempt is made to be correctly rounding (the latter |
98 | only applies to IBM long double). The arguments are X and Y and |
99 | the return type is TYPE. */ |
100 | #define NARROW_ADD_TRIVIAL(X, Y, TYPE) \ |
101 | do \ |
102 | { \ |
103 | TYPE ret; \ |
104 | \ |
105 | ret = (TYPE) ((X) + (Y)); \ |
106 | CHECK_NARROW_ADD (ret, (X), (Y)); \ |
107 | return ret; \ |
108 | } \ |
109 | while (0) |
110 | |
111 | /* Check for error conditions from a narrowing subtract function |
112 | returning RET with arguments X and Y and set errno as needed. |
113 | Overflow and underflow can occur for finite arguments and a domain |
114 | error for infinite ones. */ |
115 | #define CHECK_NARROW_SUB(RET, X, Y) \ |
116 | do \ |
117 | { \ |
118 | if (!isfinite (RET)) \ |
119 | { \ |
120 | if (isnan (RET)) \ |
121 | { \ |
122 | if (!isnan (X) && !isnan (Y)) \ |
123 | __set_errno (EDOM); \ |
124 | } \ |
125 | else if (isfinite (X) && isfinite (Y)) \ |
126 | __set_errno (ERANGE); \ |
127 | } \ |
128 | else if ((RET) == 0 && (X) != (Y)) \ |
129 | __set_errno (ERANGE); \ |
130 | } \ |
131 | while (0) |
132 | |
133 | /* Implement narrowing subtract using round-to-odd. The arguments are |
134 | X and Y, the return type is TYPE and UNION, MANTISSA and SUFFIX are |
135 | as for ROUND_TO_ODD. */ |
136 | #define NARROW_SUB_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA) \ |
137 | do \ |
138 | { \ |
139 | TYPE ret; \ |
140 | \ |
141 | /* Ensure a zero result is computed in the original rounding \ |
142 | mode. */ \ |
143 | if ((X) == (Y)) \ |
144 | ret = (TYPE) ((X) - (Y)); \ |
145 | else \ |
146 | ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) - (Y), \ |
147 | UNION, SUFFIX, MANTISSA); \ |
148 | \ |
149 | CHECK_NARROW_SUB (ret, (X), (Y)); \ |
150 | return ret; \ |
151 | } \ |
152 | while (0) |
153 | |
154 | /* Implement a narrowing subtract function that is not actually |
155 | narrowing or where no attempt is made to be correctly rounding (the |
156 | latter only applies to IBM long double). The arguments are X and Y |
157 | and the return type is TYPE. */ |
158 | #define NARROW_SUB_TRIVIAL(X, Y, TYPE) \ |
159 | do \ |
160 | { \ |
161 | TYPE ret; \ |
162 | \ |
163 | ret = (TYPE) ((X) - (Y)); \ |
164 | CHECK_NARROW_SUB (ret, (X), (Y)); \ |
165 | return ret; \ |
166 | } \ |
167 | while (0) |
168 | |
169 | /* Check for error conditions from a narrowing multiply function |
170 | returning RET with arguments X and Y and set errno as needed. |
171 | Overflow and underflow can occur for finite arguments and a domain |
172 | error for Inf * 0. */ |
173 | #define CHECK_NARROW_MUL(RET, X, Y) \ |
174 | do \ |
175 | { \ |
176 | if (!isfinite (RET)) \ |
177 | { \ |
178 | if (isnan (RET)) \ |
179 | { \ |
180 | if (!isnan (X) && !isnan (Y)) \ |
181 | __set_errno (EDOM); \ |
182 | } \ |
183 | else if (isfinite (X) && isfinite (Y)) \ |
184 | __set_errno (ERANGE); \ |
185 | } \ |
186 | else if ((RET) == 0 && (X) != 0 && (Y) != 0) \ |
187 | __set_errno (ERANGE); \ |
188 | } \ |
189 | while (0) |
190 | |
191 | /* Implement narrowing multiply using round-to-odd. The arguments are |
192 | X and Y, the return type is TYPE and UNION, MANTISSA and SUFFIX are |
193 | as for ROUND_TO_ODD. */ |
194 | #define NARROW_MUL_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA) \ |
195 | do \ |
196 | { \ |
197 | TYPE ret; \ |
198 | \ |
199 | ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) * (Y), \ |
200 | UNION, SUFFIX, MANTISSA); \ |
201 | \ |
202 | CHECK_NARROW_MUL (ret, (X), (Y)); \ |
203 | return ret; \ |
204 | } \ |
205 | while (0) |
206 | |
207 | /* Implement a narrowing multiply function that is not actually |
208 | narrowing or where no attempt is made to be correctly rounding (the |
209 | latter only applies to IBM long double). The arguments are X and Y |
210 | and the return type is TYPE. */ |
211 | #define NARROW_MUL_TRIVIAL(X, Y, TYPE) \ |
212 | do \ |
213 | { \ |
214 | TYPE ret; \ |
215 | \ |
216 | ret = (TYPE) ((X) * (Y)); \ |
217 | CHECK_NARROW_MUL (ret, (X), (Y)); \ |
218 | return ret; \ |
219 | } \ |
220 | while (0) |
221 | |
222 | /* Check for error conditions from a narrowing divide function |
223 | returning RET with arguments X and Y and set errno as needed. |
224 | Overflow, underflow and divide-by-zero can occur for finite |
225 | arguments and a domain error for Inf / Inf and 0 / 0. */ |
226 | #define CHECK_NARROW_DIV(RET, X, Y) \ |
227 | do \ |
228 | { \ |
229 | if (!isfinite (RET)) \ |
230 | { \ |
231 | if (isnan (RET)) \ |
232 | { \ |
233 | if (!isnan (X) && !isnan (Y)) \ |
234 | __set_errno (EDOM); \ |
235 | } \ |
236 | else if (isfinite (X)) \ |
237 | __set_errno (ERANGE); \ |
238 | } \ |
239 | else if ((RET) == 0 && (X) != 0 && !isinf (Y)) \ |
240 | __set_errno (ERANGE); \ |
241 | } \ |
242 | while (0) |
243 | |
244 | /* Implement narrowing divide using round-to-odd. The arguments are |
245 | X and Y, the return type is TYPE and UNION, MANTISSA and SUFFIX are |
246 | as for ROUND_TO_ODD. */ |
247 | #define NARROW_DIV_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA) \ |
248 | do \ |
249 | { \ |
250 | TYPE ret; \ |
251 | \ |
252 | ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) / (Y), \ |
253 | UNION, SUFFIX, MANTISSA); \ |
254 | \ |
255 | CHECK_NARROW_DIV (ret, (X), (Y)); \ |
256 | return ret; \ |
257 | } \ |
258 | while (0) |
259 | |
260 | /* Implement a narrowing divide function that is not actually |
261 | narrowing or where no attempt is made to be correctly rounding (the |
262 | latter only applies to IBM long double). The arguments are X and Y |
263 | and the return type is TYPE. */ |
264 | #define NARROW_DIV_TRIVIAL(X, Y, TYPE) \ |
265 | do \ |
266 | { \ |
267 | TYPE ret; \ |
268 | \ |
269 | ret = (TYPE) ((X) / (Y)); \ |
270 | CHECK_NARROW_DIV (ret, (X), (Y)); \ |
271 | return ret; \ |
272 | } \ |
273 | while (0) |
274 | |
275 | /* The following macros declare aliases for a narrowing function. The |
276 | sole argument is the base name of a family of functions, such as |
277 | "add". If any platform changes long double format after the |
278 | introduction of narrowing functions, in a way requiring symbol |
279 | versioning compatibility, additional variants of these macros will |
280 | be needed. */ |
281 | |
282 | #define libm_alias_float_double_main(func) \ |
283 | weak_alias (__f ## func, f ## func) \ |
284 | weak_alias (__f ## func, f32 ## func ## f64) \ |
285 | weak_alias (__f ## func, f32 ## func ## f32x) |
286 | |
287 | #ifdef NO_LONG_DOUBLE |
288 | # define libm_alias_float_double(func) \ |
289 | libm_alias_float_double_main (func) \ |
290 | weak_alias (__f ## func, f ## func ## l) |
291 | #else |
292 | # define libm_alias_float_double(func) \ |
293 | libm_alias_float_double_main (func) |
294 | #endif |
295 | |
296 | #define libm_alias_float32x_float64_main(func) \ |
297 | weak_alias (__f32x ## func ## f64, f32x ## func ## f64) |
298 | |
299 | #ifdef NO_LONG_DOUBLE |
300 | # define libm_alias_float32x_float64(func) \ |
301 | libm_alias_float32x_float64_main (func) \ |
302 | weak_alias (__f32x ## func ## f64, d ## func ## l) |
303 | #elif defined __LONG_DOUBLE_MATH_OPTIONAL |
304 | # define libm_alias_float32x_float64(func) \ |
305 | libm_alias_float32x_float64_main (func) \ |
306 | weak_alias (__f32x ## func ## f64, __nldbl_d ## func ## l) |
307 | #else |
308 | # define libm_alias_float32x_float64(func) \ |
309 | libm_alias_float32x_float64_main (func) |
310 | #endif |
311 | |
312 | #if __HAVE_FLOAT128 && !__HAVE_DISTINCT_FLOAT128 |
313 | # define libm_alias_float_ldouble_f128(func) \ |
314 | weak_alias (__f ## func ## l, f32 ## func ## f128) |
315 | # define libm_alias_double_ldouble_f128(func) \ |
316 | weak_alias (__d ## func ## l, f32x ## func ## f128) \ |
317 | weak_alias (__d ## func ## l, f64 ## func ## f128) |
318 | #else |
319 | # define libm_alias_float_ldouble_f128(func) |
320 | # define libm_alias_double_ldouble_f128(func) |
321 | #endif |
322 | |
323 | #if __HAVE_FLOAT64X_LONG_DOUBLE |
324 | # define libm_alias_float_ldouble_f64x(func) \ |
325 | weak_alias (__f ## func ## l, f32 ## func ## f64x) |
326 | # define libm_alias_double_ldouble_f64x(func) \ |
327 | weak_alias (__d ## func ## l, f32x ## func ## f64x) \ |
328 | weak_alias (__d ## func ## l, f64 ## func ## f64x) |
329 | #else |
330 | # define libm_alias_float_ldouble_f64x(func) |
331 | # define libm_alias_double_ldouble_f64x(func) |
332 | #endif |
333 | |
334 | #define libm_alias_float_ldouble(func) \ |
335 | weak_alias (__f ## func ## l, f ## func ## l) \ |
336 | libm_alias_float_ldouble_f128 (func) \ |
337 | libm_alias_float_ldouble_f64x (func) |
338 | |
339 | #define libm_alias_double_ldouble(func) \ |
340 | weak_alias (__d ## func ## l, d ## func ## l) \ |
341 | libm_alias_double_ldouble_f128 (func) \ |
342 | libm_alias_double_ldouble_f64x (func) |
343 | |
344 | #define libm_alias_float64x_float128(func) \ |
345 | weak_alias (__f64x ## func ## f128, f64x ## func ## f128) |
346 | |
347 | #define libm_alias_float32_float128_main(func) \ |
348 | weak_alias (__f32 ## func ## f128, f32 ## func ## f128) |
349 | |
350 | #define libm_alias_float64_float128_main(func) \ |
351 | weak_alias (__f64 ## func ## f128, f64 ## func ## f128) \ |
352 | weak_alias (__f64 ## func ## f128, f32x ## func ## f128) |
353 | |
354 | #if __HAVE_FLOAT64X_LONG_DOUBLE |
355 | # define libm_alias_float32_float128(func) \ |
356 | libm_alias_float32_float128_main (func) |
357 | # define libm_alias_float64_float128(func) \ |
358 | libm_alias_float64_float128_main (func) |
359 | #else |
360 | # define libm_alias_float32_float128(func) \ |
361 | libm_alias_float32_float128_main (func) \ |
362 | weak_alias (__f32 ## func ## f128, f32 ## func ## f64x) |
363 | # define libm_alias_float64_float128(func) \ |
364 | libm_alias_float64_float128_main (func) \ |
365 | weak_alias (__f64 ## func ## f128, f64 ## func ## f64x) \ |
366 | weak_alias (__f64 ## func ## f128, f32x ## func ## f64x) |
367 | #endif |
368 | |
369 | #endif /* math-narrow.h. */ |
370 | |