t_fpsetround.c revision 1.6.44.1 1 1.6.44.1 martin /* $NetBSD: t_fpsetround.c,v 1.6.44.1 2024/11/20 14:04:55 martin Exp $ */
2 1.1 jruoho
3 1.2 christos /*-
4 1.2 christos * Copyright (c) 2011 The NetBSD Foundation, Inc.
5 1.2 christos * All rights reserved.
6 1.2 christos *
7 1.2 christos * This code is derived from software contributed to The NetBSD Foundation
8 1.2 christos * by Christos Zoulas.
9 1.2 christos *
10 1.2 christos * Redistribution and use in source and binary forms, with or without
11 1.2 christos * modification, are permitted provided that the following conditions
12 1.2 christos * are met:
13 1.2 christos * 1. Redistributions of source code must retain the above copyright
14 1.2 christos * notice, this list of conditions and the following disclaimer.
15 1.2 christos * 2. Redistributions in binary form must reproduce the above copyright
16 1.2 christos * notice, this list of conditions and the following disclaimer in the
17 1.2 christos * documentation and/or other materials provided with the distribution.
18 1.2 christos * 3. All advertising materials mentioning features or use of this software
19 1.2 christos * must display the following acknowledgement:
20 1.2 christos * This product includes software developed by the NetBSD
21 1.2 christos * Foundation, Inc. and its contributors.
22 1.2 christos * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.2 christos * contributors may be used to endorse or promote products derived
24 1.2 christos * from this software without specific prior written permission.
25 1.2 christos *
26 1.2 christos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.2 christos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.2 christos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.2 christos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.2 christos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.2 christos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.2 christos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.2 christos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.2 christos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.2 christos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.2 christos * POSSIBILITY OF SUCH DAMAGE.
37 1.1 jruoho */
38 1.2 christos #include <sys/cdefs.h>
39 1.6.44.1 martin __RCSID("$NetBSD: t_fpsetround.c,v 1.6.44.1 2024/11/20 14:04:55 martin Exp $");
40 1.1 jruoho
41 1.1 jruoho #include <float.h>
42 1.2 christos #include <math.h>
43 1.1 jruoho #include <stdlib.h>
44 1.1 jruoho #include <string.h>
45 1.3 christos #include <stdio.h>
46 1.1 jruoho
47 1.2 christos #include <atf-c.h>
48 1.2 christos
49 1.1 jruoho ATF_TC(fpsetround_basic);
50 1.1 jruoho ATF_TC_HEAD(fpsetround_basic, tc)
51 1.1 jruoho {
52 1.1 jruoho
53 1.1 jruoho atf_tc_set_md_var(tc, "descr",
54 1.1 jruoho "Minimal testing of fpgetround(3) and fpsetround(3)");
55 1.1 jruoho }
56 1.1 jruoho
57 1.6 christos #ifdef _FLOAT_IEEE754
58 1.6 christos #include <ieeefp.h>
59 1.6 christos
60 1.2 christos static const struct {
61 1.2 christos const char *n;
62 1.3 christos int rm;
63 1.3 christos int rf;
64 1.3 christos } rnd[] = {
65 1.3 christos { "RN", FP_RN, 1 },
66 1.3 christos { "RP", FP_RP, 2 },
67 1.3 christos { "RM", FP_RM, 3 },
68 1.3 christos { "RZ", FP_RZ, 0 },
69 1.3 christos
70 1.3 christos };
71 1.3 christos
72 1.3 christos static const struct {
73 1.3 christos const char *n;
74 1.2 christos int v[4];
75 1.2 christos } tst[] = { /* RN RP RM RZ */
76 1.2 christos { "1.1", { 1, 1, 2, 1 } },
77 1.2 christos { "1.5", { 1, 2, 2, 1 } },
78 1.2 christos { "1.9", { 1, 2, 2, 1 } },
79 1.5 christos { "2.1", { 2, 2, 3, 2 } },
80 1.5 christos { "2.5", { 2, 2, 3, 2 } },
81 1.5 christos { "2.9", { 2, 3, 3, 2 } },
82 1.2 christos { "-1.1", { -1, -1, -1, -2 } },
83 1.2 christos { "-1.5", { -1, -2, -1, -2 } },
84 1.2 christos { "-1.9", { -1, -2, -1, -2 } },
85 1.5 christos { "-2.1", { -2, -2, -2, -3 } },
86 1.5 christos { "-2.5", { -2, -2, -2, -3 } },
87 1.5 christos { "-2.9", { -2, -3, -2, -3 } },
88 1.2 christos };
89 1.2 christos
90 1.4 christos static const char *
91 1.4 christos getname(int r)
92 1.4 christos {
93 1.4 christos for (size_t i = 0; i < __arraycount(rnd); i++)
94 1.4 christos if (rnd[i].rm == r)
95 1.4 christos return rnd[i].n;
96 1.4 christos return "*unknown*";
97 1.4 christos }
98 1.4 christos
99 1.2 christos static void
100 1.2 christos test(int r)
101 1.2 christos {
102 1.3 christos int did = 0;
103 1.2 christos for (size_t i = 0; i < __arraycount(tst); i++) {
104 1.2 christos double d = strtod(tst[i].n, NULL);
105 1.3 christos int g = (int)rint(d);
106 1.3 christos int e = tst[i].v[r];
107 1.3 christos ATF_CHECK_EQ(g, e);
108 1.3 christos if (g != e) {
109 1.3 christos if (!did) {
110 1.3 christos fprintf(stderr, "Mode Value Result Expected\n");
111 1.3 christos did = 1;
112 1.3 christos }
113 1.3 christos fprintf(stderr, "%4.4s %-5.5s %6d %8d\n", rnd[r].n,
114 1.3 christos tst[i].n, (int)rint(d), tst[i].v[r]);
115 1.3 christos }
116 1.2 christos }
117 1.2 christos }
118 1.6 christos #endif
119 1.2 christos
120 1.2 christos
121 1.1 jruoho ATF_TC_BODY(fpsetround_basic, tc)
122 1.1 jruoho {
123 1.1 jruoho
124 1.6 christos #ifndef _FLOAT_IEEE754
125 1.1 jruoho atf_tc_skip("Test not applicable on this architecture.");
126 1.1 jruoho #else
127 1.2 christos int r;
128 1.1 jruoho
129 1.2 christos ATF_CHECK_EQ(r = fpgetround(), FP_RN);
130 1.4 christos if (FP_RN != r)
131 1.4 christos fprintf(stderr, "default expected=%s got=%s\n", getname(FP_RN),
132 1.4 christos getname(r));
133 1.1 jruoho ATF_CHECK_EQ(FLT_ROUNDS, 1);
134 1.1 jruoho
135 1.2 christos for (size_t i = 0; i < __arraycount(rnd); i++) {
136 1.4 christos const size_t j = (i + 1) & 3;
137 1.4 christos const int o = rnd[i].rm;
138 1.4 christos const int n = rnd[j].rm;
139 1.2 christos
140 1.2 christos ATF_CHECK_EQ(r = fpsetround(n), o);
141 1.3 christos if (o != r)
142 1.4 christos fprintf(stderr, "set %s expected=%s got=%s\n",
143 1.4 christos getname(n), getname(o), getname(r));
144 1.2 christos ATF_CHECK_EQ(r = fpgetround(), n);
145 1.3 christos if (n != r)
146 1.4 christos fprintf(stderr, "get expected=%s got=%s\n", getname(n),
147 1.4 christos getname(r));
148 1.4 christos ATF_CHECK_EQ(r = FLT_ROUNDS, rnd[j].rf);
149 1.3 christos if (r != rnd[j].rf)
150 1.3 christos fprintf(stderr, "rounds expected=%x got=%x\n",
151 1.3 christos rnd[j].rf, r);
152 1.4 christos test(r);
153 1.2 christos }
154 1.6 christos #endif /* _FLOAT_IEEE754 */
155 1.1 jruoho }
156 1.1 jruoho
157 1.6.44.1 martin ATF_TC(fpsetround_noftz);
158 1.6.44.1 martin ATF_TC_HEAD(fpsetround_noftz, tc)
159 1.6.44.1 martin {
160 1.6.44.1 martin
161 1.6.44.1 martin atf_tc_set_md_var(tc, "descr",
162 1.6.44.1 martin "Test fpsetround(3) does not toggle flush-to-zero mode");
163 1.6.44.1 martin }
164 1.6.44.1 martin ATF_TC_BODY(fpsetround_noftz, tc)
165 1.6.44.1 martin {
166 1.6.44.1 martin #if !defined(_FLOAT_IEEE754) || !defined(__DBL_DENORM_MIN__)
167 1.6.44.1 martin atf_tc_skip("no fpsetround or subnormals");
168 1.6.44.1 martin #else
169 1.6.44.1 martin volatile double x = DBL_MIN;
170 1.6.44.1 martin volatile double y;
171 1.6.44.1 martin int r;
172 1.6.44.1 martin
173 1.6.44.1 martin y = x/2;
174 1.6.44.1 martin ATF_CHECK_MSG(y != 0, "machine runs flush-to-zero by default");
175 1.6.44.1 martin
176 1.6.44.1 martin /*
177 1.6.44.1 martin * This curious test is a regression test for:
178 1.6.44.1 martin *
179 1.6.44.1 martin * PR port-arm/58782: fpsetround flips all the other fpcsr bits
180 1.6.44.1 martin * on aarch64
181 1.6.44.1 martin */
182 1.6.44.1 martin
183 1.6.44.1 martin ATF_CHECK_EQ_MSG((r = fpsetround(FP_RN)), FP_RN,
184 1.6.44.1 martin "r=%d FP_RN=%d", r, FP_RN);
185 1.6.44.1 martin y = x/2;
186 1.6.44.1 martin ATF_CHECK_MSG(y != 0,
187 1.6.44.1 martin "machine runs flush-to-zero after one fpsetround call");
188 1.6.44.1 martin
189 1.6.44.1 martin ATF_CHECK_EQ_MSG((r = fpsetround(FP_RN)), FP_RN,
190 1.6.44.1 martin "r=%d FP_RN=%d", r, FP_RN);
191 1.6.44.1 martin y = x/2;
192 1.6.44.1 martin ATF_CHECK_MSG(y != 0,
193 1.6.44.1 martin "machine runs flush-to-zero after two fpsetround calls");
194 1.6.44.1 martin #endif
195 1.6.44.1 martin }
196 1.6.44.1 martin
197 1.1 jruoho ATF_TP_ADD_TCS(tp)
198 1.1 jruoho {
199 1.1 jruoho
200 1.1 jruoho ATF_TP_ADD_TC(tp, fpsetround_basic);
201 1.6.44.1 martin ATF_TP_ADD_TC(tp, fpsetround_noftz);
202 1.1 jruoho
203 1.1 jruoho return atf_no_error();
204 1.1 jruoho }
205