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