1*640235e2SEnji Cooper /* $NetBSD: t_fpsetmask.c,v 1.16 2016/03/12 11:55:14 martin Exp $ */ 257718be8SEnji Cooper 357718be8SEnji Cooper /*- 457718be8SEnji Cooper * Copyright (c) 1995 The NetBSD Foundation, Inc. 557718be8SEnji Cooper * All rights reserved. 657718be8SEnji Cooper * 757718be8SEnji Cooper * Redistribution and use in source and binary forms, with or without 857718be8SEnji Cooper * modification, are permitted provided that the following conditions 957718be8SEnji Cooper * are met: 1057718be8SEnji Cooper * 1. Redistributions of source code must retain the above copyright 1157718be8SEnji Cooper * notice, this list of conditions and the following disclaimer. 1257718be8SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright 1357718be8SEnji Cooper * notice, this list of conditions and the following disclaimer in the 1457718be8SEnji Cooper * documentation and/or other materials provided with the distribution. 1557718be8SEnji Cooper * 1657718be8SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 1757718be8SEnji Cooper * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 1857718be8SEnji Cooper * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 1957718be8SEnji Cooper * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2057718be8SEnji Cooper * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2157718be8SEnji Cooper * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2257718be8SEnji Cooper * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2357718be8SEnji Cooper * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2457718be8SEnji Cooper * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2557718be8SEnji Cooper * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2657718be8SEnji Cooper * POSSIBILITY OF SUCH DAMAGE. 2757718be8SEnji Cooper */ 2857718be8SEnji Cooper 2957718be8SEnji Cooper #include <sys/param.h> 3057718be8SEnji Cooper 3157718be8SEnji Cooper #include <atf-c.h> 3257718be8SEnji Cooper 3357718be8SEnji Cooper #include <stdio.h> 3457718be8SEnji Cooper #include <signal.h> 3557718be8SEnji Cooper #include <float.h> 3657718be8SEnji Cooper #include <setjmp.h> 3757718be8SEnji Cooper #include <stdlib.h> 3857718be8SEnji Cooper #include <string.h> 3957718be8SEnji Cooper 4057718be8SEnji Cooper #include "isqemu.h" 4157718be8SEnji Cooper 4257718be8SEnji Cooper #ifndef _FLOAT_IEEE754 4357718be8SEnji Cooper 4457718be8SEnji Cooper ATF_TC(no_test); 4557718be8SEnji Cooper ATF_TC_HEAD(no_test, tc) 4657718be8SEnji Cooper { 4757718be8SEnji Cooper 4857718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Dummy test case"); 4957718be8SEnji Cooper } 5057718be8SEnji Cooper 5157718be8SEnji Cooper ATF_TC_BODY(no_test, tc) 5257718be8SEnji Cooper { 5357718be8SEnji Cooper 5457718be8SEnji Cooper atf_tc_skip("Test not available on this architecture."); 5557718be8SEnji Cooper } 5657718be8SEnji Cooper 5757718be8SEnji Cooper #else /* defined(_FLOAT_IEEE754) */ 5857718be8SEnji Cooper 5957718be8SEnji Cooper #include <ieeefp.h> 6057718be8SEnji Cooper 61*640235e2SEnji Cooper #if __arm__ && !__SOFTFP__ 62*640235e2SEnji Cooper /* 63*640235e2SEnji Cooper * Some NEON fpus do not implement IEEE exception handling, 64*640235e2SEnji Cooper * skip these tests if running on them and compiled for 65*640235e2SEnji Cooper * hard float. 66*640235e2SEnji Cooper */ 67*640235e2SEnji Cooper #define FPU_PREREQ() \ 68*640235e2SEnji Cooper if (0 == fpsetmask(fpsetmask(FP_X_INV))) \ 69*640235e2SEnji Cooper atf_tc_skip("FPU does not implement exception handling"); 70*640235e2SEnji Cooper #endif 71*640235e2SEnji Cooper 72*640235e2SEnji Cooper #ifndef FPU_PREREQ 73*640235e2SEnji Cooper #define FPU_PREREQ() /* nothing */ 74*640235e2SEnji Cooper #endif 7557718be8SEnji Cooper 7657718be8SEnji Cooper void sigfpe(int, siginfo_t *, void *); 7757718be8SEnji Cooper 7857718be8SEnji Cooper volatile sig_atomic_t signal_caught; 7957718be8SEnji Cooper volatile int sicode; 8057718be8SEnji Cooper 8157718be8SEnji Cooper static volatile const float f_one = 1.0; 8257718be8SEnji Cooper static volatile const float f_zero = 0.0; 8357718be8SEnji Cooper static volatile const double d_one = 1.0; 8457718be8SEnji Cooper static volatile const double d_zero = 0.0; 8557718be8SEnji Cooper static volatile const long double ld_one = 1.0; 8657718be8SEnji Cooper static volatile const long double ld_zero = 0.0; 8757718be8SEnji Cooper 8857718be8SEnji Cooper static volatile const float f_huge = FLT_MAX; 8957718be8SEnji Cooper static volatile const float f_tiny = FLT_MIN; 9057718be8SEnji Cooper static volatile const double d_huge = DBL_MAX; 9157718be8SEnji Cooper static volatile const double d_tiny = DBL_MIN; 9257718be8SEnji Cooper static volatile const long double ld_huge = LDBL_MAX; 9357718be8SEnji Cooper static volatile const long double ld_tiny = LDBL_MIN; 9457718be8SEnji Cooper 9557718be8SEnji Cooper static volatile float f_x; 9657718be8SEnji Cooper static volatile double d_x; 9757718be8SEnji Cooper static volatile long double ld_x; 9857718be8SEnji Cooper 9957718be8SEnji Cooper /* trip divide by zero */ 10057718be8SEnji Cooper static void 10157718be8SEnji Cooper f_dz(void) 10257718be8SEnji Cooper { 10357718be8SEnji Cooper 10457718be8SEnji Cooper f_x = f_one / f_zero; 10557718be8SEnji Cooper } 10657718be8SEnji Cooper 10757718be8SEnji Cooper static void 10857718be8SEnji Cooper d_dz(void) 10957718be8SEnji Cooper { 11057718be8SEnji Cooper 11157718be8SEnji Cooper d_x = d_one / d_zero; 11257718be8SEnji Cooper } 11357718be8SEnji Cooper 11457718be8SEnji Cooper static void 11557718be8SEnji Cooper ld_dz(void) 11657718be8SEnji Cooper { 11757718be8SEnji Cooper 11857718be8SEnji Cooper ld_x = ld_one / ld_zero; 11957718be8SEnji Cooper } 12057718be8SEnji Cooper 12157718be8SEnji Cooper /* trip invalid operation */ 12257718be8SEnji Cooper static void 12357718be8SEnji Cooper d_inv(void) 12457718be8SEnji Cooper { 12557718be8SEnji Cooper 12657718be8SEnji Cooper d_x = d_zero / d_zero; 12757718be8SEnji Cooper } 12857718be8SEnji Cooper 12957718be8SEnji Cooper static void 13057718be8SEnji Cooper ld_inv(void) 13157718be8SEnji Cooper { 13257718be8SEnji Cooper 13357718be8SEnji Cooper ld_x = ld_zero / ld_zero; 13457718be8SEnji Cooper } 13557718be8SEnji Cooper 13657718be8SEnji Cooper static void 13757718be8SEnji Cooper f_inv(void) 13857718be8SEnji Cooper { 13957718be8SEnji Cooper 14057718be8SEnji Cooper f_x = f_zero / f_zero; 14157718be8SEnji Cooper } 14257718be8SEnji Cooper 14357718be8SEnji Cooper /* trip overflow */ 14457718be8SEnji Cooper static void 14557718be8SEnji Cooper f_ofl(void) 14657718be8SEnji Cooper { 14757718be8SEnji Cooper 14857718be8SEnji Cooper f_x = f_huge * f_huge; 14957718be8SEnji Cooper } 15057718be8SEnji Cooper 15157718be8SEnji Cooper static void 15257718be8SEnji Cooper d_ofl(void) 15357718be8SEnji Cooper { 15457718be8SEnji Cooper 15557718be8SEnji Cooper d_x = d_huge * d_huge; 15657718be8SEnji Cooper } 15757718be8SEnji Cooper 15857718be8SEnji Cooper static void 15957718be8SEnji Cooper ld_ofl(void) 16057718be8SEnji Cooper { 16157718be8SEnji Cooper 16257718be8SEnji Cooper ld_x = ld_huge * ld_huge; 16357718be8SEnji Cooper } 16457718be8SEnji Cooper 16557718be8SEnji Cooper /* trip underflow */ 16657718be8SEnji Cooper static void 16757718be8SEnji Cooper f_ufl(void) 16857718be8SEnji Cooper { 16957718be8SEnji Cooper 17057718be8SEnji Cooper f_x = f_tiny * f_tiny; 17157718be8SEnji Cooper } 17257718be8SEnji Cooper 17357718be8SEnji Cooper static void 17457718be8SEnji Cooper d_ufl(void) 17557718be8SEnji Cooper { 17657718be8SEnji Cooper 17757718be8SEnji Cooper d_x = d_tiny * d_tiny; 17857718be8SEnji Cooper } 17957718be8SEnji Cooper 18057718be8SEnji Cooper static void 18157718be8SEnji Cooper ld_ufl(void) 18257718be8SEnji Cooper { 18357718be8SEnji Cooper 18457718be8SEnji Cooper ld_x = ld_tiny * ld_tiny; 18557718be8SEnji Cooper } 18657718be8SEnji Cooper 18757718be8SEnji Cooper struct ops { 18857718be8SEnji Cooper void (*op)(void); 18957718be8SEnji Cooper fp_except mask; 19057718be8SEnji Cooper int sicode; 19157718be8SEnji Cooper }; 19257718be8SEnji Cooper 19357718be8SEnji Cooper static const struct ops float_ops[] = { 19457718be8SEnji Cooper { f_dz, FP_X_DZ, FPE_FLTDIV }, 19557718be8SEnji Cooper { f_inv, FP_X_INV, FPE_FLTINV }, 19657718be8SEnji Cooper { f_ofl, FP_X_OFL, FPE_FLTOVF }, 19757718be8SEnji Cooper { f_ufl, FP_X_UFL, FPE_FLTUND }, 19857718be8SEnji Cooper { NULL, 0, 0 } 19957718be8SEnji Cooper }; 20057718be8SEnji Cooper 20157718be8SEnji Cooper static const struct ops double_ops[] = { 20257718be8SEnji Cooper { d_dz, FP_X_DZ, FPE_FLTDIV }, 20357718be8SEnji Cooper { d_inv, FP_X_INV, FPE_FLTINV }, 20457718be8SEnji Cooper { d_ofl, FP_X_OFL, FPE_FLTOVF }, 20557718be8SEnji Cooper { d_ufl, FP_X_UFL, FPE_FLTUND }, 20657718be8SEnji Cooper { NULL, 0, 0 } 20757718be8SEnji Cooper }; 20857718be8SEnji Cooper 20957718be8SEnji Cooper static const struct ops long_double_ops[] = { 21057718be8SEnji Cooper { ld_dz, FP_X_DZ, FPE_FLTDIV }, 21157718be8SEnji Cooper { ld_inv, FP_X_INV, FPE_FLTINV }, 21257718be8SEnji Cooper { ld_ofl, FP_X_OFL, FPE_FLTOVF }, 21357718be8SEnji Cooper { ld_ufl, FP_X_UFL, FPE_FLTUND }, 21457718be8SEnji Cooper { NULL, 0, 0 } 21557718be8SEnji Cooper }; 21657718be8SEnji Cooper 21757718be8SEnji Cooper static sigjmp_buf b; 21857718be8SEnji Cooper 21957718be8SEnji Cooper static void 22057718be8SEnji Cooper fpsetmask_masked(const struct ops *test_ops) 22157718be8SEnji Cooper { 22257718be8SEnji Cooper struct sigaction sa; 22357718be8SEnji Cooper fp_except ex1, ex2; 22457718be8SEnji Cooper const struct ops *t; 22557718be8SEnji Cooper 22657718be8SEnji Cooper /* mask all exceptions, clear history */ 22757718be8SEnji Cooper fpsetmask(0); 22857718be8SEnji Cooper fpsetsticky(0); 22957718be8SEnji Cooper 23057718be8SEnji Cooper /* set up signal handler */ 23157718be8SEnji Cooper sa.sa_sigaction = sigfpe; 23257718be8SEnji Cooper sigemptyset(&sa.sa_mask); 23357718be8SEnji Cooper sa.sa_flags = SA_SIGINFO; 23457718be8SEnji Cooper sigaction(SIGFPE, &sa, 0); 23557718be8SEnji Cooper signal_caught = 0; 23657718be8SEnji Cooper 23757718be8SEnji Cooper /* 23857718be8SEnji Cooper * exceptions masked, check whether "sticky" bits are set correctly 23957718be8SEnji Cooper */ 24057718be8SEnji Cooper for (t = test_ops; t->op != NULL; t++) { 24157718be8SEnji Cooper (*t->op)(); 24257718be8SEnji Cooper ex1 = fpgetsticky(); 24357718be8SEnji Cooper ATF_CHECK_EQ(ex1 & t->mask, t->mask); 24457718be8SEnji Cooper ATF_CHECK_EQ(signal_caught, 0); 24557718be8SEnji Cooper 24657718be8SEnji Cooper /* check correct fpsetsticky() behaviour */ 24757718be8SEnji Cooper ex2 = fpsetsticky(0); 24857718be8SEnji Cooper ATF_CHECK_EQ(fpgetsticky(), 0); 24957718be8SEnji Cooper ATF_CHECK_EQ(ex1, ex2); 25057718be8SEnji Cooper } 25157718be8SEnji Cooper } 25257718be8SEnji Cooper 25357718be8SEnji Cooper /* force delayed exceptions to be delivered */ 25457718be8SEnji Cooper #define BARRIER() fpsetmask(0); f_x = f_one * f_one 25557718be8SEnji Cooper 25657718be8SEnji Cooper static void 25757718be8SEnji Cooper fpsetmask_unmasked(const struct ops *test_ops) 25857718be8SEnji Cooper { 25957718be8SEnji Cooper struct sigaction sa; 26057718be8SEnji Cooper int r; 26157718be8SEnji Cooper const struct ops *volatile t; 26257718be8SEnji Cooper 26357718be8SEnji Cooper /* mask all exceptions, clear history */ 26457718be8SEnji Cooper fpsetmask(0); 26557718be8SEnji Cooper fpsetsticky(0); 26657718be8SEnji Cooper 26757718be8SEnji Cooper /* set up signal handler */ 26857718be8SEnji Cooper sa.sa_sigaction = sigfpe; 26957718be8SEnji Cooper sigemptyset(&sa.sa_mask); 27057718be8SEnji Cooper sa.sa_flags = SA_SIGINFO; 27157718be8SEnji Cooper sigaction(SIGFPE, &sa, 0); 27257718be8SEnji Cooper signal_caught = 0; 27357718be8SEnji Cooper 27457718be8SEnji Cooper /* 27557718be8SEnji Cooper * exception unmasked, check SIGFPE delivery and correct siginfo 27657718be8SEnji Cooper */ 27757718be8SEnji Cooper for (t = test_ops; t->op != NULL; t++) { 27857718be8SEnji Cooper fpsetmask(t->mask); 27957718be8SEnji Cooper r = sigsetjmp(b, 1); 28057718be8SEnji Cooper if (!r) { 28157718be8SEnji Cooper (*t->op)(); 28257718be8SEnji Cooper BARRIER(); 28357718be8SEnji Cooper } 28457718be8SEnji Cooper ATF_CHECK_EQ(signal_caught, 1); 28557718be8SEnji Cooper ATF_CHECK_EQ(sicode, t->sicode); 28657718be8SEnji Cooper signal_caught = 0; 28757718be8SEnji Cooper } 28857718be8SEnji Cooper } 28957718be8SEnji Cooper 29057718be8SEnji Cooper void 29157718be8SEnji Cooper sigfpe(int s, siginfo_t *si, void *c) 29257718be8SEnji Cooper { 29357718be8SEnji Cooper signal_caught = 1; 29457718be8SEnji Cooper sicode = si->si_code; 29557718be8SEnji Cooper siglongjmp(b, 1); 29657718be8SEnji Cooper } 29757718be8SEnji Cooper 29857718be8SEnji Cooper #define TEST(m, t) \ 29957718be8SEnji Cooper ATF_TC(m##_##t); \ 30057718be8SEnji Cooper \ 30157718be8SEnji Cooper ATF_TC_HEAD(m##_##t, tc) \ 30257718be8SEnji Cooper { \ 30357718be8SEnji Cooper \ 30457718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", \ 30557718be8SEnji Cooper "Test " ___STRING(m) " exceptions for " \ 30657718be8SEnji Cooper ___STRING(t) "values"); \ 30757718be8SEnji Cooper } \ 30857718be8SEnji Cooper \ 30957718be8SEnji Cooper ATF_TC_BODY(m##_##t, tc) \ 31057718be8SEnji Cooper { \ 311*640235e2SEnji Cooper \ 312*640235e2SEnji Cooper FPU_PREREQ(); \ 313*640235e2SEnji Cooper \ 31457718be8SEnji Cooper if (strcmp(MACHINE, "macppc") == 0) \ 31557718be8SEnji Cooper atf_tc_expect_fail("PR port-macppc/46319"); \ 31657718be8SEnji Cooper \ 31757718be8SEnji Cooper if (isQEMU()) \ 31857718be8SEnji Cooper atf_tc_expect_fail("PR misc/44767"); \ 31957718be8SEnji Cooper \ 32057718be8SEnji Cooper m(t##_ops); \ 32157718be8SEnji Cooper } 32257718be8SEnji Cooper 32357718be8SEnji Cooper TEST(fpsetmask_masked, float) 32457718be8SEnji Cooper TEST(fpsetmask_masked, double) 32557718be8SEnji Cooper TEST(fpsetmask_masked, long_double) 32657718be8SEnji Cooper TEST(fpsetmask_unmasked, float) 32757718be8SEnji Cooper TEST(fpsetmask_unmasked, double) 32857718be8SEnji Cooper TEST(fpsetmask_unmasked, long_double) 32957718be8SEnji Cooper 33057718be8SEnji Cooper ATF_TC(fpsetmask_basic); 33157718be8SEnji Cooper ATF_TC_HEAD(fpsetmask_basic, tc) 33257718be8SEnji Cooper { 33357718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "A basic test of fpsetmask(3)"); 33457718be8SEnji Cooper } 33557718be8SEnji Cooper 33657718be8SEnji Cooper ATF_TC_BODY(fpsetmask_basic, tc) 33757718be8SEnji Cooper { 33857718be8SEnji Cooper size_t i; 33957718be8SEnji Cooper fp_except_t msk, lst[] = { FP_X_INV, FP_X_DZ, FP_X_OFL, FP_X_UFL }; 34057718be8SEnji Cooper 341*640235e2SEnji Cooper FPU_PREREQ(); 342*640235e2SEnji Cooper 34357718be8SEnji Cooper msk = fpgetmask(); 34457718be8SEnji Cooper for (i = 0; i < __arraycount(lst); i++) { 34557718be8SEnji Cooper fpsetmask(msk | lst[i]); 34657718be8SEnji Cooper ATF_CHECK((fpgetmask() & lst[i]) != 0); 347*640235e2SEnji Cooper fpsetmask(msk & ~lst[i]); 34857718be8SEnji Cooper ATF_CHECK((fpgetmask() & lst[i]) == 0); 34957718be8SEnji Cooper } 35057718be8SEnji Cooper 35157718be8SEnji Cooper } 35257718be8SEnji Cooper 35357718be8SEnji Cooper #endif /* defined(_FLOAT_IEEE754) */ 35457718be8SEnji Cooper 35557718be8SEnji Cooper ATF_TP_ADD_TCS(tp) 35657718be8SEnji Cooper { 35757718be8SEnji Cooper 35857718be8SEnji Cooper #ifndef _FLOAT_IEEE754 35957718be8SEnji Cooper ATF_TP_ADD_TC(tp, no_test); 36057718be8SEnji Cooper #else 36157718be8SEnji Cooper ATF_TP_ADD_TC(tp, fpsetmask_basic); 36257718be8SEnji Cooper ATF_TP_ADD_TC(tp, fpsetmask_masked_float); 36357718be8SEnji Cooper ATF_TP_ADD_TC(tp, fpsetmask_masked_double); 36457718be8SEnji Cooper ATF_TP_ADD_TC(tp, fpsetmask_masked_long_double); 36557718be8SEnji Cooper ATF_TP_ADD_TC(tp, fpsetmask_unmasked_float); 36657718be8SEnji Cooper ATF_TP_ADD_TC(tp, fpsetmask_unmasked_double); 36757718be8SEnji Cooper ATF_TP_ADD_TC(tp, fpsetmask_unmasked_long_double); 36857718be8SEnji Cooper #endif 36957718be8SEnji Cooper 37057718be8SEnji Cooper return atf_no_error(); 37157718be8SEnji Cooper } 372