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