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