Remove "Contributed by" lines
[platform/upstream/glibc.git] / math / math-narrow.h
1 /* Helper macros for functions returning a narrower type.
2    Copyright (C) 2018-2021 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    <https://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 #include <math-narrow-alias-float128.h>
356
357 #endif /* math-narrow.h.  */