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