1 /*- 2 * Copyright (c) 2004 David Schultz <das@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 /* 28 * Test the correctness and C99-compliance of various fenv.h features. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/types.h> 35 #include <sys/wait.h> 36 #include <assert.h> 37 #include <err.h> 38 #include <fenv.h> 39 #include <float.h> 40 #include <libutil.h> 41 #include <math.h> 42 #include <signal.h> 43 #include <stdio.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #include "test-utils.h" 48 49 #define NEXCEPTS (sizeof(std_excepts) / sizeof(std_excepts[0])) 50 51 static const int std_excepts[] = { 52 FE_INVALID, 53 FE_DIVBYZERO, 54 FE_OVERFLOW, 55 FE_UNDERFLOW, 56 FE_INEXACT, 57 }; 58 59 /* init_exceptsets() initializes this to the power set of std_excepts[] */ 60 static int std_except_sets[1 << NEXCEPTS]; 61 62 #pragma STDC FENV_ACCESS ON 63 64 /* 65 * Initialize std_except_sets[] to the power set of std_excepts[] 66 */ 67 static __attribute__((constructor)) void 68 do_setup(void) 69 { 70 unsigned i, j, sr; 71 72 /* Avoid double output after fork() */ 73 setvbuf(stdout, NULL, _IONBF, 0); 74 75 for (i = 0; i < 1 << NEXCEPTS; i++) { 76 for (sr = i, j = 0; sr != 0; sr >>= 1, j++) 77 std_except_sets[i] |= std_excepts[j] & ((~sr & 1) - 1); 78 } 79 } 80 81 /* 82 * Raise a floating-point exception without relying on the standard 83 * library routines, which we are trying to test. 84 * 85 * XXX We can't raise an {over,under}flow without also raising an 86 * inexact exception. 87 */ 88 static void 89 raiseexcept(int excepts) 90 { 91 volatile double d; 92 93 /* 94 * With a compiler that supports the FENV_ACCESS pragma 95 * properly, simple expressions like '0.0 / 0.0' should 96 * be sufficient to generate traps. Unfortunately, we 97 * need to bring a volatile variable into the equation 98 * to prevent incorrect optimizations. 99 */ 100 if (excepts & FE_INVALID) { 101 d = 0.0; 102 d = 0.0 / d; 103 } 104 if (excepts & FE_DIVBYZERO) { 105 d = 0.0; 106 d = 1.0 / d; 107 } 108 if (excepts & FE_OVERFLOW) { 109 d = DBL_MAX; 110 d *= 2.0; 111 } 112 if (excepts & FE_UNDERFLOW) { 113 d = DBL_MIN; 114 d /= DBL_MAX; 115 } 116 if (excepts & FE_INEXACT) { 117 d = DBL_MIN; 118 d += 1.0; 119 } 120 121 /* 122 * On the x86 (and some other architectures?) the FPU and 123 * integer units are decoupled. We need to execute an FWAIT 124 * or a floating-point instruction to get synchronous exceptions. 125 */ 126 d = 1.0; 127 d += 1.0; 128 } 129 130 /* 131 * Determine the current rounding mode without relying on the fenv 132 * routines. This function may raise an inexact exception. 133 */ 134 static int 135 getround(void) 136 { 137 volatile double d; 138 139 /* 140 * This test works just as well with 0.0 - 0.0, except on ia64 141 * where 0.0 - 0.0 gives the wrong sign when rounding downwards. 142 */ 143 d = 1.0; 144 d -= 1.0; 145 if (copysign(1.0, d) < 0.0) 146 return (FE_DOWNWARD); 147 148 d = 1.0; 149 if (d + (DBL_EPSILON * 3.0 / 4.0) == 1.0) 150 return (FE_TOWARDZERO); 151 if (d + (DBL_EPSILON * 1.0 / 4.0) > 1.0) 152 return (FE_UPWARD); 153 154 return (FE_TONEAREST); 155 } 156 157 static void 158 trap_handler(int sig) 159 { 160 161 ATF_CHECK_EQ(SIGFPE, sig); 162 _exit(0); 163 } 164 165 /* 166 * This tests checks the default FP environment, so it must be first. 167 * The memcmp() test below may be too much to ask for, since there 168 * could be multiple machine-specific default environments. 169 */ 170 ATF_TC_WITHOUT_HEAD(dfl_env); 171 ATF_TC_BODY(dfl_env, tc) 172 { 173 #ifndef NO_STRICT_DFL_ENV 174 fenv_t env; 175 176 fegetenv(&env); 177 /* Print the default environment for debugging purposes. */ 178 hexdump(&env, sizeof(env), "current fenv ", HD_OMIT_CHARS); 179 hexdump(FE_DFL_ENV, sizeof(env), "default fenv ", HD_OMIT_CHARS); 180 CHECK_FP_EXCEPTIONS(0, FE_ALL_EXCEPT); 181 #ifdef __amd64__ 182 /* 183 * Compare the fields that the AMD [1] and Intel [2] specs say will be 184 * set once fnstenv returns. 185 * 186 * Not all amd64 capable processors implement the fnstenv instruction 187 * by zero'ing out the env.__x87.__other field (example: AMD Opteron 188 * 6308). The AMD64/x64 specs aren't explicit on what the 189 * env.__x87.__other field will contain after fnstenv is executed, so 190 * the values in env.__x87.__other could be filled with arbitrary 191 * data depending on how the CPU implements fnstenv. 192 * 193 * 1. http://support.amd.com/TechDocs/26569_APM_v5.pdf 194 * 2. http://www.intel.com/Assets/en_US/PDF/manual/253666.pdf 195 */ 196 ATF_CHECK(memcmp(&env.__mxcsr, &FE_DFL_ENV->__mxcsr, 197 sizeof(env.__mxcsr)) == 0); 198 ATF_CHECK(memcmp(&env.__x87.__control, &FE_DFL_ENV->__x87.__control, 199 sizeof(env.__x87.__control)) == 0); 200 ATF_CHECK(memcmp(&env.__x87.__status, &FE_DFL_ENV->__x87.__status, 201 sizeof(env.__x87.__status)) == 0); 202 ATF_CHECK(memcmp(&env.__x87.__tag, &FE_DFL_ENV->__x87.__tag, 203 sizeof(env.__x87.__tag)) == 0); 204 #else 205 ATF_CHECK_EQ(0, memcmp(&env, FE_DFL_ENV, sizeof(env))); 206 #endif 207 208 #endif 209 CHECK_FP_EXCEPTIONS(0, FE_ALL_EXCEPT); 210 } 211 212 /* 213 * Test fetestexcept() and feclearexcept(). 214 */ 215 ATF_TC_WITHOUT_HEAD(fetestclearexcept); 216 ATF_TC_BODY(fetestclearexcept, tc) 217 { 218 int excepts, i; 219 220 for (i = 0; i < 1 << NEXCEPTS; i++) 221 ATF_CHECK_EQ(0, fetestexcept(std_except_sets[i])); 222 for (i = 0; i < 1 << NEXCEPTS; i++) { 223 excepts = std_except_sets[i]; 224 225 /* FE_ALL_EXCEPT might be special-cased, as on i386. */ 226 raiseexcept(excepts); 227 ATF_CHECK_EQ(excepts, fetestexcept(excepts)); 228 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 229 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 230 231 raiseexcept(excepts); 232 ATF_CHECK_EQ(excepts, fetestexcept(excepts)); 233 if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) { 234 excepts |= FE_INEXACT; 235 ATF_CHECK_EQ(excepts, (fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT)); 236 } else { 237 ATF_CHECK_EQ(excepts, fetestexcept(ALL_STD_EXCEPT)); 238 } 239 ATF_CHECK_EQ(0, feclearexcept(excepts)); 240 ATF_CHECK_EQ(0, fetestexcept(ALL_STD_EXCEPT)); 241 } 242 } 243 244 /* 245 * Test fegetexceptflag() and fesetexceptflag(). 246 * 247 * Prerequisites: fetestexcept(), feclearexcept() 248 */ 249 ATF_TC_WITHOUT_HEAD(fegsetexceptflag); 250 ATF_TC_BODY(fegsetexceptflag, tc) 251 { 252 fexcept_t flag; 253 int excepts, i; 254 255 CHECK_FP_EXCEPTIONS(0, FE_ALL_EXCEPT); 256 for (i = 0; i < 1 << NEXCEPTS; i++) { 257 excepts = std_except_sets[i]; 258 259 ATF_CHECK_EQ(0, fegetexceptflag(&flag, excepts)); 260 raiseexcept(ALL_STD_EXCEPT); 261 ATF_CHECK_EQ(0, fesetexceptflag(&flag, excepts)); 262 ATF_CHECK_EQ((ALL_STD_EXCEPT ^ excepts), fetestexcept(ALL_STD_EXCEPT)); 263 264 ATF_CHECK_EQ(0, fegetexceptflag(&flag, FE_ALL_EXCEPT)); 265 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 266 ATF_CHECK_EQ(0, fesetexceptflag(&flag, excepts)); 267 ATF_CHECK_EQ(0, fetestexcept(ALL_STD_EXCEPT)); 268 ATF_CHECK_EQ(0, fesetexceptflag(&flag, ALL_STD_EXCEPT ^ excepts)); 269 ATF_CHECK_EQ((ALL_STD_EXCEPT ^ excepts), fetestexcept(ALL_STD_EXCEPT)); 270 271 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 272 } 273 } 274 275 /* 276 * Test feraiseexcept(). 277 * 278 * Prerequisites: fetestexcept(), feclearexcept() 279 */ 280 ATF_TC_WITHOUT_HEAD(feraiseexcept); 281 ATF_TC_BODY(feraiseexcept, tc) 282 { 283 int excepts, i; 284 285 for (i = 0; i < 1 << NEXCEPTS; i++) { 286 excepts = std_except_sets[i]; 287 288 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 289 ATF_CHECK_EQ(0, feraiseexcept(excepts)); 290 if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0) { 291 excepts |= FE_INEXACT; 292 ATF_CHECK_EQ(excepts, (fetestexcept(ALL_STD_EXCEPT) | FE_INEXACT)); 293 } else { 294 ATF_CHECK_EQ(excepts, fetestexcept(ALL_STD_EXCEPT)); 295 } 296 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 297 } 298 ATF_CHECK_EQ(0, feraiseexcept(FE_INVALID | FE_DIVBYZERO)); 299 ATF_CHECK_EQ((FE_INVALID | FE_DIVBYZERO), fetestexcept(ALL_STD_EXCEPT)); 300 ATF_CHECK_EQ(0, feraiseexcept(FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT)); 301 ATF_CHECK_EQ(ALL_STD_EXCEPT, fetestexcept(ALL_STD_EXCEPT)); 302 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 303 } 304 305 /* 306 * Test fegetround() and fesetround(). 307 */ 308 ATF_TC_WITHOUT_HEAD(fegsetround); 309 ATF_TC_BODY(fegsetround, tc) 310 { 311 312 ATF_CHECK_EQ(FE_TONEAREST, fegetround()); 313 ATF_CHECK_EQ(FE_TONEAREST, getround()); 314 ATF_CHECK_EQ(1, FLT_ROUNDS); 315 316 ATF_CHECK_EQ(0, fesetround(FE_DOWNWARD)); 317 ATF_CHECK_EQ(FE_DOWNWARD, fegetround()); 318 ATF_CHECK_EQ(FE_DOWNWARD, getround()); 319 ATF_CHECK_EQ(3, FLT_ROUNDS); 320 321 ATF_CHECK_EQ(0, fesetround(FE_UPWARD)); 322 ATF_CHECK_EQ(FE_UPWARD, getround()); 323 ATF_CHECK_EQ(FE_UPWARD, fegetround()); 324 ATF_CHECK_EQ(2, FLT_ROUNDS); 325 326 ATF_CHECK_EQ(0, fesetround(FE_TOWARDZERO)); 327 ATF_CHECK_EQ(FE_TOWARDZERO, getround()); 328 ATF_CHECK_EQ(FE_TOWARDZERO, fegetround()); 329 ATF_CHECK_EQ(0, FLT_ROUNDS); 330 331 ATF_CHECK_EQ(0, fesetround(FE_TONEAREST)); 332 ATF_CHECK_EQ(FE_TONEAREST, getround()); 333 ATF_CHECK_EQ(1, FLT_ROUNDS); 334 335 ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); 336 } 337 338 /* 339 * Test fegetenv() and fesetenv(). 340 * 341 * Prerequisites: fetestexcept(), feclearexcept(), fegetround(), fesetround() 342 */ 343 ATF_TC_WITHOUT_HEAD(fegsetenv); 344 ATF_TC_BODY(fegsetenv, tc) 345 { 346 fenv_t env1, env2; 347 int excepts, i; 348 349 for (i = 0; i < 1 << NEXCEPTS; i++) { 350 excepts = std_except_sets[i]; 351 352 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 353 ATF_CHECK_EQ(FE_TONEAREST, fegetround()); 354 ATF_CHECK_EQ(0, fegetenv(&env1)); 355 356 /* 357 * fe[gs]etenv() should be able to save and restore 358 * exception flags without the spurious inexact 359 * exceptions that afflict raiseexcept(). 360 */ 361 raiseexcept(excepts); 362 if ((excepts & (FE_UNDERFLOW | FE_OVERFLOW)) != 0 && 363 (excepts & FE_INEXACT) == 0) 364 ATF_CHECK_EQ(0, feclearexcept(FE_INEXACT)); 365 366 fesetround(FE_DOWNWARD); 367 ATF_CHECK_EQ(0, fegetenv(&env2)); 368 ATF_CHECK_EQ(0, fesetenv(&env1)); 369 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 370 ATF_CHECK_EQ(FE_TONEAREST, fegetround()); 371 372 ATF_CHECK_EQ(0, fesetenv(&env2)); 373 374 /* 375 * Some platforms like powerpc may set extra exception bits. Since 376 * only standard exceptions are tested, mask against ALL_STD_EXCEPT 377 */ 378 ATF_CHECK_EQ(excepts, (fetestexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT)); 379 380 ATF_CHECK_EQ(FE_DOWNWARD, fegetround()); 381 ATF_CHECK_EQ(0, fesetenv(&env1)); 382 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 383 ATF_CHECK_EQ(FE_TONEAREST, fegetround()); 384 } 385 } 386 387 /* 388 * Test fegetexcept(), fedisableexcept(), and feenableexcept(). 389 * 390 * Prerequisites: fetestexcept(), feraiseexcept() 391 */ 392 ATF_TC_WITHOUT_HEAD(masking); 393 ATF_TC_BODY(masking, tc) 394 { 395 struct sigaction act; 396 int except, pass, raise, status; 397 unsigned i; 398 399 ATF_REQUIRE_EQ(0, (fegetexcept() & ALL_STD_EXCEPT)); 400 401 /* 402 * Some CPUs, e.g. AArch64 QEMU does not support trapping on FP 403 * exceptions. In that case the trap enable bits are all RAZ/WI, so 404 * writing to those bits will be ignored and the the next read will 405 * return all zeroes for those bits. Skip the test if no floating 406 * point exceptions are supported and mark it XFAIL if some are missing. 407 */ 408 ATF_REQUIRE_EQ(0, (feenableexcept(FE_ALL_EXCEPT))); 409 except = fegetexcept(); 410 if (except == 0) { 411 atf_tc_skip("CPU does not support trapping on floating point " 412 "exceptions."); 413 } else if ((except & ALL_STD_EXCEPT) != ALL_STD_EXCEPT) { 414 atf_tc_expect_fail("Not all floating point exceptions can be " 415 "set to trap: %#x vs %#x", except, ALL_STD_EXCEPT); 416 } 417 fedisableexcept(FE_ALL_EXCEPT); 418 419 420 ATF_CHECK_EQ(0, (feenableexcept(FE_INVALID|FE_OVERFLOW) & ALL_STD_EXCEPT)); 421 ATF_CHECK_EQ((FE_INVALID | FE_OVERFLOW), (feenableexcept(FE_UNDERFLOW) & ALL_STD_EXCEPT)); 422 ATF_CHECK_EQ((FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW), (fedisableexcept(FE_OVERFLOW) & ALL_STD_EXCEPT)); 423 ATF_CHECK_EQ((FE_INVALID | FE_UNDERFLOW), (fegetexcept() & ALL_STD_EXCEPT)); 424 ATF_CHECK_EQ((FE_INVALID | FE_UNDERFLOW), (fedisableexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT)); 425 ATF_CHECK_EQ(0, (fegetexcept() & ALL_STD_EXCEPT)); 426 427 sigemptyset(&act.sa_mask); 428 act.sa_flags = 0; 429 act.sa_handler = trap_handler; 430 for (pass = 0; pass < 2; pass++) { 431 for (i = 0; i < NEXCEPTS; i++) { 432 except = std_excepts[i]; 433 /* over/underflow may also raise inexact */ 434 if (except == FE_INEXACT) 435 raise = FE_DIVBYZERO | FE_INVALID; 436 else 437 raise = ALL_STD_EXCEPT ^ except; 438 439 /* 440 * We need to fork a child process because 441 * there isn't a portable way to recover from 442 * a floating-point exception. 443 */ 444 switch(fork()) { 445 case 0: /* child */ 446 ATF_CHECK_EQ(0, (fegetexcept() & ALL_STD_EXCEPT)); 447 ATF_REQUIRE_EQ(0, (feenableexcept(except) & ALL_STD_EXCEPT)); 448 ATF_CHECK_EQ(except, fegetexcept()); 449 raiseexcept(raise); 450 ATF_CHECK_EQ(0, feraiseexcept(raise)); 451 ATF_CHECK_EQ(raise, fetestexcept(ALL_STD_EXCEPT)); 452 453 ATF_CHECK_EQ(0, sigaction(SIGFPE, &act, NULL)); 454 switch (pass) { 455 case 0: 456 raiseexcept(except); 457 case 1: 458 feraiseexcept(except); 459 default: 460 ATF_REQUIRE(0); 461 } 462 ATF_REQUIRE(0); 463 default: /* parent */ 464 ATF_REQUIRE(wait(&status) > 0); 465 /* 466 * Avoid assert() here so that it's possible 467 * to examine a failed child's core dump. 468 */ 469 if (!WIFEXITED(status)) 470 errx(1, "child aborted\n"); 471 ATF_CHECK_EQ(0, WEXITSTATUS(status)); 472 break; 473 case -1: /* error */ 474 ATF_REQUIRE(0); 475 } 476 } 477 } 478 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 479 } 480 481 /* 482 * Test feholdexcept() and feupdateenv(). 483 * 484 * Prerequisites: fetestexcept(), fegetround(), fesetround(), 485 * fedisableexcept(), feenableexcept() 486 */ 487 ATF_TC_WITHOUT_HEAD(feholdupdate); 488 ATF_TC_BODY(feholdupdate, tc) 489 { 490 fenv_t env; 491 492 struct sigaction act; 493 int except, pass, status, raise; 494 unsigned i; 495 496 sigemptyset(&act.sa_mask); 497 act.sa_flags = 0; 498 act.sa_handler = trap_handler; 499 for (pass = 0; pass < 2; pass++) { 500 for (i = 0; i < NEXCEPTS; i++) { 501 except = std_excepts[i]; 502 /* over/underflow may also raise inexact */ 503 if (except == FE_INEXACT) 504 raise = FE_DIVBYZERO | FE_INVALID; 505 else 506 raise = ALL_STD_EXCEPT ^ except; 507 508 /* 509 * We need to fork a child process because 510 * there isn't a portable way to recover from 511 * a floating-point exception. 512 */ 513 switch(fork()) { 514 case 0: /* child */ 515 /* 516 * We don't want to cause a fatal exception in 517 * the child until the second pass, so we can 518 * check other properties of feupdateenv(). 519 */ 520 if (pass == 1) 521 ATF_REQUIRE_EQ(0, feenableexcept(except) & ALL_STD_EXCEPT); 522 raiseexcept(raise); 523 ATF_CHECK_EQ(0, fesetround(FE_DOWNWARD)); 524 ATF_CHECK_EQ(0, feholdexcept(&env)); 525 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 526 raiseexcept(except); 527 ATF_CHECK_EQ(0, fesetround(FE_UPWARD)); 528 529 if (pass == 1) 530 ATF_CHECK_EQ(0, sigaction(SIGFPE, &act, NULL)); 531 ATF_CHECK_EQ(0, feupdateenv(&env)); 532 ATF_CHECK_EQ(FE_DOWNWARD, fegetround()); 533 ATF_CHECK_EQ((except | raise), fetestexcept(ALL_STD_EXCEPT)); 534 535 ATF_CHECK_EQ(0, pass); 536 _exit(0); 537 default: /* parent */ 538 ATF_REQUIRE(wait(&status) > 0); 539 /* 540 * Avoid assert() here so that it's possible 541 * to examine a failed child's core dump. 542 */ 543 if (!WIFEXITED(status)) 544 errx(1, "child aborted\n"); 545 ATF_CHECK_EQ(0, WEXITSTATUS(status)); 546 break; 547 case -1: /* error */ 548 ATF_REQUIRE(0); 549 } 550 } 551 } 552 ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); 553 } 554 555 ATF_TP_ADD_TCS(tp) 556 { 557 ATF_TP_ADD_TC(tp, dfl_env); 558 ATF_TP_ADD_TC(tp, fetestclearexcept); 559 ATF_TP_ADD_TC(tp, fegsetexceptflag); 560 ATF_TP_ADD_TC(tp, feraiseexcept); 561 ATF_TP_ADD_TC(tp, fegsetround); 562 ATF_TP_ADD_TC(tp, fegsetenv); 563 ATF_TP_ADD_TC(tp, masking); 564 ATF_TP_ADD_TC(tp, feholdupdate); 565 566 return (atf_no_error()); 567 } 568