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