1 /*
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright © 2020 Keith Packard
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above
14  *    copyright notice, this list of conditions and the following
15  *    disclaimer in the documentation and/or other materials provided
16  *    with the distribution.
17  *
18  * 3. Neither the name of the copyright holder nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33  * OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #define _GNU_SOURCE
37 #include <fenv.h>
38 #include <math.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <errno.h>
43 #include <limits.h>
44 #include <stdbool.h>
45 
46 #ifdef _HAVE_ATTRIBUTE_ALWAYS_INLINE
47 #define ALWAYS_INLINE __inline__ __attribute__((__always_inline__))
48 #else
49 #define ALWAYS_INLINE __inline__
50 #endif
51 
52 static ALWAYS_INLINE float
opt_barrier_float(float x)53 opt_barrier_float (float x)
54 {
55   volatile float y = x;
56   return y;
57 }
58 
59 static ALWAYS_INLINE double
opt_barrier_double(double x)60 opt_barrier_double (double x)
61 {
62   volatile double y = x;
63   return y;
64 }
65 
66 #if __SIZEOF_LONG_DOUBLE__ > 0
67 static ALWAYS_INLINE long double
opt_barrier_long_double(long double x)68 opt_barrier_long_double (long double x)
69 {
70   volatile long double y = x;
71   return y;
72 }
73 #endif
74 
75 #ifdef __clang__
76 #define clang_barrier_long_double(x) opt_barrier_long_double(x)
77 #define clang_barrier_double(x) opt_barrier_double(x)
78 #define clang_barrier_float(x) opt_barrier_float(x)
79 #else
80 #define clang_barrier_long_double(x) (x)
81 #define clang_barrier_double(x) (x)
82 #define clang_barrier_float(x) (x)
83 #endif
84 
85 static const char *
e_to_str(int e)86 e_to_str(int e)
87 {
88 	if (e == 0)
89 		return "NONE";
90 
91 #ifdef FE_DIVBYZERO
92 	if (e == FE_DIVBYZERO)
93 		return "FE_DIVBYZERO";
94 #endif
95 #ifdef FE_OVERFLOW
96 	if (e == FE_OVERFLOW)
97 		return "FE_OVERFLOW";
98 #endif
99 #ifdef FE_UNDERFLOW
100 	if (e == FE_UNDERFLOW)
101 		return "FE_UNDERFLOW";
102 #endif
103 #ifdef FE_INEXACT
104 	if (e == FE_INEXACT)
105 		return "FE_INEXACT";
106 #endif
107 #ifdef FE_INVALID
108 	if (e == FE_INVALID)
109 		return "FE_INVALID";
110 #endif
111 #if defined(FE_OVERFLOW) && defined(FE_INEXACT)
112 	if (e == (FE_OVERFLOW|FE_INEXACT))
113 		return "FE_OVERFLOW|FE_INEXACT";
114 #endif
115 #if defined(FE_UNDERFLOW) && defined(FE_INEXACT)
116 	if (e == (FE_UNDERFLOW|FE_INEXACT))
117 		return "FE_UNDERFLOW|FE_INEXACT";
118 #endif
119 	static char buf[3][128];
120         static int i = 0;
121         buf[i][0] = '\0';
122         while (e) {
123             char *v = NULL;
124             char tmp[24];
125 #ifdef FE_DIVBYZERO
126             if (e & FE_DIVBYZERO) {
127 		v = "FE_DIVBYZERO";
128                 e &= ~FE_DIVBYZERO;
129             } else
130 #endif
131 #ifdef FE_OVERFLOW
132             if (e & FE_OVERFLOW) {
133 		v = "FE_OVERFLOW";
134                 e &= ~FE_OVERFLOW;
135             } else
136 #endif
137 #ifdef FE_UNDERFLOW
138             if (e & FE_UNDERFLOW) {
139 		v = "FE_UNDERFLOW";
140                 e &= ~FE_UNDERFLOW;
141             } else
142 #endif
143 #ifdef FE_INEXACT
144             if (e & FE_INEXACT) {
145 		v = "FE_INEXACT";
146                 e &= ~FE_INEXACT;
147             } else
148 #endif
149 #ifdef FE_INVALID
150             if (e & FE_INVALID) {
151 		v = "FE_INVALID";
152                 e &= ~FE_INVALID;
153             } else
154 #endif
155             {
156                 snprintf(tmp, sizeof(tmp), "?? 0x%x", e);
157                 v = tmp;
158                 e = 0;
159             }
160 #define check_add(s) do {                                               \
161                 if (strlen(buf[i]) + strlen(s) + 1 > sizeof(buf[i]))    \
162                     printf("exception buf overflow %s + %s\n", buf[i], s); \
163                 else                                                    \
164                     strcat(buf[i], s);                                  \
165             } while(0)
166             if (buf[i][0])
167                 check_add(" | ");
168             check_add(v);
169         }
170         char *ret = buf[i];
171         i = (i + 1) % 3;
172         return ret;
173 }
174 
175 #define scat(a,b) a ## b
176 
177 #ifdef __mcffpu__
178 #define SKIP_SNAN_CHECKS
179 #endif
180 
181 #ifdef __HAVE_68881__
182 #define SKIP_SNAN_CHECKS
183 #endif
184 
185 #if defined(__m68k__) && !defined(__mcoldfire__) && !defined(__HAVE_M68881__)
186 #undef _TEST_LONG_DOUBLE
187 #define NO_NEXTTOWARD
188 #endif
189 
190 /* Tests with long doubles */
191 #ifdef _TEST_LONG_DOUBLE
192 
193 #if defined(__PICOLIBC__) && !defined(_HAVE_LONG_DOUBLE_MATH)
194 #define SIMPLE_MATH_ONLY
195 #define NO_NEXTTOWARD
196 #endif
197 
198 #ifdef PICOLIBC_LONG_DOUBLE_NOEXCEPT
199 #define EXCEPTION_TEST 0
200 #else
201 #define EXCEPTION_TEST	MATH_ERREXCEPT
202 #endif
203 #define LONG_DOUBLE_EXCEPTION_TEST EXCEPTION_TEST
204 #ifdef _M_PI_L
205 #define PI_VAL _M_PI_L
206 #else
207 #define PI_VAL  3.141592653589793238462643383279502884L
208 #endif
209 
210 #ifdef __PICOLIBC__
211 #define NO_BESSEL_TESTS
212 #endif
213 
214 #define _PASTE_LDBL(exp) 0x.fp ## exp ## L
215 #define PASTE_LDBL(exp) _PASTE_LDBL(exp)
216 
217 #define BIG PASTE_LDBL(__LDBL_MAX_EXP__)
218 #if __LDBL_MANT_DIG__ >= 64
219 #define BIGODD  0x1.123456789abcdef2p+63l
220 #define BIGEVEN 0x1.123456789abcdef0p+63l
221 #else
222 #define BIGODD  0x1.123456789abcdp+52l
223 #define BIGEVEN 0x1.123456789abccp+52l
224 #endif
225 #define SMALL __LDBL_DENORM_MIN__
226 #define FLOAT_T long double
227 #define MIN_VAL __LDBL_DENORM_MIN__
228 #define MAX_VAL __LDBL_MAX__
229 #define MANT_DIG __LDBL_MANT_DIG__
230 #define EPSILON_VAL __LDBL_EPSILON__
231 #define sNAN __builtin_nansl("")
232 #define force_eval(x) clang_barrier_long_double(x)
233 
234 #define TEST_LONG_DOUBLE
235 
236 #define makemathname(s) scat(s,l)
237 #define makemathname_r(s) scat(s,l_r)
238 
239 #include "math_errhandling_tests.c"
240 
241 #undef BIG
242 #undef BIGODD
243 #undef BIGEVEN
244 #undef SMALL
245 #undef MIN_VAL
246 #undef MAX_VAL
247 #undef MANT_DIG
248 #undef EPSILON_VAL
249 #undef force_eval
250 #undef sNAN
251 #undef makemathname
252 #undef makemathname_r
253 #undef FLOAT_T
254 #undef EXCEPTION_TEST
255 #undef TEST_LONG_DOUBLE
256 #undef NO_BESSEL_TESTS
257 #undef PI_VAL
258 #undef SIMPLE_MATH_ONLY
259 #endif
260 
261 /* Tests with doubles */
262 #ifdef PICOLIBC_DOUBLE_NOEXCEPT
263 #define EXCEPTION_TEST 0
264 #else
265 #define EXCEPTION_TEST	MATH_ERREXCEPT
266 #endif
267 #define DOUBLE_EXCEPTION_TEST EXCEPTION_TEST
268 
269 #if __SIZEOF_DOUBLE__ == 4
270 #define BIG 3e38
271 #define BIGODD  0x1.123456p+23
272 #define BIGEVEN 0x1.123454p+23
273 #define SMALL 1e-45
274 #else
275 #define BIG 1.7e308
276 #define BIGODD  0x1.123456789abcdp+52
277 #define BIGEVEN 0x1.123456789abccp+52
278 #define SMALL 5e-324
279 #endif
280 #define FLOAT_T double
281 #define MIN_VAL __DBL_DENORM_MIN__
282 #define MAX_VAL __DBL_MAX__
283 #define MANT_DIG __DBL_MANT_DIG__
284 #define EPSILON_VAL __DBL_EPSILON__
285 #define sNAN __builtin_nans("")
286 #define force_eval(x) clang_barrier_double(x)
287 #define PI_VAL M_PI
288 
289 #define TEST_DOUBLE
290 
291 #define makemathname(s) s
292 #define makemathname_r(s) scat(s,_r)
293 
294 #include "math_errhandling_tests.c"
295 
296 #undef BIG
297 #undef BIGODD
298 #undef BIGEVEN
299 #undef SMALL
300 #undef MIN_VAL
301 #undef MAX_VAL
302 #undef MANT_DIG
303 #undef EPSILON_VAL
304 #undef force_eval
305 #undef sNAN
306 #undef makemathname
307 #undef makemathname_r
308 #undef FLOAT_T
309 #undef EXCEPTION_TEST
310 #undef TEST_DOUBLE
311 #undef PI_VAL
312 
313 /* Tests with floats */
314 #define EXCEPTION_TEST	MATH_ERREXCEPT
315 #define BIG 3e38
316 #define BIGODD  0x1.123456p+23
317 #define BIGEVEN 0x1.123454p+23
318 #define SMALL 1e-45
319 #define MIN_VAL 0x8p-152f
320 #define MAX_VAL 0xf.fffffp+124f
321 #define MANT_DIG __FLT_MANT_DIG__
322 #define EPSILON_VAL 0x1p-23f
323 #define sNAN __builtin_nansf("")
324 #define force_eval(x) clang_barrier_float(x)
325 #define FLOAT_T float
326 #define TEST_FLOAT
327 #define makemathname(s) scat(s,f)
328 #define makemathname_r(s) scat(s,f_r)
329 #define PI_VAL ((float) M_PI)
330 
331 #include "math_errhandling_tests.c"
332 
main(void)333 int main(void)
334 {
335 	int result = 0;
336 
337 	printf("Double tests:\n");
338 	result += run_tests();
339 #ifdef _TEST_LONG_DOUBLE
340 	printf("Long double tests:\n");
341 #ifdef __m68k__
342         volatile long double zero = 0.0L;
343         volatile long double one = 1.0L;
344         volatile long double check = nextafterl(zero, one);
345         if (check + check == zero) {
346             printf("m68k emulating long double with double, skipping\n");
347         } else
348 #endif
349 	result += run_testsl();
350 #endif
351 	printf("Float tests:\n");
352 	result += run_testsf();
353 	return result;
354 }
355