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 
45 static const char *
e_to_str(int e)46 e_to_str(int e)
47 {
48 	if (e == 0)
49 		return "NONE";
50 
51 #ifdef FE_DIVBYZERO
52 	if (e == FE_DIVBYZERO)
53 		return "FE_DIVBYZERO";
54 #endif
55 #ifdef FE_OVERFLOW
56 	if (e == FE_OVERFLOW)
57 		return "FE_OVERFLOW";
58 #endif
59 #ifdef FE_UNDERFLOW
60 	if (e == FE_UNDERFLOW)
61 		return "FE_UNDERFLOW";
62 #endif
63 #ifdef FE_INEXACT
64 	if (e == FE_INEXACT)
65 		return "FE_INEXACT";
66 #endif
67 #ifdef FE_INVALID
68 	if (e == FE_INVALID)
69 		return "FE_INVALID";
70 #endif
71 #if defined(FE_OVERFLOW) && defined(FE_INEXACT)
72 	if (e == (FE_OVERFLOW|FE_INEXACT))
73 		return "FE_OVERFLOW|FE_INEXACT";
74 #endif
75 #if defined(FE_UNDERFLOW) && defined(FE_INEXACT)
76 	if (e == (FE_UNDERFLOW|FE_INEXACT))
77 		return "FE_UNDERFLOW|FE_INEXACT";
78 #endif
79 	static char buf[3][128];
80         static int i = 0;
81         buf[i][0] = '\0';
82         while (e) {
83             char *v = NULL;
84             char tmp[24];
85 #ifdef FE_DIVBYZERO
86             if (e & FE_DIVBYZERO) {
87 		v = "FE_DIVBYZERO";
88                 e &= ~FE_DIVBYZERO;
89             } else
90 #endif
91 #ifdef FE_OVERFLOW
92             if (e & FE_OVERFLOW) {
93 		v = "FE_OVERFLOW";
94                 e &= ~FE_OVERFLOW;
95             } else
96 #endif
97 #ifdef FE_UNDERFLOW
98             if (e & FE_UNDERFLOW) {
99 		v = "FE_UNDERFLOW";
100                 e &= ~FE_UNDERFLOW;
101             } else
102 #endif
103 #ifdef FE_INEXACT
104             if (e & FE_INEXACT) {
105 		v = "FE_INEXACT";
106                 e &= ~FE_INEXACT;
107             } else
108 #endif
109 #ifdef FE_INVALID
110             if (e & FE_INVALID) {
111 		v = "FE_INVALID";
112                 e &= ~FE_INVALID;
113             } else
114 #endif
115             {
116                 snprintf(tmp, sizeof(tmp), "?? 0x%x", e);
117                 v = tmp;
118                 e = 0;
119             }
120 #define check_add(s) do {                                               \
121                 if (strlen(buf[i]) + strlen(s) + 1 > sizeof(buf[i]))    \
122                     printf("exception buf overflow %s + %s\n", buf[i], s); \
123                 else                                                    \
124                     strcat(buf[i], s);                                  \
125             } while(0)
126             if (buf[i][0])
127                 check_add(" | ");
128             check_add(v);
129         }
130         char *ret = buf[i];
131         i = (i + 1) % 3;
132         return ret;
133 }
134 
135 #define scat(a,b) a ## b
136 
137 /* Tests with long doubles */
138 #ifdef __SIZEOF_LONG_DOUBLE__
139 
140 #if defined(__PICOLIBC__) && !defined(_HAVE_LONG_DOUBLE_MATH)
141 #define SIMPLE_MATH_ONLY
142 #define NO_NEXTTOWARD
143 #endif
144 
145 #ifdef PICOLIBC_LONG_DOUBLE_NOEXCEPT
146 #define EXCEPTION_TEST 0
147 #else
148 #define EXCEPTION_TEST	MATH_ERREXCEPT
149 #endif
150 #define LONG_DOUBLE_EXCEPTION_TEST EXCEPTION_TEST
151 #ifdef _M_PI_L
152 #define PI_VAL _M_PI_L
153 #else
154 #define PI_VAL  3.141592653589793238462643383279502884L
155 #endif
156 
157 #ifdef __PICOLIBC__
158 #define NO_BESSEL_TESTS
159 #endif
160 
161 #define _PASTE_LDBL(exp) 0x.fp ## exp ## L
162 #define PASTE_LDBL(exp) _PASTE_LDBL(exp)
163 
164 #define BIG PASTE_LDBL(__LDBL_MAX_EXP__)
165 #if __LDBL_MANT_DIG__ >= 64
166 #define BIGODD  0x1.123456789abcdef2p+63l
167 #define BIGEVEN 0x1.123456789abcdef0p+63l
168 #else
169 #define BIGODD  0x1.123456789abcdp+52
170 #define BIGEVEN 0x1.123456789abccp+52
171 #endif
172 #define SMALL __LDBL_DENORM_MIN__
173 #define FLOAT_T long double
174 #define MIN_VAL __LDBL_DENORM_MIN__
175 #define MAX_VAL __LDBL_MAX__
176 #define EPSILON_VAL __LDBL_EPSILON__
177 #define sNAN __builtin_nansl("")
178 
179 #define TEST_LONG_DOUBLE
180 
181 #define makemathname(s) scat(s,l)
182 #define makemathname_r(s) scat(s,l_r)
183 
184 #include "math_errhandling_tests.c"
185 
186 #undef BIG
187 #undef BIGODD
188 #undef BIGEVEN
189 #undef SMALL
190 #undef MIN_VAL
191 #undef MAX_VAL
192 #undef EPSILON_VAL
193 #undef sNAN
194 #undef makemathname
195 #undef makemathname_r
196 #undef FLOAT_T
197 #undef EXCEPTION_TEST
198 #undef TEST_LONG_DOUBLE
199 #undef NO_BESSEL_TESTS
200 #undef PI_VAL
201 #undef SIMPLE_MATH_ONLY
202 #endif
203 
204 /* Tests with doubles */
205 #ifdef PICOLIBC_DOUBLE_NOEXCEPT
206 #define EXCEPTION_TEST 0
207 #else
208 #define EXCEPTION_TEST	MATH_ERREXCEPT
209 #endif
210 #define DOUBLE_EXCEPTION_TEST EXCEPTION_TEST
211 
212 #define BIG 1.7e308
213 #define BIGODD  0x1.123456789abcdp+52
214 #define BIGEVEN 0x1.123456789abccp+52
215 #define SMALL 5e-324
216 #define FLOAT_T double
217 #define MIN_VAL __DBL_DENORM_MIN__
218 #define MAX_VAL __DBL_MAX__
219 #define EPSILON_VAL __DBL_EPSILON__
220 #define sNAN __builtin_nans("")
221 #define PI_VAL M_PI
222 
223 #define TEST_DOUBLE
224 
225 #define makemathname(s) s
226 #define makemathname_r(s) scat(s,_r)
227 
228 #include "math_errhandling_tests.c"
229 
230 #undef BIG
231 #undef BIGODD
232 #undef BIGEVEN
233 #undef SMALL
234 #undef MIN_VAL
235 #undef MAX_VAL
236 #undef EPSILON_VAL
237 #undef sNAN
238 #undef makemathname
239 #undef makemathname_r
240 #undef FLOAT_T
241 #undef EXCEPTION_TEST
242 #undef TEST_DOUBLE
243 #undef PI_VAL
244 
245 /* Tests with floats */
246 #define EXCEPTION_TEST	MATH_ERREXCEPT
247 #define BIG 3e38
248 #define BIGODD  0x1.123456p+23
249 #define BIGEVEN 0x1.123454p+23
250 #define SMALL 1e-45
251 #define MIN_VAL 0x8p-152f
252 #define MAX_VAL 0xf.fffffp+124f
253 #define EPSILON_VAL 0x1p-23f
254 #define sNAN __builtin_nansf("")
255 #define FLOAT_T float
256 #define TEST_FLOAT
257 #define makemathname(s) scat(s,f)
258 #define makemathname_r(s) scat(s,f_r)
259 #define PI_VAL ((float) M_PI)
260 
261 #include "math_errhandling_tests.c"
262 
main(void)263 int main(void)
264 {
265 	int result = 0;
266 
267 #if DOUBLE_EXCEPTION_TEST
268 	printf("Double tests:\n");
269 	result += run_tests();
270 #endif
271 #ifdef LONG_DOUBLE_EXCEPTION_TEST
272 	printf("Long double tests:\n");
273 	result += run_testsl();
274 #endif
275 	printf("Float tests:\n");
276 	result += run_testsf();
277 	return result;
278 }
279