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