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