1 /* Helper macros for functions returning a narrower type.
2 Copyright (C) 2018-2024 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 <https://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-barriers.h>
28 #include <math_private.h>
29 #include <fenv_private.h>
30 #include <math-narrow-alias.h>
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
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
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) \
54 libc_feholdexcept_setround ## SUFFIX (&env, FE_TOWARDZERO); \
56 math_force_eval (u.d); \
57 if (CLEAR_UNDERFLOW) \
58 feclearexcept (FE_UNDERFLOW); \
60 |= libc_feupdateenv_test ## SUFFIX (&env, FE_INEXACT) != 0; \
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
69 #define CHECK_NARROW_ADD(RET, X, Y) \
72 if (!isfinite (RET)) \
76 if (!isnan (X) && !isnan (Y)) \
79 else if (isfinite (X) && isfinite (Y)) \
80 __set_errno (ERANGE); \
82 else if ((RET) == 0 && (X) != -(Y)) \
83 __set_errno (ERANGE); \
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) \
95 /* Ensure a zero result is computed in the original rounding \
98 ret = (TYPE) ((X) + (Y)); \
100 ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) + (Y), \
101 UNION, SUFFIX, MANTISSA, false); \
103 CHECK_NARROW_ADD (ret, (X), (Y)); \
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) \
117 ret = (TYPE) ((X) + (Y)); \
118 CHECK_NARROW_ADD (ret, (X), (Y)); \
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) \
130 if (!isfinite (RET)) \
134 if (!isnan (X) && !isnan (Y)) \
135 __set_errno (EDOM); \
137 else if (isfinite (X) && isfinite (Y)) \
138 __set_errno (ERANGE); \
140 else if ((RET) == 0 && (X) != (Y)) \
141 __set_errno (ERANGE); \
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) \
153 /* Ensure a zero result is computed in the original rounding \
156 ret = (TYPE) ((X) - (Y)); \
158 ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) - (Y), \
159 UNION, SUFFIX, MANTISSA, false); \
161 CHECK_NARROW_SUB (ret, (X), (Y)); \
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) \
175 ret = (TYPE) ((X) - (Y)); \
176 CHECK_NARROW_SUB (ret, (X), (Y)); \
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) \
188 if (!isfinite (RET)) \
192 if (!isnan (X) && !isnan (Y)) \
193 __set_errno (EDOM); \
195 else if (isfinite (X) && isfinite (Y)) \
196 __set_errno (ERANGE); \
198 else if ((RET) == 0 && (X) != 0 && (Y) != 0) \
199 __set_errno (ERANGE); \
203 /* Implement narrowing multiply using round-to-odd. The arguments are
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, \
212 ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) * (Y), \
213 UNION, SUFFIX, MANTISSA, \
216 CHECK_NARROW_MUL (ret, (X), (Y)); \
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) \
230 ret = (TYPE) ((X) * (Y)); \
231 CHECK_NARROW_MUL (ret, (X), (Y)); \
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) \
243 if (!isfinite (RET)) \
247 if (!isnan (X) && !isnan (Y)) \
248 __set_errno (EDOM); \
250 else if (isfinite (X)) \
251 __set_errno (ERANGE); \
253 else if ((RET) == 0 && (X) != 0 && !isinf (Y)) \
254 __set_errno (ERANGE); \
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, \
267 ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) / (Y), \
268 UNION, SUFFIX, MANTISSA, \
271 CHECK_NARROW_DIV (ret, (X), (Y)); \
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) \
285 ret = (TYPE) ((X) / (Y)); \
286 CHECK_NARROW_DIV (ret, (X), (Y)); \
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) \
298 if (!isfinite (RET)) \
303 __set_errno (EDOM); \
305 else if (isfinite (X)) \
306 __set_errno (ERANGE); \
308 else if ((RET) == 0 && (X) != 0) \
309 __set_errno (ERANGE); \
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
316 #define NARROW_SQRT_ROUND_TO_ODD(X, TYPE, UNION, SUFFIX, MANTISSA) \
321 ret = (TYPE) ROUND_TO_ODD (sqrt ## SUFFIX (math_opt_barrier (X)), \
322 UNION, SUFFIX, MANTISSA, false); \
324 CHECK_NARROW_SQRT (ret, (X)); \
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) \
339 ret = (TYPE) (sqrt ## SUFFIX (X)); \
340 CHECK_NARROW_SQRT (ret, (X)); \
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
350 #define CHECK_NARROW_FMA(RET, X, Y, Z) \
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, \
366 tmp = ROUND_TO_ODD (fma ## SUFFIX (math_opt_barrier (X), (Y), \
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. */ \
372 ret = (TYPE) (math_opt_barrier (X) * (Y) + (Z)); \
376 CHECK_NARROW_FMA (ret, (X), (Y), (Z)); \
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
387 #define NARROW_FMA_TRIVIAL(X, Y, Z, TYPE, SUFFIX) \
392 ret = (TYPE) (fma ## SUFFIX ((X), (Y), (Z))); \
393 CHECK_NARROW_FMA (ret, (X), (Y), (Z)); \
398 #endif /* math-narrow.h. */