1 /* $NetBSD: t_fpsetmask.c,v 1.13 2014/02/09 21:26:07 jmmv 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 #include <atf-c/config.h> 33 34 #include <stdio.h> 35 #include <signal.h> 36 #include <float.h> 37 #include <setjmp.h> 38 #include <stdlib.h> 39 #include <string.h> 40 41 #include "isqemu.h" 42 43 #ifndef _FLOAT_IEEE754 44 45 ATF_TC(no_test); 46 ATF_TC_HEAD(no_test, tc) 47 { 48 49 atf_tc_set_md_var(tc, "descr", "Dummy test case"); 50 } 51 52 ATF_TC_BODY(no_test, tc) 53 { 54 55 atf_tc_skip("Test not available on this architecture."); 56 } 57 58 #else /* defined(_FLOAT_IEEE754) */ 59 60 #include <ieeefp.h> 61 62 const char *skip_mesg; 63 const char *skip_arch; 64 65 void sigfpe(int, siginfo_t *, void *); 66 67 volatile sig_atomic_t signal_caught; 68 volatile int sicode; 69 70 static volatile const float f_one = 1.0; 71 static volatile const float f_zero = 0.0; 72 static volatile const double d_one = 1.0; 73 static volatile const double d_zero = 0.0; 74 static volatile const long double ld_one = 1.0; 75 static volatile const long double ld_zero = 0.0; 76 77 static volatile const float f_huge = FLT_MAX; 78 static volatile const float f_tiny = FLT_MIN; 79 static volatile const double d_huge = DBL_MAX; 80 static volatile const double d_tiny = DBL_MIN; 81 static volatile const long double ld_huge = LDBL_MAX; 82 static volatile const long double ld_tiny = LDBL_MIN; 83 84 static volatile float f_x; 85 static volatile double d_x; 86 static volatile long double ld_x; 87 88 /* trip divide by zero */ 89 static void 90 f_dz(void) 91 { 92 93 f_x = f_one / f_zero; 94 } 95 96 static void 97 d_dz(void) 98 { 99 100 d_x = d_one / d_zero; 101 } 102 103 static void 104 ld_dz(void) 105 { 106 107 ld_x = ld_one / ld_zero; 108 } 109 110 /* trip invalid operation */ 111 static void 112 d_inv(void) 113 { 114 115 d_x = d_zero / d_zero; 116 } 117 118 static void 119 ld_inv(void) 120 { 121 122 ld_x = ld_zero / ld_zero; 123 } 124 125 static void 126 f_inv(void) 127 { 128 129 f_x = f_zero / f_zero; 130 } 131 132 /* trip overflow */ 133 static void 134 f_ofl(void) 135 { 136 137 f_x = f_huge * f_huge; 138 } 139 140 static void 141 d_ofl(void) 142 { 143 144 d_x = d_huge * d_huge; 145 } 146 147 static void 148 ld_ofl(void) 149 { 150 151 ld_x = ld_huge * ld_huge; 152 } 153 154 /* trip underflow */ 155 static void 156 f_ufl(void) 157 { 158 159 f_x = f_tiny * f_tiny; 160 } 161 162 static void 163 d_ufl(void) 164 { 165 166 d_x = d_tiny * d_tiny; 167 } 168 169 static void 170 ld_ufl(void) 171 { 172 173 ld_x = ld_tiny * ld_tiny; 174 } 175 176 struct ops { 177 void (*op)(void); 178 fp_except mask; 179 int sicode; 180 }; 181 182 static const struct ops float_ops[] = { 183 { f_dz, FP_X_DZ, FPE_FLTDIV }, 184 { f_inv, FP_X_INV, FPE_FLTINV }, 185 { f_ofl, FP_X_OFL, FPE_FLTOVF }, 186 { f_ufl, FP_X_UFL, FPE_FLTUND }, 187 { NULL, 0, 0 } 188 }; 189 190 static const struct ops double_ops[] = { 191 { d_dz, FP_X_DZ, FPE_FLTDIV }, 192 { d_inv, FP_X_INV, FPE_FLTINV }, 193 { d_ofl, FP_X_OFL, FPE_FLTOVF }, 194 { d_ufl, FP_X_UFL, FPE_FLTUND }, 195 { NULL, 0, 0 } 196 }; 197 198 static const struct ops long_double_ops[] = { 199 { ld_dz, FP_X_DZ, FPE_FLTDIV }, 200 { ld_inv, FP_X_INV, FPE_FLTINV }, 201 { ld_ofl, FP_X_OFL, FPE_FLTOVF }, 202 { ld_ufl, FP_X_UFL, FPE_FLTUND }, 203 { NULL, 0, 0 } 204 }; 205 206 static sigjmp_buf b; 207 208 static void 209 fpsetmask_masked(const struct ops *test_ops) 210 { 211 struct sigaction sa; 212 fp_except ex1, ex2; 213 const struct ops *t; 214 215 /* mask all exceptions, clear history */ 216 fpsetmask(0); 217 fpsetsticky(0); 218 219 /* set up signal handler */ 220 sa.sa_sigaction = sigfpe; 221 sigemptyset(&sa.sa_mask); 222 sa.sa_flags = SA_SIGINFO; 223 sigaction(SIGFPE, &sa, 0); 224 signal_caught = 0; 225 226 /* 227 * exceptions masked, check whether "sticky" bits are set correctly 228 */ 229 for (t = test_ops; t->op != NULL; t++) { 230 (*t->op)(); 231 ex1 = fpgetsticky(); 232 ATF_CHECK_EQ(ex1 & t->mask, t->mask); 233 ATF_CHECK_EQ(signal_caught, 0); 234 235 /* check correct fpsetsticky() behaviour */ 236 ex2 = fpsetsticky(0); 237 ATF_CHECK_EQ(fpgetsticky(), 0); 238 ATF_CHECK_EQ(ex1, ex2); 239 } 240 } 241 242 /* force delayed exceptions to be delivered */ 243 #define BARRIER() fpsetmask(0); f_x = f_one * f_one 244 245 static void 246 fpsetmask_unmasked(const struct ops *test_ops) 247 { 248 struct sigaction sa; 249 int r; 250 const struct ops *volatile t; 251 252 /* mask all exceptions, clear history */ 253 fpsetmask(0); 254 fpsetsticky(0); 255 256 /* set up signal handler */ 257 sa.sa_sigaction = sigfpe; 258 sigemptyset(&sa.sa_mask); 259 sa.sa_flags = SA_SIGINFO; 260 sigaction(SIGFPE, &sa, 0); 261 signal_caught = 0; 262 263 /* 264 * exception unmasked, check SIGFPE delivery and correct siginfo 265 */ 266 for (t = test_ops; t->op != NULL; t++) { 267 fpsetmask(t->mask); 268 r = sigsetjmp(b, 1); 269 if (!r) { 270 (*t->op)(); 271 BARRIER(); 272 } 273 ATF_CHECK_EQ(signal_caught, 1); 274 ATF_CHECK_EQ(sicode, t->sicode); 275 signal_caught = 0; 276 } 277 } 278 279 void 280 sigfpe(int s, siginfo_t *si, void *c) 281 { 282 signal_caught = 1; 283 sicode = si->si_code; 284 siglongjmp(b, 1); 285 } 286 287 #define TEST(m, t) \ 288 ATF_TC(m##_##t); \ 289 \ 290 ATF_TC_HEAD(m##_##t, tc) \ 291 { \ 292 \ 293 atf_tc_set_md_var(tc, "descr", \ 294 "Test " ___STRING(m) " exceptions for " \ 295 ___STRING(t) "values"); \ 296 } \ 297 \ 298 ATF_TC_BODY(m##_##t, tc) \ 299 { \ 300 if (strcmp(MACHINE, "macppc") == 0) \ 301 atf_tc_expect_fail("PR port-macppc/46319"); \ 302 \ 303 if (isQEMU()) \ 304 atf_tc_expect_fail("PR misc/44767"); \ 305 \ 306 m(t##_ops); \ 307 } 308 309 TEST(fpsetmask_masked, float) 310 TEST(fpsetmask_masked, double) 311 TEST(fpsetmask_masked, long_double) 312 TEST(fpsetmask_unmasked, float) 313 TEST(fpsetmask_unmasked, double) 314 TEST(fpsetmask_unmasked, long_double) 315 316 ATF_TC(fpsetmask_basic); 317 ATF_TC_HEAD(fpsetmask_basic, tc) 318 { 319 atf_tc_set_md_var(tc, "descr", "A basic test of fpsetmask(3)"); 320 } 321 322 ATF_TC_BODY(fpsetmask_basic, tc) 323 { 324 size_t i; 325 fp_except_t msk, lst[] = { FP_X_INV, FP_X_DZ, FP_X_OFL, FP_X_UFL }; 326 327 msk = fpgetmask(); 328 for (i = 0; i < __arraycount(lst); i++) { 329 fpsetmask(msk | lst[i]); 330 ATF_CHECK((fpgetmask() & lst[i]) != 0); 331 fpsetmask(msk & lst[i]); 332 ATF_CHECK((fpgetmask() & lst[i]) == 0); 333 } 334 335 } 336 337 #endif /* defined(_FLOAT_IEEE754) */ 338 339 ATF_TP_ADD_TCS(tp) 340 { 341 342 #ifndef _FLOAT_IEEE754 343 ATF_TP_ADD_TC(tp, no_test); 344 #else 345 ATF_TP_ADD_TC(tp, fpsetmask_basic); 346 ATF_TP_ADD_TC(tp, fpsetmask_masked_float); 347 ATF_TP_ADD_TC(tp, fpsetmask_masked_double); 348 ATF_TP_ADD_TC(tp, fpsetmask_masked_long_double); 349 ATF_TP_ADD_TC(tp, fpsetmask_unmasked_float); 350 ATF_TP_ADD_TC(tp, fpsetmask_unmasked_double); 351 ATF_TP_ADD_TC(tp, fpsetmask_unmasked_long_double); 352 #endif 353 354 return atf_no_error(); 355 } 356