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