1309466Sngie/* $NetBSD: t_fpsetmask.c,v 1.16 2016/03/12 11:55:14 martin Exp $ */ 2272343Sngie 3272343Sngie/*- 4272343Sngie * Copyright (c) 1995 The NetBSD Foundation, Inc. 5272343Sngie * All rights reserved. 6272343Sngie * 7272343Sngie * Redistribution and use in source and binary forms, with or without 8272343Sngie * modification, are permitted provided that the following conditions 9272343Sngie * are met: 10272343Sngie * 1. Redistributions of source code must retain the above copyright 11272343Sngie * notice, this list of conditions and the following disclaimer. 12272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 13272343Sngie * notice, this list of conditions and the following disclaimer in the 14272343Sngie * documentation and/or other materials provided with the distribution. 15272343Sngie * 16272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18272343Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19272343Sngie * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20272343Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21272343Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22272343Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24272343Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26272343Sngie * POSSIBILITY OF SUCH DAMAGE. 27272343Sngie */ 28272343Sngie 29272343Sngie#include <sys/param.h> 30272343Sngie 31272343Sngie#include <atf-c.h> 32272343Sngie 33272343Sngie#include <stdio.h> 34272343Sngie#include <signal.h> 35272343Sngie#include <float.h> 36272343Sngie#include <setjmp.h> 37272343Sngie#include <stdlib.h> 38272343Sngie#include <string.h> 39272343Sngie 40272343Sngie#include "isqemu.h" 41272343Sngie 42272343Sngie#ifndef _FLOAT_IEEE754 43272343Sngie 44272343SngieATF_TC(no_test); 45272343SngieATF_TC_HEAD(no_test, tc) 46272343Sngie{ 47272343Sngie 48272343Sngie atf_tc_set_md_var(tc, "descr", "Dummy test case"); 49272343Sngie} 50272343Sngie 51272343SngieATF_TC_BODY(no_test, tc) 52272343Sngie{ 53272343Sngie 54272343Sngie atf_tc_skip("Test not available on this architecture."); 55272343Sngie} 56272343Sngie 57272343Sngie#else /* defined(_FLOAT_IEEE754) */ 58272343Sngie 59272343Sngie#include <ieeefp.h> 60272343Sngie 61309466Sngie#if __arm__ && !__SOFTFP__ 62309466Sngie /* 63309466Sngie * Some NEON fpus do not implement IEEE exception handling, 64309466Sngie * skip these tests if running on them and compiled for 65309466Sngie * hard float. 66309466Sngie */ 67309466Sngie#define FPU_PREREQ() \ 68309466Sngie if (0 == fpsetmask(fpsetmask(FP_X_INV))) \ 69309466Sngie atf_tc_skip("FPU does not implement exception handling"); 70309466Sngie#endif 71272343Sngie 72309466Sngie#ifndef FPU_PREREQ 73309466Sngie#define FPU_PREREQ() /* nothing */ 74309466Sngie#endif 75309466Sngie 76272343Sngievoid sigfpe(int, siginfo_t *, void *); 77272343Sngie 78272343Sngievolatile sig_atomic_t signal_caught; 79272343Sngievolatile int sicode; 80272343Sngie 81272343Sngiestatic volatile const float f_one = 1.0; 82272343Sngiestatic volatile const float f_zero = 0.0; 83272343Sngiestatic volatile const double d_one = 1.0; 84272343Sngiestatic volatile const double d_zero = 0.0; 85272343Sngiestatic volatile const long double ld_one = 1.0; 86272343Sngiestatic volatile const long double ld_zero = 0.0; 87272343Sngie 88272343Sngiestatic volatile const float f_huge = FLT_MAX; 89272343Sngiestatic volatile const float f_tiny = FLT_MIN; 90272343Sngiestatic volatile const double d_huge = DBL_MAX; 91272343Sngiestatic volatile const double d_tiny = DBL_MIN; 92272343Sngiestatic volatile const long double ld_huge = LDBL_MAX; 93272343Sngiestatic volatile const long double ld_tiny = LDBL_MIN; 94272343Sngie 95272343Sngiestatic volatile float f_x; 96272343Sngiestatic volatile double d_x; 97272343Sngiestatic volatile long double ld_x; 98272343Sngie 99272343Sngie/* trip divide by zero */ 100272343Sngiestatic void 101272343Sngief_dz(void) 102272343Sngie{ 103272343Sngie 104272343Sngie f_x = f_one / f_zero; 105272343Sngie} 106272343Sngie 107272343Sngiestatic void 108272343Sngied_dz(void) 109272343Sngie{ 110272343Sngie 111272343Sngie d_x = d_one / d_zero; 112272343Sngie} 113272343Sngie 114272343Sngiestatic void 115272343Sngield_dz(void) 116272343Sngie{ 117272343Sngie 118272343Sngie ld_x = ld_one / ld_zero; 119272343Sngie} 120272343Sngie 121272343Sngie/* trip invalid operation */ 122272343Sngiestatic void 123272343Sngied_inv(void) 124272343Sngie{ 125272343Sngie 126272343Sngie d_x = d_zero / d_zero; 127272343Sngie} 128272343Sngie 129272343Sngiestatic void 130272343Sngield_inv(void) 131272343Sngie{ 132272343Sngie 133272343Sngie ld_x = ld_zero / ld_zero; 134272343Sngie} 135272343Sngie 136272343Sngiestatic void 137272343Sngief_inv(void) 138272343Sngie{ 139272343Sngie 140272343Sngie f_x = f_zero / f_zero; 141272343Sngie} 142272343Sngie 143272343Sngie/* trip overflow */ 144272343Sngiestatic void 145272343Sngief_ofl(void) 146272343Sngie{ 147272343Sngie 148272343Sngie f_x = f_huge * f_huge; 149272343Sngie} 150272343Sngie 151272343Sngiestatic void 152272343Sngied_ofl(void) 153272343Sngie{ 154272343Sngie 155272343Sngie d_x = d_huge * d_huge; 156272343Sngie} 157272343Sngie 158272343Sngiestatic void 159272343Sngield_ofl(void) 160272343Sngie{ 161272343Sngie 162272343Sngie ld_x = ld_huge * ld_huge; 163272343Sngie} 164272343Sngie 165272343Sngie/* trip underflow */ 166272343Sngiestatic void 167272343Sngief_ufl(void) 168272343Sngie{ 169272343Sngie 170272343Sngie f_x = f_tiny * f_tiny; 171272343Sngie} 172272343Sngie 173272343Sngiestatic void 174272343Sngied_ufl(void) 175272343Sngie{ 176272343Sngie 177272343Sngie d_x = d_tiny * d_tiny; 178272343Sngie} 179272343Sngie 180272343Sngiestatic void 181272343Sngield_ufl(void) 182272343Sngie{ 183272343Sngie 184272343Sngie ld_x = ld_tiny * ld_tiny; 185272343Sngie} 186272343Sngie 187272343Sngiestruct ops { 188272343Sngie void (*op)(void); 189272343Sngie fp_except mask; 190272343Sngie int sicode; 191272343Sngie}; 192272343Sngie 193272343Sngiestatic const struct ops float_ops[] = { 194272343Sngie { f_dz, FP_X_DZ, FPE_FLTDIV }, 195272343Sngie { f_inv, FP_X_INV, FPE_FLTINV }, 196272343Sngie { f_ofl, FP_X_OFL, FPE_FLTOVF }, 197272343Sngie { f_ufl, FP_X_UFL, FPE_FLTUND }, 198272343Sngie { NULL, 0, 0 } 199272343Sngie}; 200272343Sngie 201272343Sngiestatic const struct ops double_ops[] = { 202272343Sngie { d_dz, FP_X_DZ, FPE_FLTDIV }, 203272343Sngie { d_inv, FP_X_INV, FPE_FLTINV }, 204272343Sngie { d_ofl, FP_X_OFL, FPE_FLTOVF }, 205272343Sngie { d_ufl, FP_X_UFL, FPE_FLTUND }, 206272343Sngie { NULL, 0, 0 } 207272343Sngie}; 208272343Sngie 209272343Sngiestatic const struct ops long_double_ops[] = { 210272343Sngie { ld_dz, FP_X_DZ, FPE_FLTDIV }, 211272343Sngie { ld_inv, FP_X_INV, FPE_FLTINV }, 212272343Sngie { ld_ofl, FP_X_OFL, FPE_FLTOVF }, 213272343Sngie { ld_ufl, FP_X_UFL, FPE_FLTUND }, 214272343Sngie { NULL, 0, 0 } 215272343Sngie}; 216272343Sngie 217272343Sngiestatic sigjmp_buf b; 218272343Sngie 219272343Sngiestatic void 220272343Sngiefpsetmask_masked(const struct ops *test_ops) 221272343Sngie{ 222272343Sngie struct sigaction sa; 223272343Sngie fp_except ex1, ex2; 224272343Sngie const struct ops *t; 225272343Sngie 226272343Sngie /* mask all exceptions, clear history */ 227272343Sngie fpsetmask(0); 228272343Sngie fpsetsticky(0); 229272343Sngie 230272343Sngie /* set up signal handler */ 231272343Sngie sa.sa_sigaction = sigfpe; 232272343Sngie sigemptyset(&sa.sa_mask); 233272343Sngie sa.sa_flags = SA_SIGINFO; 234272343Sngie sigaction(SIGFPE, &sa, 0); 235272343Sngie signal_caught = 0; 236272343Sngie 237272343Sngie /* 238272343Sngie * exceptions masked, check whether "sticky" bits are set correctly 239272343Sngie */ 240272343Sngie for (t = test_ops; t->op != NULL; t++) { 241272343Sngie (*t->op)(); 242272343Sngie ex1 = fpgetsticky(); 243272343Sngie ATF_CHECK_EQ(ex1 & t->mask, t->mask); 244272343Sngie ATF_CHECK_EQ(signal_caught, 0); 245272343Sngie 246272343Sngie /* check correct fpsetsticky() behaviour */ 247272343Sngie ex2 = fpsetsticky(0); 248272343Sngie ATF_CHECK_EQ(fpgetsticky(), 0); 249272343Sngie ATF_CHECK_EQ(ex1, ex2); 250272343Sngie } 251272343Sngie} 252272343Sngie 253272343Sngie/* force delayed exceptions to be delivered */ 254272343Sngie#define BARRIER() fpsetmask(0); f_x = f_one * f_one 255272343Sngie 256272343Sngiestatic void 257272343Sngiefpsetmask_unmasked(const struct ops *test_ops) 258272343Sngie{ 259272343Sngie struct sigaction sa; 260272343Sngie int r; 261272343Sngie const struct ops *volatile t; 262272343Sngie 263272343Sngie /* mask all exceptions, clear history */ 264272343Sngie fpsetmask(0); 265272343Sngie fpsetsticky(0); 266272343Sngie 267272343Sngie /* set up signal handler */ 268272343Sngie sa.sa_sigaction = sigfpe; 269272343Sngie sigemptyset(&sa.sa_mask); 270272343Sngie sa.sa_flags = SA_SIGINFO; 271272343Sngie sigaction(SIGFPE, &sa, 0); 272272343Sngie signal_caught = 0; 273272343Sngie 274272343Sngie /* 275272343Sngie * exception unmasked, check SIGFPE delivery and correct siginfo 276272343Sngie */ 277272343Sngie for (t = test_ops; t->op != NULL; t++) { 278272343Sngie fpsetmask(t->mask); 279272343Sngie r = sigsetjmp(b, 1); 280272343Sngie if (!r) { 281272343Sngie (*t->op)(); 282272343Sngie BARRIER(); 283272343Sngie } 284272343Sngie ATF_CHECK_EQ(signal_caught, 1); 285272343Sngie ATF_CHECK_EQ(sicode, t->sicode); 286272343Sngie signal_caught = 0; 287272343Sngie } 288272343Sngie} 289272343Sngie 290272343Sngievoid 291272343Sngiesigfpe(int s, siginfo_t *si, void *c) 292272343Sngie{ 293272343Sngie signal_caught = 1; 294272343Sngie sicode = si->si_code; 295272343Sngie siglongjmp(b, 1); 296272343Sngie} 297272343Sngie 298272343Sngie#define TEST(m, t) \ 299272343Sngie ATF_TC(m##_##t); \ 300272343Sngie \ 301272343Sngie ATF_TC_HEAD(m##_##t, tc) \ 302272343Sngie { \ 303272343Sngie \ 304272343Sngie atf_tc_set_md_var(tc, "descr", \ 305272343Sngie "Test " ___STRING(m) " exceptions for " \ 306272343Sngie ___STRING(t) "values"); \ 307272343Sngie } \ 308272343Sngie \ 309272343Sngie ATF_TC_BODY(m##_##t, tc) \ 310272343Sngie { \ 311309466Sngie \ 312309466Sngie FPU_PREREQ(); \ 313309466Sngie \ 314272343Sngie if (strcmp(MACHINE, "macppc") == 0) \ 315272343Sngie atf_tc_expect_fail("PR port-macppc/46319"); \ 316272343Sngie \ 317272343Sngie if (isQEMU()) \ 318272343Sngie atf_tc_expect_fail("PR misc/44767"); \ 319272343Sngie \ 320272343Sngie m(t##_ops); \ 321272343Sngie } 322272343Sngie 323272343SngieTEST(fpsetmask_masked, float) 324272343SngieTEST(fpsetmask_masked, double) 325272343SngieTEST(fpsetmask_masked, long_double) 326272343SngieTEST(fpsetmask_unmasked, float) 327272343SngieTEST(fpsetmask_unmasked, double) 328272343SngieTEST(fpsetmask_unmasked, long_double) 329272343Sngie 330272343SngieATF_TC(fpsetmask_basic); 331272343SngieATF_TC_HEAD(fpsetmask_basic, tc) 332272343Sngie{ 333272343Sngie atf_tc_set_md_var(tc, "descr", "A basic test of fpsetmask(3)"); 334272343Sngie} 335272343Sngie 336272343SngieATF_TC_BODY(fpsetmask_basic, tc) 337272343Sngie{ 338272343Sngie size_t i; 339272343Sngie fp_except_t msk, lst[] = { FP_X_INV, FP_X_DZ, FP_X_OFL, FP_X_UFL }; 340272343Sngie 341309466Sngie FPU_PREREQ(); 342309466Sngie 343272343Sngie msk = fpgetmask(); 344272343Sngie for (i = 0; i < __arraycount(lst); i++) { 345272343Sngie fpsetmask(msk | lst[i]); 346272343Sngie ATF_CHECK((fpgetmask() & lst[i]) != 0); 347309466Sngie fpsetmask(msk & ~lst[i]); 348272343Sngie ATF_CHECK((fpgetmask() & lst[i]) == 0); 349272343Sngie } 350272343Sngie 351272343Sngie} 352272343Sngie 353272343Sngie#endif /* defined(_FLOAT_IEEE754) */ 354272343Sngie 355272343SngieATF_TP_ADD_TCS(tp) 356272343Sngie{ 357272343Sngie 358272343Sngie#ifndef _FLOAT_IEEE754 359272343Sngie ATF_TP_ADD_TC(tp, no_test); 360272343Sngie#else 361272343Sngie ATF_TP_ADD_TC(tp, fpsetmask_basic); 362272343Sngie ATF_TP_ADD_TC(tp, fpsetmask_masked_float); 363272343Sngie ATF_TP_ADD_TC(tp, fpsetmask_masked_double); 364272343Sngie ATF_TP_ADD_TC(tp, fpsetmask_masked_long_double); 365272343Sngie ATF_TP_ADD_TC(tp, fpsetmask_unmasked_float); 366272343Sngie ATF_TP_ADD_TC(tp, fpsetmask_unmasked_double); 367272343Sngie ATF_TP_ADD_TC(tp, fpsetmask_unmasked_long_double); 368272343Sngie#endif 369272343Sngie 370272343Sngie return atf_no_error(); 371272343Sngie} 372