1 1.22 riastrad /* $NetBSD: t_fpsetmask.c,v 1.22 2024/05/14 14:55:43 riastradh Exp $ */ 2 1.1 jruoho 3 1.1 jruoho /*- 4 1.1 jruoho * Copyright (c) 1995 The NetBSD Foundation, Inc. 5 1.1 jruoho * All rights reserved. 6 1.1 jruoho * 7 1.1 jruoho * Redistribution and use in source and binary forms, with or without 8 1.1 jruoho * modification, are permitted provided that the following conditions 9 1.1 jruoho * are met: 10 1.1 jruoho * 1. Redistributions of source code must retain the above copyright 11 1.1 jruoho * notice, this list of conditions and the following disclaimer. 12 1.1 jruoho * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jruoho * notice, this list of conditions and the following disclaimer in the 14 1.1 jruoho * documentation and/or other materials provided with the distribution. 15 1.1 jruoho * 16 1.1 jruoho * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 jruoho * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 jruoho * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 jruoho * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 jruoho * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 jruoho * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 jruoho * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 jruoho * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 jruoho * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 jruoho * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 jruoho * POSSIBILITY OF SUCH DAMAGE. 27 1.1 jruoho */ 28 1.1 jruoho 29 1.13 jmmv #include <sys/param.h> 30 1.13 jmmv 31 1.1 jruoho #include <atf-c.h> 32 1.1 jruoho 33 1.1 jruoho #include <stdio.h> 34 1.1 jruoho #include <signal.h> 35 1.1 jruoho #include <float.h> 36 1.1 jruoho #include <setjmp.h> 37 1.1 jruoho #include <stdlib.h> 38 1.1 jruoho #include <string.h> 39 1.1 jruoho 40 1.10 christos #include "isqemu.h" 41 1.10 christos 42 1.2 christos #ifndef _FLOAT_IEEE754 43 1.1 jruoho 44 1.1 jruoho ATF_TC(no_test); 45 1.1 jruoho ATF_TC_HEAD(no_test, tc) 46 1.1 jruoho { 47 1.1 jruoho 48 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Dummy test case"); 49 1.1 jruoho } 50 1.1 jruoho 51 1.1 jruoho ATF_TC_BODY(no_test, tc) 52 1.1 jruoho { 53 1.1 jruoho 54 1.1 jruoho atf_tc_skip("Test not available on this architecture."); 55 1.1 jruoho } 56 1.1 jruoho 57 1.2 christos #else /* defined(_FLOAT_IEEE754) */ 58 1.1 jruoho 59 1.1 jruoho #include <ieeefp.h> 60 1.1 jruoho 61 1.18 martin #if (__arm__ && !__SOFTFP__) || __aarch64__ 62 1.15 martin /* 63 1.20 kamil * Some NEON fpus do not trap on IEEE 754 FP exceptions. 64 1.22 riastrad * Skip these tests if running on them and compiled for 65 1.15 martin * hard float. 66 1.15 martin */ 67 1.22 riastrad #define FPU_PREREQ() do \ 68 1.22 riastrad { \ 69 1.22 riastrad if (0 == fpsetmask(fpsetmask(FP_X_INV))) \ 70 1.22 riastrad atf_tc_skip("FPU does not implement traps on FP exceptions"); \ 71 1.22 riastrad } while (0) 72 1.22 riastrad #endif 73 1.22 riastrad 74 1.22 riastrad #ifdef __riscv__ 75 1.22 riastrad #ifdef __riscv__ 76 1.22 riastrad #define FPU_PREREQ() \ 77 1.22 riastrad atf_tc_skip("RISC-V does not support floating-point exception traps") 78 1.22 riastrad #endif 79 1.15 martin #endif 80 1.15 martin 81 1.15 martin #ifndef FPU_PREREQ 82 1.22 riastrad #define FPU_PREREQ() __nothing 83 1.15 martin #endif 84 1.1 jruoho 85 1.1 jruoho void sigfpe(int, siginfo_t *, void *); 86 1.1 jruoho 87 1.1 jruoho volatile sig_atomic_t signal_caught; 88 1.1 jruoho volatile int sicode; 89 1.1 jruoho 90 1.1 jruoho static volatile const float f_one = 1.0; 91 1.1 jruoho static volatile const float f_zero = 0.0; 92 1.1 jruoho static volatile const double d_one = 1.0; 93 1.1 jruoho static volatile const double d_zero = 0.0; 94 1.1 jruoho static volatile const long double ld_one = 1.0; 95 1.1 jruoho static volatile const long double ld_zero = 0.0; 96 1.1 jruoho 97 1.1 jruoho static volatile const float f_huge = FLT_MAX; 98 1.1 jruoho static volatile const float f_tiny = FLT_MIN; 99 1.1 jruoho static volatile const double d_huge = DBL_MAX; 100 1.1 jruoho static volatile const double d_tiny = DBL_MIN; 101 1.1 jruoho static volatile const long double ld_huge = LDBL_MAX; 102 1.1 jruoho static volatile const long double ld_tiny = LDBL_MIN; 103 1.1 jruoho 104 1.1 jruoho static volatile float f_x; 105 1.1 jruoho static volatile double d_x; 106 1.1 jruoho static volatile long double ld_x; 107 1.1 jruoho 108 1.1 jruoho /* trip divide by zero */ 109 1.1 jruoho static void 110 1.1 jruoho f_dz(void) 111 1.1 jruoho { 112 1.1 jruoho 113 1.1 jruoho f_x = f_one / f_zero; 114 1.1 jruoho } 115 1.1 jruoho 116 1.1 jruoho static void 117 1.1 jruoho d_dz(void) 118 1.1 jruoho { 119 1.1 jruoho 120 1.1 jruoho d_x = d_one / d_zero; 121 1.1 jruoho } 122 1.1 jruoho 123 1.1 jruoho static void 124 1.1 jruoho ld_dz(void) 125 1.1 jruoho { 126 1.1 jruoho 127 1.1 jruoho ld_x = ld_one / ld_zero; 128 1.1 jruoho } 129 1.1 jruoho 130 1.1 jruoho /* trip invalid operation */ 131 1.1 jruoho static void 132 1.1 jruoho d_inv(void) 133 1.1 jruoho { 134 1.1 jruoho 135 1.1 jruoho d_x = d_zero / d_zero; 136 1.1 jruoho } 137 1.1 jruoho 138 1.1 jruoho static void 139 1.1 jruoho ld_inv(void) 140 1.1 jruoho { 141 1.1 jruoho 142 1.1 jruoho ld_x = ld_zero / ld_zero; 143 1.1 jruoho } 144 1.1 jruoho 145 1.1 jruoho static void 146 1.1 jruoho f_inv(void) 147 1.1 jruoho { 148 1.1 jruoho 149 1.1 jruoho f_x = f_zero / f_zero; 150 1.1 jruoho } 151 1.1 jruoho 152 1.1 jruoho /* trip overflow */ 153 1.1 jruoho static void 154 1.1 jruoho f_ofl(void) 155 1.1 jruoho { 156 1.1 jruoho 157 1.1 jruoho f_x = f_huge * f_huge; 158 1.1 jruoho } 159 1.1 jruoho 160 1.1 jruoho static void 161 1.1 jruoho d_ofl(void) 162 1.1 jruoho { 163 1.1 jruoho 164 1.1 jruoho d_x = d_huge * d_huge; 165 1.1 jruoho } 166 1.1 jruoho 167 1.1 jruoho static void 168 1.1 jruoho ld_ofl(void) 169 1.1 jruoho { 170 1.1 jruoho 171 1.1 jruoho ld_x = ld_huge * ld_huge; 172 1.1 jruoho } 173 1.1 jruoho 174 1.1 jruoho /* trip underflow */ 175 1.1 jruoho static void 176 1.1 jruoho f_ufl(void) 177 1.1 jruoho { 178 1.1 jruoho 179 1.1 jruoho f_x = f_tiny * f_tiny; 180 1.1 jruoho } 181 1.1 jruoho 182 1.1 jruoho static void 183 1.1 jruoho d_ufl(void) 184 1.1 jruoho { 185 1.1 jruoho 186 1.1 jruoho d_x = d_tiny * d_tiny; 187 1.1 jruoho } 188 1.1 jruoho 189 1.1 jruoho static void 190 1.1 jruoho ld_ufl(void) 191 1.1 jruoho { 192 1.1 jruoho 193 1.1 jruoho ld_x = ld_tiny * ld_tiny; 194 1.1 jruoho } 195 1.1 jruoho 196 1.1 jruoho struct ops { 197 1.1 jruoho void (*op)(void); 198 1.1 jruoho fp_except mask; 199 1.1 jruoho int sicode; 200 1.1 jruoho }; 201 1.1 jruoho 202 1.1 jruoho static const struct ops float_ops[] = { 203 1.1 jruoho { f_dz, FP_X_DZ, FPE_FLTDIV }, 204 1.1 jruoho { f_inv, FP_X_INV, FPE_FLTINV }, 205 1.1 jruoho { f_ofl, FP_X_OFL, FPE_FLTOVF }, 206 1.1 jruoho { f_ufl, FP_X_UFL, FPE_FLTUND }, 207 1.1 jruoho { NULL, 0, 0 } 208 1.1 jruoho }; 209 1.1 jruoho 210 1.1 jruoho static const struct ops double_ops[] = { 211 1.1 jruoho { d_dz, FP_X_DZ, FPE_FLTDIV }, 212 1.1 jruoho { d_inv, FP_X_INV, FPE_FLTINV }, 213 1.1 jruoho { d_ofl, FP_X_OFL, FPE_FLTOVF }, 214 1.1 jruoho { d_ufl, FP_X_UFL, FPE_FLTUND }, 215 1.1 jruoho { NULL, 0, 0 } 216 1.1 jruoho }; 217 1.1 jruoho 218 1.1 jruoho static const struct ops long_double_ops[] = { 219 1.1 jruoho { ld_dz, FP_X_DZ, FPE_FLTDIV }, 220 1.1 jruoho { ld_inv, FP_X_INV, FPE_FLTINV }, 221 1.1 jruoho { ld_ofl, FP_X_OFL, FPE_FLTOVF }, 222 1.1 jruoho { ld_ufl, FP_X_UFL, FPE_FLTUND }, 223 1.1 jruoho { NULL, 0, 0 } 224 1.1 jruoho }; 225 1.1 jruoho 226 1.1 jruoho static sigjmp_buf b; 227 1.1 jruoho 228 1.1 jruoho static void 229 1.1 jruoho fpsetmask_masked(const struct ops *test_ops) 230 1.1 jruoho { 231 1.1 jruoho struct sigaction sa; 232 1.1 jruoho fp_except ex1, ex2; 233 1.1 jruoho const struct ops *t; 234 1.1 jruoho 235 1.1 jruoho /* mask all exceptions, clear history */ 236 1.1 jruoho fpsetmask(0); 237 1.1 jruoho fpsetsticky(0); 238 1.1 jruoho 239 1.1 jruoho /* set up signal handler */ 240 1.1 jruoho sa.sa_sigaction = sigfpe; 241 1.1 jruoho sigemptyset(&sa.sa_mask); 242 1.1 jruoho sa.sa_flags = SA_SIGINFO; 243 1.1 jruoho sigaction(SIGFPE, &sa, 0); 244 1.1 jruoho signal_caught = 0; 245 1.1 jruoho 246 1.1 jruoho /* 247 1.1 jruoho * exceptions masked, check whether "sticky" bits are set correctly 248 1.1 jruoho */ 249 1.1 jruoho for (t = test_ops; t->op != NULL; t++) { 250 1.1 jruoho (*t->op)(); 251 1.1 jruoho ex1 = fpgetsticky(); 252 1.1 jruoho ATF_CHECK_EQ(ex1 & t->mask, t->mask); 253 1.1 jruoho ATF_CHECK_EQ(signal_caught, 0); 254 1.1 jruoho 255 1.1 jruoho /* check correct fpsetsticky() behaviour */ 256 1.1 jruoho ex2 = fpsetsticky(0); 257 1.1 jruoho ATF_CHECK_EQ(fpgetsticky(), 0); 258 1.1 jruoho ATF_CHECK_EQ(ex1, ex2); 259 1.1 jruoho } 260 1.1 jruoho } 261 1.1 jruoho 262 1.1 jruoho /* force delayed exceptions to be delivered */ 263 1.1 jruoho #define BARRIER() fpsetmask(0); f_x = f_one * f_one 264 1.1 jruoho 265 1.1 jruoho static void 266 1.1 jruoho fpsetmask_unmasked(const struct ops *test_ops) 267 1.1 jruoho { 268 1.1 jruoho struct sigaction sa; 269 1.1 jruoho int r; 270 1.1 jruoho const struct ops *volatile t; 271 1.1 jruoho 272 1.1 jruoho /* mask all exceptions, clear history */ 273 1.1 jruoho fpsetmask(0); 274 1.1 jruoho fpsetsticky(0); 275 1.1 jruoho 276 1.1 jruoho /* set up signal handler */ 277 1.1 jruoho sa.sa_sigaction = sigfpe; 278 1.1 jruoho sigemptyset(&sa.sa_mask); 279 1.1 jruoho sa.sa_flags = SA_SIGINFO; 280 1.1 jruoho sigaction(SIGFPE, &sa, 0); 281 1.1 jruoho signal_caught = 0; 282 1.1 jruoho 283 1.1 jruoho /* 284 1.1 jruoho * exception unmasked, check SIGFPE delivery and correct siginfo 285 1.1 jruoho */ 286 1.1 jruoho for (t = test_ops; t->op != NULL; t++) { 287 1.1 jruoho fpsetmask(t->mask); 288 1.1 jruoho r = sigsetjmp(b, 1); 289 1.1 jruoho if (!r) { 290 1.1 jruoho (*t->op)(); 291 1.1 jruoho BARRIER(); 292 1.1 jruoho } 293 1.1 jruoho ATF_CHECK_EQ(signal_caught, 1); 294 1.1 jruoho ATF_CHECK_EQ(sicode, t->sicode); 295 1.1 jruoho signal_caught = 0; 296 1.1 jruoho } 297 1.1 jruoho } 298 1.1 jruoho 299 1.1 jruoho void 300 1.1 jruoho sigfpe(int s, siginfo_t *si, void *c) 301 1.1 jruoho { 302 1.1 jruoho signal_caught = 1; 303 1.1 jruoho sicode = si->si_code; 304 1.1 jruoho siglongjmp(b, 1); 305 1.1 jruoho } 306 1.1 jruoho 307 1.1 jruoho #define TEST(m, t) \ 308 1.1 jruoho ATF_TC(m##_##t); \ 309 1.1 jruoho \ 310 1.1 jruoho ATF_TC_HEAD(m##_##t, tc) \ 311 1.1 jruoho { \ 312 1.1 jruoho \ 313 1.1 jruoho atf_tc_set_md_var(tc, "descr", \ 314 1.1 jruoho "Test " ___STRING(m) " exceptions for " \ 315 1.1 jruoho ___STRING(t) "values"); \ 316 1.1 jruoho } \ 317 1.1 jruoho \ 318 1.1 jruoho ATF_TC_BODY(m##_##t, tc) \ 319 1.1 jruoho { \ 320 1.15 martin \ 321 1.15 martin FPU_PREREQ(); \ 322 1.15 martin \ 323 1.21 gson if (isQEMU_TCG()) \ 324 1.7 jruoho atf_tc_expect_fail("PR misc/44767"); \ 325 1.7 jruoho \ 326 1.1 jruoho m(t##_ops); \ 327 1.1 jruoho } 328 1.1 jruoho 329 1.1 jruoho TEST(fpsetmask_masked, float) 330 1.1 jruoho TEST(fpsetmask_masked, double) 331 1.1 jruoho TEST(fpsetmask_masked, long_double) 332 1.1 jruoho TEST(fpsetmask_unmasked, float) 333 1.1 jruoho TEST(fpsetmask_unmasked, double) 334 1.1 jruoho TEST(fpsetmask_unmasked, long_double) 335 1.1 jruoho 336 1.3 njoly ATF_TC(fpsetmask_basic); 337 1.3 njoly ATF_TC_HEAD(fpsetmask_basic, tc) 338 1.3 njoly { 339 1.3 njoly atf_tc_set_md_var(tc, "descr", "A basic test of fpsetmask(3)"); 340 1.3 njoly } 341 1.3 njoly 342 1.3 njoly ATF_TC_BODY(fpsetmask_basic, tc) 343 1.3 njoly { 344 1.3 njoly size_t i; 345 1.3 njoly fp_except_t msk, lst[] = { FP_X_INV, FP_X_DZ, FP_X_OFL, FP_X_UFL }; 346 1.3 njoly 347 1.15 martin FPU_PREREQ(); 348 1.15 martin 349 1.3 njoly msk = fpgetmask(); 350 1.3 njoly for (i = 0; i < __arraycount(lst); i++) { 351 1.3 njoly fpsetmask(msk | lst[i]); 352 1.3 njoly ATF_CHECK((fpgetmask() & lst[i]) != 0); 353 1.16 martin fpsetmask(msk & ~lst[i]); 354 1.3 njoly ATF_CHECK((fpgetmask() & lst[i]) == 0); 355 1.3 njoly } 356 1.3 njoly 357 1.3 njoly } 358 1.3 njoly 359 1.2 christos #endif /* defined(_FLOAT_IEEE754) */ 360 1.1 jruoho 361 1.1 jruoho ATF_TP_ADD_TCS(tp) 362 1.1 jruoho { 363 1.1 jruoho 364 1.2 christos #ifndef _FLOAT_IEEE754 365 1.1 jruoho ATF_TP_ADD_TC(tp, no_test); 366 1.1 jruoho #else 367 1.3 njoly ATF_TP_ADD_TC(tp, fpsetmask_basic); 368 1.1 jruoho ATF_TP_ADD_TC(tp, fpsetmask_masked_float); 369 1.1 jruoho ATF_TP_ADD_TC(tp, fpsetmask_masked_double); 370 1.1 jruoho ATF_TP_ADD_TC(tp, fpsetmask_masked_long_double); 371 1.1 jruoho ATF_TP_ADD_TC(tp, fpsetmask_unmasked_float); 372 1.1 jruoho ATF_TP_ADD_TC(tp, fpsetmask_unmasked_double); 373 1.1 jruoho ATF_TP_ADD_TC(tp, fpsetmask_unmasked_long_double); 374 1.1 jruoho #endif 375 1.1 jruoho 376 1.1 jruoho return atf_no_error(); 377 1.1 jruoho } 378