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