t_fpsetmask.c revision 276478
1219019Sgabor/* $NetBSD: t_fpsetmask.c,v 1.14 2014/11/04 00:20:19 justin Exp $ */ 2219019Sgabor 3219019Sgabor/*- 4219019Sgabor * Copyright (c) 1995 The NetBSD Foundation, Inc. 5219019Sgabor * All rights reserved. 6219019Sgabor * 7219019Sgabor * Redistribution and use in source and binary forms, with or without 8219019Sgabor * modification, are permitted provided that the following conditions 9219019Sgabor * are met: 10219019Sgabor * 1. Redistributions of source code must retain the above copyright 11219019Sgabor * notice, this list of conditions and the following disclaimer. 12219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright 13219019Sgabor * notice, this list of conditions and the following disclaimer in the 14219019Sgabor * documentation and/or other materials provided with the distribution. 15219019Sgabor * 16219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17219019Sgabor * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18219019Sgabor * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19219019Sgabor * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20219019Sgabor * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21219019Sgabor * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22219019Sgabor * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23219019Sgabor * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24219019Sgabor * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25219019Sgabor * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26219019Sgabor * POSSIBILITY OF SUCH DAMAGE. 27219019Sgabor */ 28219019Sgabor 29219019Sgabor#include <sys/param.h> 30219019Sgabor 31219019Sgabor#include <atf-c.h> 32219019Sgabor 33219019Sgabor#include <stdio.h> 34219019Sgabor#include <signal.h> 35219019Sgabor#include <float.h> 36219019Sgabor#include <setjmp.h> 37219019Sgabor#include <stdlib.h> 38219019Sgabor#include <string.h> 39219019Sgabor 40219019Sgabor#include "isqemu.h" 41219019Sgabor 42219019Sgabor#ifndef _FLOAT_IEEE754 43219019Sgabor 44267665StijlATF_TC(no_test); 45267665StijlATF_TC_HEAD(no_test, tc) 46267665Stijl{ 47219019Sgabor 48267665Stijl atf_tc_set_md_var(tc, "descr", "Dummy test case"); 49219019Sgabor} 50219019Sgabor 51219019SgaborATF_TC_BODY(no_test, tc) 52219019Sgabor{ 53219019Sgabor 54219019Sgabor atf_tc_skip("Test not available on this architecture."); 55219019Sgabor} 56219019Sgabor 57219019Sgabor#else /* defined(_FLOAT_IEEE754) */ 58219019Sgabor 59219019Sgabor#include <ieeefp.h> 60219019Sgabor 61219019Sgaborconst char *skip_mesg; 62219019Sgaborconst char *skip_arch; 63219019Sgabor 64219019Sgaborvoid sigfpe(int, siginfo_t *, void *); 65219019Sgabor 66219019Sgaborvolatile sig_atomic_t signal_caught; 67219019Sgaborvolatile int sicode; 68219019Sgabor 69267665Stijlstatic volatile const float f_one = 1.0; 70219019Sgaborstatic volatile const float f_zero = 0.0; 71219019Sgaborstatic volatile const double d_one = 1.0; 72219019Sgaborstatic volatile const double d_zero = 0.0; 73219019Sgaborstatic volatile const long double ld_one = 1.0; 74282275Stijlstatic volatile const long double ld_zero = 0.0; 75267665Stijl 76219019Sgaborstatic volatile const float f_huge = FLT_MAX; 77219019Sgaborstatic volatile const float f_tiny = FLT_MIN; 78219019Sgaborstatic volatile const double d_huge = DBL_MAX; 79219019Sgaborstatic volatile const double d_tiny = DBL_MIN; 80219019Sgaborstatic volatile const long double ld_huge = LDBL_MAX; 81219019Sgaborstatic volatile const long double ld_tiny = LDBL_MIN; 82219019Sgabor 83219019Sgaborstatic volatile float f_x; 84219019Sgaborstatic volatile double d_x; 85267665Stijlstatic volatile long double ld_x; 86219019Sgabor 87267665Stijl/* trip divide by zero */ 88219019Sgaborstatic void 89219019Sgaborf_dz(void) 90219019Sgabor{ 91219019Sgabor 92219019Sgabor f_x = f_one / f_zero; 93219019Sgabor} 94219019Sgabor 95219019Sgaborstatic void 96219019Sgabord_dz(void) 97219019Sgabor{ 98219019Sgabor 99219019Sgabor d_x = d_one / d_zero; 100219019Sgabor} 101219019Sgabor 102219019Sgaborstatic void 103219019Sgaborld_dz(void) 104219019Sgabor{ 105219019Sgabor 106219019Sgabor ld_x = ld_one / ld_zero; 107219019Sgabor} 108219019Sgabor 109219019Sgabor/* trip invalid operation */ 110219019Sgaborstatic void 111219019Sgabord_inv(void) 112219019Sgabor{ 113219019Sgabor 114219019Sgabor d_x = d_zero / d_zero; 115219019Sgabor} 116219019Sgabor 117219019Sgaborstatic void 118219019Sgaborld_inv(void) 119219019Sgabor{ 120219019Sgabor 121219019Sgabor ld_x = ld_zero / ld_zero; 122219019Sgabor} 123219019Sgabor 124219019Sgaborstatic void 125219019Sgaborf_inv(void) 126219019Sgabor{ 127219019Sgabor 128219019Sgabor f_x = f_zero / f_zero; 129219019Sgabor} 130219019Sgabor 131219019Sgabor/* trip overflow */ 132219019Sgaborstatic void 133219019Sgaborf_ofl(void) 134219019Sgabor{ 135219019Sgabor 136219019Sgabor f_x = f_huge * f_huge; 137267665Stijl} 138219019Sgabor 139219019Sgaborstatic void 140219019Sgabord_ofl(void) 141219019Sgabor{ 142219019Sgabor 143219019Sgabor d_x = d_huge * d_huge; 144219019Sgabor} 145219019Sgabor 146219019Sgaborstatic void 147219019Sgaborld_ofl(void) 148219019Sgabor{ 149219019Sgabor 150219019Sgabor ld_x = ld_huge * ld_huge; 151219019Sgabor} 152219019Sgabor 153219019Sgabor/* trip underflow */ 154219019Sgaborstatic void 155219019Sgaborf_ufl(void) 156219019Sgabor{ 157219019Sgabor 158219019Sgabor f_x = f_tiny * f_tiny; 159287794Sdelphij} 160267665Stijl 161219019Sgaborstatic void 162219019Sgabord_ufl(void) 163287794Sdelphij{ 164219019Sgabor 165219019Sgabor d_x = d_tiny * d_tiny; 166219019Sgabor} 167219019Sgabor 168219019Sgaborstatic void 169219019Sgaborld_ufl(void) 170219019Sgabor{ 171219019Sgabor 172219019Sgabor ld_x = ld_tiny * ld_tiny; 173219019Sgabor} 174219019Sgabor 175219019Sgaborstruct ops { 176219019Sgabor void (*op)(void); 177219019Sgabor fp_except mask; 178219019Sgabor int sicode; 179219019Sgabor}; 180219019Sgabor 181219019Sgaborstatic const struct ops float_ops[] = { 182219019Sgabor { f_dz, FP_X_DZ, FPE_FLTDIV }, 183219019Sgabor { f_inv, FP_X_INV, FPE_FLTINV }, 184219019Sgabor { f_ofl, FP_X_OFL, FPE_FLTOVF }, 185219019Sgabor { f_ufl, FP_X_UFL, FPE_FLTUND }, 186219019Sgabor { NULL, 0, 0 } 187219019Sgabor}; 188219019Sgabor 189287794Sdelphijstatic const struct ops double_ops[] = { 190219019Sgabor { d_dz, FP_X_DZ, FPE_FLTDIV }, 191219019Sgabor { d_inv, FP_X_INV, FPE_FLTINV }, 192219019Sgabor { d_ofl, FP_X_OFL, FPE_FLTOVF }, 193219019Sgabor { d_ufl, FP_X_UFL, FPE_FLTUND }, 194287794Sdelphij { NULL, 0, 0 } 195219019Sgabor}; 196219019Sgabor 197219019Sgaborstatic const struct ops long_double_ops[] = { 198219019Sgabor { ld_dz, FP_X_DZ, FPE_FLTDIV }, 199219019Sgabor { ld_inv, FP_X_INV, FPE_FLTINV }, 200219019Sgabor { ld_ofl, FP_X_OFL, FPE_FLTOVF }, 201219019Sgabor { ld_ufl, FP_X_UFL, FPE_FLTUND }, 202219019Sgabor { NULL, 0, 0 } 203219019Sgabor}; 204219019Sgabor 205267665Stijlstatic sigjmp_buf b; 206219019Sgabor 207267665Stijlstatic void 208219019Sgaborfpsetmask_masked(const struct ops *test_ops) 209219019Sgabor{ 210219019Sgabor struct sigaction sa; 211219019Sgabor fp_except ex1, ex2; 212219019Sgabor const struct ops *t; 213219019Sgabor 214267665Stijl /* mask all exceptions, clear history */ 215219019Sgabor fpsetmask(0); 216219019Sgabor fpsetsticky(0); 217219019Sgabor 218267665Stijl /* set up signal handler */ 219219019Sgabor 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 244static void 245fpsetmask_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 278void 279sigfpe(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 308TEST(fpsetmask_masked, float) 309TEST(fpsetmask_masked, double) 310TEST(fpsetmask_masked, long_double) 311TEST(fpsetmask_unmasked, float) 312TEST(fpsetmask_unmasked, double) 313TEST(fpsetmask_unmasked, long_double) 314 315ATF_TC(fpsetmask_basic); 316ATF_TC_HEAD(fpsetmask_basic, tc) 317{ 318 atf_tc_set_md_var(tc, "descr", "A basic test of fpsetmask(3)"); 319} 320 321ATF_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 338ATF_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