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