t_fenv.c revision 1.8 1 1.8 riastrad /* $NetBSD: t_fenv.c,v 1.8 2023/11/05 15:28:17 riastradh Exp $ */
2 1.1 martin
3 1.1 martin /*-
4 1.1 martin * Copyright (c) 2014 The NetBSD Foundation, Inc.
5 1.1 martin * All rights reserved.
6 1.1 martin *
7 1.1 martin * This code is derived from software contributed to The NetBSD Foundation
8 1.1 martin * by Martin Husemann.
9 1.1 martin *
10 1.1 martin * Redistribution and use in source and binary forms, with or without
11 1.1 martin * modification, are permitted provided that the following conditions
12 1.1 martin * are met:
13 1.1 martin * 1. Redistributions of source code must retain the above copyright
14 1.1 martin * notice, this list of conditions and the following disclaimer.
15 1.1 martin * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 martin * notice, this list of conditions and the following disclaimer in the
17 1.1 martin * documentation and/or other materials provided with the distribution.
18 1.1 martin *
19 1.1 martin * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 martin * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 martin * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 martin * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 martin * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 martin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 martin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 martin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 martin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 martin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 martin * POSSIBILITY OF SUCH DAMAGE.
30 1.1 martin */
31 1.1 martin #include <sys/cdefs.h>
32 1.8 riastrad __RCSID("$NetBSD: t_fenv.c,v 1.8 2023/11/05 15:28:17 riastradh Exp $");
33 1.1 martin
34 1.1 martin #include <atf-c.h>
35 1.1 martin
36 1.3 christos #include <fenv.h>
37 1.3 christos #ifdef __HAVE_FENV
38 1.1 martin
39 1.8 riastrad #include <float.h>
40 1.1 martin #include <ieeefp.h>
41 1.1 martin #include <stdlib.h>
42 1.1 martin
43 1.1 martin
44 1.4 martin #if (__arm__ && !__SOFTFP__) || __aarch64__
45 1.1 martin /*
46 1.6 kamil * Some NEON fpus do not trap on IEEE 754 FP exceptions.
47 1.5 martin * Skip these tests if running on them and compiled for
48 1.1 martin * hard float.
49 1.1 martin */
50 1.2 martin #define FPU_EXC_PREREQ() \
51 1.1 martin if (0 == fpsetmask(fpsetmask(FP_X_INV))) \
52 1.5 martin atf_tc_skip("FPU does not implement traps on FP exceptions");
53 1.2 martin
54 1.2 martin /*
55 1.2 martin * Same as above: some don't allow configuring the rounding mode.
56 1.2 martin */
57 1.2 martin #define FPU_RND_PREREQ() \
58 1.2 martin if (0 == fpsetround(fpsetround(FP_RZ))) \
59 1.2 martin atf_tc_skip("FPU does not implement configurable " \
60 1.2 martin "rounding modes");
61 1.1 martin #endif
62 1.1 martin
63 1.2 martin #ifndef FPU_EXC_PREREQ
64 1.2 martin #define FPU_EXC_PREREQ() /* nothing */
65 1.2 martin #endif
66 1.2 martin #ifndef FPU_RND_PREREQ
67 1.2 martin #define FPU_RND_PREREQ() /* nothing */
68 1.1 martin #endif
69 1.1 martin
70 1.1 martin
71 1.8 riastrad static int
72 1.8 riastrad feround_to_fltrounds(int feround)
73 1.8 riastrad {
74 1.8 riastrad
75 1.8 riastrad /*
76 1.8 riastrad * C99, Sec. 5.2.4.2.2 Characteristics of floating types
77 1.8 riastrad * <float.h>, p. 24, clause 7
78 1.8 riastrad */
79 1.8 riastrad switch (feround) {
80 1.8 riastrad case FE_TOWARDZERO:
81 1.8 riastrad return 0;
82 1.8 riastrad case FE_TONEAREST:
83 1.8 riastrad return 1;
84 1.8 riastrad case FE_UPWARD:
85 1.8 riastrad return 2;
86 1.8 riastrad case FE_DOWNWARD:
87 1.8 riastrad return 3;
88 1.8 riastrad default:
89 1.8 riastrad return -1;
90 1.8 riastrad }
91 1.8 riastrad }
92 1.8 riastrad
93 1.8 riastrad static void
94 1.8 riastrad checkfltrounds(void)
95 1.8 riastrad {
96 1.8 riastrad int feround = fegetround();
97 1.8 riastrad int expected = feround_to_fltrounds(feround);
98 1.8 riastrad
99 1.8 riastrad ATF_CHECK_EQ_MSG(FLT_ROUNDS, expected,
100 1.8 riastrad "FLT_ROUNDS=%d expected=%d fegetround()=%d",
101 1.8 riastrad FLT_ROUNDS, expected, feround);
102 1.8 riastrad }
103 1.8 riastrad
104 1.1 martin ATF_TC(fegetround);
105 1.1 martin
106 1.1 martin ATF_TC_HEAD(fegetround, tc)
107 1.1 martin {
108 1.1 martin atf_tc_set_md_var(tc, "descr",
109 1.1 martin "verify the fegetround() function agrees with the legacy "
110 1.1 martin "fpsetround");
111 1.1 martin }
112 1.1 martin
113 1.1 martin ATF_TC_BODY(fegetround, tc)
114 1.1 martin {
115 1.2 martin FPU_RND_PREREQ();
116 1.2 martin
117 1.1 martin fpsetround(FP_RZ);
118 1.7 riastrad ATF_CHECK_EQ_MSG(fegetround(), FE_TOWARDZERO,
119 1.7 riastrad "fegetround()=%d FE_TOWARDZERO=%d",
120 1.7 riastrad fegetround(), FE_TOWARDZERO);
121 1.8 riastrad checkfltrounds();
122 1.8 riastrad
123 1.1 martin fpsetround(FP_RM);
124 1.7 riastrad ATF_CHECK_EQ_MSG(fegetround(), FE_DOWNWARD,
125 1.7 riastrad "fegetround()=%d FE_DOWNWARD=%d",
126 1.7 riastrad fegetround(), FE_DOWNWARD);
127 1.8 riastrad checkfltrounds();
128 1.8 riastrad
129 1.1 martin fpsetround(FP_RN);
130 1.7 riastrad ATF_CHECK_EQ_MSG(fegetround(), FE_TONEAREST,
131 1.7 riastrad "fegetround()=%d FE_TONEAREST=%d",
132 1.7 riastrad fegetround(), FE_TONEAREST);
133 1.8 riastrad checkfltrounds();
134 1.8 riastrad
135 1.1 martin fpsetround(FP_RP);
136 1.7 riastrad ATF_CHECK_EQ_MSG(fegetround(), FE_UPWARD,
137 1.7 riastrad "fegetround()=%d FE_UPWARD=%d",
138 1.7 riastrad fegetround(), FE_UPWARD);
139 1.8 riastrad checkfltrounds();
140 1.1 martin }
141 1.1 martin
142 1.1 martin ATF_TC(fesetround);
143 1.1 martin
144 1.1 martin ATF_TC_HEAD(fesetround, tc)
145 1.1 martin {
146 1.1 martin atf_tc_set_md_var(tc, "descr",
147 1.1 martin "verify the fesetround() function agrees with the legacy "
148 1.1 martin "fpgetround");
149 1.1 martin }
150 1.1 martin
151 1.1 martin ATF_TC_BODY(fesetround, tc)
152 1.1 martin {
153 1.2 martin FPU_RND_PREREQ();
154 1.2 martin
155 1.1 martin fesetround(FE_TOWARDZERO);
156 1.7 riastrad ATF_CHECK_EQ_MSG(fpgetround(), FP_RZ,
157 1.7 riastrad "fpgetround()=%d FP_RZ=%d",
158 1.7 riastrad (int)fpgetround(), (int)FP_RZ);
159 1.8 riastrad checkfltrounds();
160 1.8 riastrad
161 1.1 martin fesetround(FE_DOWNWARD);
162 1.7 riastrad ATF_CHECK_EQ_MSG(fpgetround(), FP_RM,
163 1.7 riastrad "fpgetround()=%d FP_RM=%d",
164 1.7 riastrad (int)fpgetround(), (int)FP_RM);
165 1.8 riastrad checkfltrounds();
166 1.8 riastrad
167 1.1 martin fesetround(FE_TONEAREST);
168 1.7 riastrad ATF_CHECK_EQ_MSG(fpgetround(), FP_RN,
169 1.7 riastrad "fpgetround()=%d FP_RN=%d",
170 1.7 riastrad (int)fpgetround(), (int)FP_RN);
171 1.8 riastrad checkfltrounds();
172 1.8 riastrad
173 1.1 martin fesetround(FE_UPWARD);
174 1.7 riastrad ATF_CHECK_EQ_MSG(fpgetround(), FP_RP,
175 1.7 riastrad "fpgetround()=%d FP_RP=%d",
176 1.7 riastrad (int)fpgetround(), (int)FP_RP);
177 1.8 riastrad checkfltrounds();
178 1.1 martin }
179 1.1 martin
180 1.1 martin ATF_TC(fegetexcept);
181 1.1 martin
182 1.1 martin ATF_TC_HEAD(fegetexcept, tc)
183 1.1 martin {
184 1.1 martin atf_tc_set_md_var(tc, "descr",
185 1.1 martin "verify the fegetexcept() function agrees with the legacy "
186 1.1 martin "fpsetmask()");
187 1.1 martin }
188 1.1 martin
189 1.1 martin ATF_TC_BODY(fegetexcept, tc)
190 1.1 martin {
191 1.2 martin FPU_EXC_PREREQ();
192 1.1 martin
193 1.1 martin fpsetmask(0);
194 1.7 riastrad ATF_CHECK_EQ_MSG(fegetexcept(), 0,
195 1.7 riastrad "fegetexcept()=%d",
196 1.7 riastrad fegetexcept());
197 1.1 martin
198 1.1 martin fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
199 1.1 martin ATF_CHECK(fegetexcept() == (FE_INVALID|FE_DIVBYZERO|FE_OVERFLOW
200 1.1 martin |FE_UNDERFLOW|FE_INEXACT));
201 1.1 martin
202 1.1 martin fpsetmask(FP_X_INV);
203 1.7 riastrad ATF_CHECK_EQ_MSG(fegetexcept(), FE_INVALID,
204 1.7 riastrad "fegetexcept()=%d FE_INVALID=%d",
205 1.7 riastrad fegetexcept(), FE_INVALID);
206 1.1 martin
207 1.1 martin fpsetmask(FP_X_DZ);
208 1.7 riastrad ATF_CHECK_EQ_MSG(fegetexcept(), FE_DIVBYZERO,
209 1.7 riastrad "fegetexcept()=%d FE_DIVBYZERO=%d",
210 1.7 riastrad fegetexcept(), FE_DIVBYZERO);
211 1.1 martin
212 1.1 martin fpsetmask(FP_X_OFL);
213 1.7 riastrad ATF_CHECK_EQ_MSG(fegetexcept(), FE_OVERFLOW,
214 1.7 riastrad "fegetexcept()=%d FE_OVERFLOW=%d",
215 1.7 riastrad fegetexcept(), FE_OVERFLOW);
216 1.1 martin
217 1.1 martin fpsetmask(FP_X_UFL);
218 1.7 riastrad ATF_CHECK_EQ_MSG(fegetexcept(), FE_UNDERFLOW,
219 1.7 riastrad "fegetexcept()=%d FE_UNDERFLOW=%d",
220 1.7 riastrad fegetexcept(), FE_UNDERFLOW);
221 1.1 martin
222 1.1 martin fpsetmask(FP_X_IMP);
223 1.7 riastrad ATF_CHECK_EQ_MSG(fegetexcept(), FE_INEXACT,
224 1.7 riastrad "fegetexcept()=%d FE_INEXACT=%d",
225 1.7 riastrad fegetexcept(), FE_INEXACT);
226 1.1 martin }
227 1.1 martin
228 1.1 martin ATF_TC(feenableexcept);
229 1.1 martin
230 1.1 martin ATF_TC_HEAD(feenableexcept, tc)
231 1.1 martin {
232 1.1 martin atf_tc_set_md_var(tc, "descr",
233 1.1 martin "verify the feenableexcept() function agrees with the legacy "
234 1.1 martin "fpgetmask()");
235 1.1 martin }
236 1.1 martin
237 1.1 martin ATF_TC_BODY(feenableexcept, tc)
238 1.1 martin {
239 1.2 martin FPU_EXC_PREREQ();
240 1.1 martin
241 1.1 martin fedisableexcept(FE_ALL_EXCEPT);
242 1.7 riastrad ATF_CHECK_EQ_MSG(fpgetmask(), 0,
243 1.7 riastrad "fpgetmask()=%d",
244 1.7 riastrad (int)fpgetmask());
245 1.1 martin
246 1.1 martin feenableexcept(FE_UNDERFLOW);
247 1.7 riastrad ATF_CHECK_EQ_MSG(fpgetmask(), FP_X_UFL,
248 1.7 riastrad "fpgetmask()=%d FP_X_UFL=%d",
249 1.7 riastrad (int)fpgetmask(), (int)FP_X_UFL);
250 1.1 martin
251 1.1 martin fedisableexcept(FE_ALL_EXCEPT);
252 1.1 martin feenableexcept(FE_OVERFLOW);
253 1.7 riastrad ATF_CHECK_EQ_MSG(fpgetmask(), FP_X_OFL,
254 1.7 riastrad "fpgetmask()=%d FP_X_OFL=%d",
255 1.7 riastrad (int)fpgetmask(), (int)FP_X_OFL);
256 1.1 martin
257 1.1 martin fedisableexcept(FE_ALL_EXCEPT);
258 1.1 martin feenableexcept(FE_DIVBYZERO);
259 1.7 riastrad ATF_CHECK_EQ_MSG(fpgetmask(), FP_X_DZ,
260 1.7 riastrad "fpgetmask()=%d FP_X_DZ=%d",
261 1.7 riastrad (int)fpgetmask(), (int)FP_X_DZ);
262 1.1 martin
263 1.1 martin fedisableexcept(FE_ALL_EXCEPT);
264 1.1 martin feenableexcept(FE_INEXACT);
265 1.7 riastrad ATF_CHECK_EQ_MSG(fpgetmask(), FP_X_IMP,
266 1.7 riastrad "fpgetmask()=%d FP_X_IMP=%d",
267 1.7 riastrad (int)fpgetmask(), (int)FP_X_IMP);
268 1.1 martin
269 1.1 martin fedisableexcept(FE_ALL_EXCEPT);
270 1.1 martin feenableexcept(FE_INVALID);
271 1.7 riastrad ATF_CHECK_EQ_MSG(fpgetmask(), FP_X_INV,
272 1.7 riastrad "fpgetmask()=%d FP_X_INV=%d",
273 1.7 riastrad (int)fpgetmask(), (int)FP_X_INV);
274 1.1 martin }
275 1.1 martin
276 1.1 martin ATF_TP_ADD_TCS(tp)
277 1.1 martin {
278 1.1 martin ATF_TP_ADD_TC(tp, fegetround);
279 1.1 martin ATF_TP_ADD_TC(tp, fesetround);
280 1.1 martin ATF_TP_ADD_TC(tp, fegetexcept);
281 1.1 martin ATF_TP_ADD_TC(tp, feenableexcept);
282 1.1 martin
283 1.1 martin return atf_no_error();
284 1.1 martin }
285 1.1 martin
286 1.1 martin #else /* no fenv.h support */
287 1.1 martin
288 1.1 martin ATF_TC(t_nofenv);
289 1.1 martin
290 1.1 martin ATF_TC_HEAD(t_nofenv, tc)
291 1.1 martin {
292 1.1 martin atf_tc_set_md_var(tc, "descr",
293 1.1 martin "dummy test case - no fenv.h support");
294 1.1 martin }
295 1.1 martin
296 1.1 martin
297 1.1 martin ATF_TC_BODY(t_nofenv, tc)
298 1.1 martin {
299 1.1 martin atf_tc_skip("no fenv.h support on this architecture");
300 1.1 martin }
301 1.1 martin
302 1.1 martin ATF_TP_ADD_TCS(tp)
303 1.1 martin {
304 1.1 martin ATF_TP_ADD_TC(tp, t_nofenv);
305 1.1 martin return atf_no_error();
306 1.1 martin }
307 1.1 martin
308 1.1 martin #endif
309