xref: /netbsd-src/tests/lib/libc/gen/t_fpsetround.c (revision daa1241083b2023820acca276246d156596cf36f)
1*daa12410Sriastradh /* $NetBSD: t_fpsetround.c,v 1.8 2024/10/29 20:04:30 riastradh Exp $ */
24a45a29aSjruoho 
3eb5e1b54Schristos /*-
4eb5e1b54Schristos  * Copyright (c) 2011 The NetBSD Foundation, Inc.
5eb5e1b54Schristos  * All rights reserved.
6eb5e1b54Schristos  *
7eb5e1b54Schristos  * This code is derived from software contributed to The NetBSD Foundation
8eb5e1b54Schristos  * by Christos Zoulas.
9eb5e1b54Schristos  *
10eb5e1b54Schristos  * Redistribution and use in source and binary forms, with or without
11eb5e1b54Schristos  * modification, are permitted provided that the following conditions
12eb5e1b54Schristos  * are met:
13eb5e1b54Schristos  * 1. Redistributions of source code must retain the above copyright
14eb5e1b54Schristos  *    notice, this list of conditions and the following disclaimer.
15eb5e1b54Schristos  * 2. Redistributions in binary form must reproduce the above copyright
16eb5e1b54Schristos  *    notice, this list of conditions and the following disclaimer in the
17eb5e1b54Schristos  *    documentation and/or other materials provided with the distribution.
18eb5e1b54Schristos  * 3. All advertising materials mentioning features or use of this software
19eb5e1b54Schristos  *    must display the following acknowledgement:
20eb5e1b54Schristos  *        This product includes software developed by the NetBSD
21eb5e1b54Schristos  *        Foundation, Inc. and its contributors.
22eb5e1b54Schristos  * 4. Neither the name of The NetBSD Foundation nor the names of its
23eb5e1b54Schristos  *    contributors may be used to endorse or promote products derived
24eb5e1b54Schristos  *    from this software without specific prior written permission.
25eb5e1b54Schristos  *
26eb5e1b54Schristos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27eb5e1b54Schristos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28eb5e1b54Schristos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29eb5e1b54Schristos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30eb5e1b54Schristos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31eb5e1b54Schristos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32eb5e1b54Schristos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33eb5e1b54Schristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34eb5e1b54Schristos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35eb5e1b54Schristos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36eb5e1b54Schristos  * POSSIBILITY OF SUCH DAMAGE.
374a45a29aSjruoho  */
38eb5e1b54Schristos #include <sys/cdefs.h>
39*daa12410Sriastradh __RCSID("$NetBSD: t_fpsetround.c,v 1.8 2024/10/29 20:04:30 riastradh Exp $");
404a45a29aSjruoho 
414a45a29aSjruoho #include <float.h>
42eb5e1b54Schristos #include <math.h>
434a45a29aSjruoho #include <stdlib.h>
444a45a29aSjruoho #include <string.h>
4583ade104Schristos #include <stdio.h>
464a45a29aSjruoho 
47eb5e1b54Schristos #include <atf-c.h>
48eb5e1b54Schristos 
494a45a29aSjruoho ATF_TC(fpsetround_basic);
504a45a29aSjruoho ATF_TC_HEAD(fpsetround_basic, tc)
514a45a29aSjruoho {
524a45a29aSjruoho 
534a45a29aSjruoho 	atf_tc_set_md_var(tc, "descr",
544a45a29aSjruoho 	    "Minimal testing of fpgetround(3) and fpsetround(3)");
554a45a29aSjruoho }
564a45a29aSjruoho 
57789b17abSchristos #ifdef _FLOAT_IEEE754
58789b17abSchristos #include <ieeefp.h>
59789b17abSchristos 
60eb5e1b54Schristos static const struct {
61eb5e1b54Schristos 	const char *n;
6283ade104Schristos 	int rm;
6383ade104Schristos 	int rf;
6483ade104Schristos } rnd[] = {
6583ade104Schristos 	{ "RN", FP_RN, 1 },
6683ade104Schristos 	{ "RP", FP_RP, 2 },
6783ade104Schristos 	{ "RM", FP_RM, 3 },
6883ade104Schristos 	{ "RZ", FP_RZ, 0 },
6983ade104Schristos 
7083ade104Schristos };
7183ade104Schristos 
7283ade104Schristos static const struct {
7383ade104Schristos 	const char *n;
74eb5e1b54Schristos 	int v[4];
75eb5e1b54Schristos } tst[] = {	/*  RN  RP  RM  RZ */
76eb5e1b54Schristos 	{  "1.1", {  1,  1,  2,  1 } },
77eb5e1b54Schristos 	{  "1.5", {  1,  2,  2,  1 } },
78eb5e1b54Schristos 	{  "1.9", {  1,  2,  2,  1 } },
79879077c6Schristos 	{  "2.1", {  2,  2,  3,  2 } },
80879077c6Schristos 	{  "2.5", {  2,  2,  3,  2 } },
81879077c6Schristos 	{  "2.9", {  2,  3,  3,  2 } },
82eb5e1b54Schristos 	{ "-1.1", { -1, -1, -1, -2 } },
83eb5e1b54Schristos 	{ "-1.5", { -1, -2, -1, -2 } },
84eb5e1b54Schristos 	{ "-1.9", { -1, -2, -1, -2 } },
85879077c6Schristos 	{ "-2.1", { -2, -2, -2, -3 } },
86879077c6Schristos 	{ "-2.5", { -2, -2, -2, -3 } },
87879077c6Schristos 	{ "-2.9", { -2, -3, -2, -3 } },
88eb5e1b54Schristos };
89eb5e1b54Schristos 
900abddc98Schristos static const char *
910abddc98Schristos getname(int r)
920abddc98Schristos {
930abddc98Schristos 	for (size_t i = 0; i < __arraycount(rnd); i++)
940abddc98Schristos 		if (rnd[i].rm == r)
950abddc98Schristos 			return rnd[i].n;
960abddc98Schristos 	return "*unknown*";
970abddc98Schristos }
980abddc98Schristos 
99eb5e1b54Schristos static void
100eb5e1b54Schristos test(int r)
101eb5e1b54Schristos {
10283ade104Schristos 	int did = 0;
103eb5e1b54Schristos 	for (size_t i = 0; i < __arraycount(tst); i++) {
104eb5e1b54Schristos 		double d = strtod(tst[i].n, NULL);
10583ade104Schristos 		int g = (int)rint(d);
10683ade104Schristos 		int e = tst[i].v[r];
10783ade104Schristos 		ATF_CHECK_EQ(g, e);
10883ade104Schristos 		if (g != e) {
10983ade104Schristos 			if (!did) {
11083ade104Schristos 				fprintf(stderr, "Mode Value Result Expected\n");
11183ade104Schristos 				did = 1;
11283ade104Schristos 			}
11383ade104Schristos 			fprintf(stderr, "%4.4s %-5.5s %6d %8d\n", rnd[r].n,
11483ade104Schristos 			    tst[i].n, (int)rint(d), tst[i].v[r]);
11583ade104Schristos 		}
116eb5e1b54Schristos 	}
117eb5e1b54Schristos }
118789b17abSchristos #endif
119eb5e1b54Schristos 
120eb5e1b54Schristos 
1214a45a29aSjruoho ATF_TC_BODY(fpsetround_basic, tc)
1224a45a29aSjruoho {
1234a45a29aSjruoho 
124789b17abSchristos #ifndef _FLOAT_IEEE754
1254a45a29aSjruoho 	atf_tc_skip("Test not applicable on this architecture.");
1264a45a29aSjruoho #else
127eb5e1b54Schristos 	int r;
1284a45a29aSjruoho 
129eb5e1b54Schristos 	ATF_CHECK_EQ(r = fpgetround(), FP_RN);
1300abddc98Schristos 	if (FP_RN != r)
1310abddc98Schristos 		fprintf(stderr, "default expected=%s got=%s\n", getname(FP_RN),
1320abddc98Schristos 		    getname(r));
1334a45a29aSjruoho 	ATF_CHECK_EQ(FLT_ROUNDS, 1);
1344a45a29aSjruoho 
135eb5e1b54Schristos 	for (size_t i = 0; i < __arraycount(rnd); i++) {
1360abddc98Schristos 		const size_t j = (i + 1) & 3;
1370abddc98Schristos 		const int o = rnd[i].rm;
1380abddc98Schristos 		const int n = rnd[j].rm;
1394a45a29aSjruoho 
140eb5e1b54Schristos 		ATF_CHECK_EQ(r = fpsetround(n), o);
14183ade104Schristos 		if (o != r)
1420abddc98Schristos 			fprintf(stderr, "set %s expected=%s got=%s\n",
1430abddc98Schristos 			    getname(n), getname(o), getname(r));
144eb5e1b54Schristos 		ATF_CHECK_EQ(r = fpgetround(), n);
14583ade104Schristos 		if (n != r)
1460abddc98Schristos 			fprintf(stderr, "get expected=%s got=%s\n", getname(n),
1470abddc98Schristos 			    getname(r));
14883ade104Schristos 		ATF_CHECK_EQ(r = FLT_ROUNDS, rnd[j].rf);
14983ade104Schristos 		if (r != rnd[j].rf)
15083ade104Schristos 			fprintf(stderr, "rounds expected=%x got=%x\n",
15183ade104Schristos 			    rnd[j].rf, r);
1520abddc98Schristos 		test(r);
153eb5e1b54Schristos 	}
154789b17abSchristos #endif /* _FLOAT_IEEE754 */
1554a45a29aSjruoho }
1564a45a29aSjruoho 
15767921d48Sriastradh ATF_TC(fpsetround_noftz);
15867921d48Sriastradh ATF_TC_HEAD(fpsetround_noftz, tc)
15967921d48Sriastradh {
16067921d48Sriastradh 
16167921d48Sriastradh 	atf_tc_set_md_var(tc, "descr",
16267921d48Sriastradh 	    "Test fpsetround(3) does not toggle flush-to-zero mode");
16367921d48Sriastradh }
16467921d48Sriastradh ATF_TC_BODY(fpsetround_noftz, tc)
16567921d48Sriastradh {
16667921d48Sriastradh #if !defined(_FLOAT_IEEE754) || !defined(__DBL_DENORM_MIN__)
16767921d48Sriastradh 	atf_tc_skip("no fpsetround or subnormals");
16867921d48Sriastradh #else
16967921d48Sriastradh 	volatile double x = DBL_MIN;
17067921d48Sriastradh 	volatile double y;
17167921d48Sriastradh 	int r;
17267921d48Sriastradh 
17367921d48Sriastradh 	y = x/2;
17467921d48Sriastradh 	ATF_CHECK_MSG(y != 0, "machine runs flush-to-zero by default");
17567921d48Sriastradh 
176*daa12410Sriastradh 	/*
177*daa12410Sriastradh 	 * This curious test is a regression test for:
178*daa12410Sriastradh 	 *
179*daa12410Sriastradh 	 * PR port-arm/58782: fpsetround flips all the other fpcsr bits
180*daa12410Sriastradh 	 * on aarch64
181*daa12410Sriastradh 	 */
18267921d48Sriastradh 
18367921d48Sriastradh 	ATF_CHECK_EQ_MSG((r = fpsetround(FP_RN)), FP_RN,
18467921d48Sriastradh 	    "r=%d FP_RN=%d", r, FP_RN);
18567921d48Sriastradh 	y = x/2;
18667921d48Sriastradh 	ATF_CHECK_MSG(y != 0,
18767921d48Sriastradh 	    "machine runs flush-to-zero after one fpsetround call");
18867921d48Sriastradh 
18967921d48Sriastradh 	ATF_CHECK_EQ_MSG((r = fpsetround(FP_RN)), FP_RN,
19067921d48Sriastradh 	    "r=%d FP_RN=%d", r, FP_RN);
19167921d48Sriastradh 	y = x/2;
19267921d48Sriastradh 	ATF_CHECK_MSG(y != 0,
19367921d48Sriastradh 	    "machine runs flush-to-zero after two fpsetround calls");
19467921d48Sriastradh #endif
19567921d48Sriastradh }
19667921d48Sriastradh 
1974a45a29aSjruoho ATF_TP_ADD_TCS(tp)
1984a45a29aSjruoho {
1994a45a29aSjruoho 
2004a45a29aSjruoho 	ATF_TP_ADD_TC(tp, fpsetround_basic);
20167921d48Sriastradh 	ATF_TP_ADD_TC(tp, fpsetround_noftz);
2024a45a29aSjruoho 
2034a45a29aSjruoho 	return atf_no_error();
2044a45a29aSjruoho }
205