1 1.8 riastrad /* $NetBSD: t_fpsetround.c,v 1.8 2024/10/29 20:04:30 riastradh 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.8 riastrad __RCSID("$NetBSD: t_fpsetround.c,v 1.8 2024/10/29 20:04:30 riastradh 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.7 riastrad ATF_TC(fpsetround_noftz); 158 1.7 riastrad ATF_TC_HEAD(fpsetround_noftz, tc) 159 1.7 riastrad { 160 1.7 riastrad 161 1.7 riastrad atf_tc_set_md_var(tc, "descr", 162 1.7 riastrad "Test fpsetround(3) does not toggle flush-to-zero mode"); 163 1.7 riastrad } 164 1.7 riastrad ATF_TC_BODY(fpsetround_noftz, tc) 165 1.7 riastrad { 166 1.7 riastrad #if !defined(_FLOAT_IEEE754) || !defined(__DBL_DENORM_MIN__) 167 1.7 riastrad atf_tc_skip("no fpsetround or subnormals"); 168 1.7 riastrad #else 169 1.7 riastrad volatile double x = DBL_MIN; 170 1.7 riastrad volatile double y; 171 1.7 riastrad int r; 172 1.7 riastrad 173 1.7 riastrad y = x/2; 174 1.7 riastrad ATF_CHECK_MSG(y != 0, "machine runs flush-to-zero by default"); 175 1.7 riastrad 176 1.8 riastrad /* 177 1.8 riastrad * This curious test is a regression test for: 178 1.8 riastrad * 179 1.8 riastrad * PR port-arm/58782: fpsetround flips all the other fpcsr bits 180 1.8 riastrad * on aarch64 181 1.8 riastrad */ 182 1.7 riastrad 183 1.7 riastrad ATF_CHECK_EQ_MSG((r = fpsetround(FP_RN)), FP_RN, 184 1.7 riastrad "r=%d FP_RN=%d", r, FP_RN); 185 1.7 riastrad y = x/2; 186 1.7 riastrad ATF_CHECK_MSG(y != 0, 187 1.7 riastrad "machine runs flush-to-zero after one fpsetround call"); 188 1.7 riastrad 189 1.7 riastrad ATF_CHECK_EQ_MSG((r = fpsetround(FP_RN)), FP_RN, 190 1.7 riastrad "r=%d FP_RN=%d", r, FP_RN); 191 1.7 riastrad y = x/2; 192 1.7 riastrad ATF_CHECK_MSG(y != 0, 193 1.7 riastrad "machine runs flush-to-zero after two fpsetround calls"); 194 1.7 riastrad #endif 195 1.7 riastrad } 196 1.7 riastrad 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.7 riastrad ATF_TP_ADD_TC(tp, fpsetround_noftz); 202 1.1 jruoho 203 1.1 jruoho return atf_no_error(); 204 1.1 jruoho } 205