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.
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.
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.
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/>. */
19 #ifndef _MATH_NARROW_H
20 #define _MATH_NARROW_H 1
22 #include <bits/floatn.h>
23 #include <bits/long-double.h>
27 #include <math_private.h>
29 /* Carry out a computation using round-to-odd. The computation is
30 EXPR; the union type in which to store the result is UNION and the
31 subfield of the "ieee" field of that union with the low part of the
32 mantissa is MANTISSA; SUFFIX is the suffix for the libc_fe* macros
33 to ensure that the correct rounding mode is used, for platforms
34 with multiple rounding modes where those macros set only the
35 relevant mode. This macro does not work correctly if the sign of
36 an exact zero result depends on the rounding mode, so that case
37 must be checked for separately. */
38 #define ROUND_TO_ODD(EXPR, UNION, SUFFIX, MANTISSA) \
43 libc_feholdexcept_setround ## SUFFIX (&env, FE_TOWARDZERO); \
45 math_force_eval (u.d); \
47 |= libc_feupdateenv_test ## SUFFIX (&env, FE_INEXACT) != 0; \
52 /* Check for error conditions from a narrowing add function returning
53 RET with arguments X and Y and set errno as needed. Overflow and
54 underflow can occur for finite arguments and a domain error for
56 #define CHECK_NARROW_ADD(RET, X, Y) \
59 if (!isfinite (RET)) \
63 if (!isnan (X) && !isnan (Y)) \
66 else if (isfinite (X) && isfinite (Y)) \
67 __set_errno (ERANGE); \
69 else if ((RET) == 0 && (X) != -(Y)) \
70 __set_errno (ERANGE); \
74 /* Implement narrowing add using round-to-odd. The arguments are X
75 and Y, the return type is TYPE and UNION, MANTISSA and SUFFIX are
76 as for ROUND_TO_ODD. */
77 #define NARROW_ADD_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA) \
82 /* Ensure a zero result is computed in the original rounding \
85 ret = (TYPE) ((X) + (Y)); \
87 ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) + (Y), \
88 UNION, SUFFIX, MANTISSA); \
90 CHECK_NARROW_ADD (ret, (X), (Y)); \
95 /* Implement a narrowing add function that is not actually narrowing
96 or where no attempt is made to be correctly rounding (the latter
97 only applies to IBM long double). The arguments are X and Y and
98 the return type is TYPE. */
99 #define NARROW_ADD_TRIVIAL(X, Y, TYPE) \
104 ret = (TYPE) ((X) + (Y)); \
105 CHECK_NARROW_ADD (ret, (X), (Y)); \
110 /* Check for error conditions from a narrowing subtract function
111 returning RET with arguments X and Y and set errno as needed.
112 Overflow and underflow can occur for finite arguments and a domain
113 error for infinite ones. */
114 #define CHECK_NARROW_SUB(RET, X, Y) \
117 if (!isfinite (RET)) \
121 if (!isnan (X) && !isnan (Y)) \
122 __set_errno (EDOM); \
124 else if (isfinite (X) && isfinite (Y)) \
125 __set_errno (ERANGE); \
127 else if ((RET) == 0 && (X) != (Y)) \
128 __set_errno (ERANGE); \
132 /* Implement narrowing subtract using round-to-odd. The arguments are
133 X and Y, the return type is TYPE and UNION, MANTISSA and SUFFIX are
134 as for ROUND_TO_ODD. */
135 #define NARROW_SUB_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA) \
140 /* Ensure a zero result is computed in the original rounding \
143 ret = (TYPE) ((X) - (Y)); \
145 ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) - (Y), \
146 UNION, SUFFIX, MANTISSA); \
148 CHECK_NARROW_SUB (ret, (X), (Y)); \
153 /* Implement a narrowing subtract function that is not actually
154 narrowing or where no attempt is made to be correctly rounding (the
155 latter only applies to IBM long double). The arguments are X and Y
156 and the return type is TYPE. */
157 #define NARROW_SUB_TRIVIAL(X, Y, TYPE) \
162 ret = (TYPE) ((X) - (Y)); \
163 CHECK_NARROW_SUB (ret, (X), (Y)); \
168 /* The following macros declare aliases for a narrowing function. The
169 sole argument is the base name of a family of functions, such as
170 "add". If any platform changes long double format after the
171 introduction of narrowing functions, in a way requiring symbol
172 versioning compatibility, additional variants of these macros will
175 #define libm_alias_float_double_main(func) \
176 weak_alias (__f ## func, f ## func) \
177 weak_alias (__f ## func, f32 ## func ## f64) \
178 weak_alias (__f ## func, f32 ## func ## f32x)
180 #ifdef NO_LONG_DOUBLE
181 # define libm_alias_float_double(func) \
182 libm_alias_float_double_main (func) \
183 weak_alias (__f ## func, f ## func ## l)
185 # define libm_alias_float_double(func) \
186 libm_alias_float_double_main (func)
189 #define libm_alias_float32x_float64_main(func) \
190 weak_alias (__f32x ## func ## f64, f32x ## func ## f64)
192 #ifdef NO_LONG_DOUBLE
193 # define libm_alias_float32x_float64(func) \
194 libm_alias_float32x_float64_main (func) \
195 weak_alias (__f32x ## func ## f64, d ## func ## l)
196 #elif defined __LONG_DOUBLE_MATH_OPTIONAL
197 # define libm_alias_float32x_float64(func) \
198 libm_alias_float32x_float64_main (func) \
199 weak_alias (__f32x ## func ## f64, __nldbl_d ## func ## l)
201 # define libm_alias_float32x_float64(func) \
202 libm_alias_float32x_float64_main (func)
205 #if __HAVE_FLOAT128 && !__HAVE_DISTINCT_FLOAT128
206 # define libm_alias_float_ldouble_f128(func) \
207 weak_alias (__f ## func ## l, f32 ## func ## f128)
208 # define libm_alias_double_ldouble_f128(func) \
209 weak_alias (__d ## func ## l, f32x ## func ## f128) \
210 weak_alias (__d ## func ## l, f64 ## func ## f128)
212 # define libm_alias_float_ldouble_f128(func)
213 # define libm_alias_double_ldouble_f128(func)
216 #if __HAVE_FLOAT64X_LONG_DOUBLE
217 # define libm_alias_float_ldouble_f64x(func) \
218 weak_alias (__f ## func ## l, f32 ## func ## f64x)
219 # define libm_alias_double_ldouble_f64x(func) \
220 weak_alias (__d ## func ## l, f32x ## func ## f64x) \
221 weak_alias (__d ## func ## l, f64 ## func ## f64x)
223 # define libm_alias_float_ldouble_f64x(func)
224 # define libm_alias_double_ldouble_f64x(func)
227 #define libm_alias_float_ldouble(func) \
228 weak_alias (__f ## func ## l, f ## func ## l) \
229 libm_alias_float_ldouble_f128 (func) \
230 libm_alias_float_ldouble_f64x (func)
232 #define libm_alias_double_ldouble(func) \
233 weak_alias (__d ## func ## l, d ## func ## l) \
234 libm_alias_double_ldouble_f128 (func) \
235 libm_alias_double_ldouble_f64x (func)
237 #define libm_alias_float64x_float128(func) \
238 weak_alias (__f64x ## func ## f128, f64x ## func ## f128)
240 #define libm_alias_float32_float128_main(func) \
241 weak_alias (__f32 ## func ## f128, f32 ## func ## f128)
243 #define libm_alias_float64_float128_main(func) \
244 weak_alias (__f64 ## func ## f128, f64 ## func ## f128) \
245 weak_alias (__f64 ## func ## f128, f32x ## func ## f128)
247 #if __HAVE_FLOAT64X_LONG_DOUBLE
248 # define libm_alias_float32_float128(func) \
249 libm_alias_float32_float128_main (func)
250 # define libm_alias_float64_float128(func) \
251 libm_alias_float64_float128_main (func)
253 # define libm_alias_float32_float128(func) \
254 libm_alias_float32_float128_main (func) \
255 weak_alias (__f32 ## func ## f128, f32 ## func ## f64x)
256 # define libm_alias_float64_float128(func) \
257 libm_alias_float64_float128_main (func) \
258 weak_alias (__f64 ## func ## f128, f64 ## func ## f64x) \
259 weak_alias (__f64 ## func ## f128, f32x ## func ## f64x)
262 #endif /* math-narrow.h. */