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