xref: /llvm-project/libc/test/src/fenv/enabled_exceptions_test.cpp (revision f100ec2517e94eb9d7a488c105d311fa5029fbef)
1ab3cbe4bSSiva Chandra Reddy //===-- Unittests for feraiseexcept with exceptions enabled ---------------===//
2ab3cbe4bSSiva Chandra Reddy //
3ab3cbe4bSSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ab3cbe4bSSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
5ab3cbe4bSSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ab3cbe4bSSiva Chandra Reddy //
7ab3cbe4bSSiva Chandra Reddy //===----------------------------------------------------------------------===//
8ab3cbe4bSSiva Chandra Reddy 
9ab3cbe4bSSiva Chandra Reddy #include "src/fenv/feclearexcept.h"
10ab3cbe4bSSiva Chandra Reddy #include "src/fenv/feraiseexcept.h"
11ab3cbe4bSSiva Chandra Reddy #include "src/fenv/fetestexcept.h"
12ab3cbe4bSSiva Chandra Reddy 
1376ec69a9STue Ly #include "src/__support/FPUtil/FEnvImpl.h"
14*f100ec25SGuillaume Chatelet #include "src/__support/macros/properties/architectures.h"
15af1315c2SSiva Chandra Reddy #include "test/UnitTest/FPExceptMatcher.h"
16af1315c2SSiva Chandra Reddy #include "test/UnitTest/Test.h"
17ab3cbe4bSSiva Chandra Reddy 
18ab3cbe4bSSiva Chandra Reddy #include <fenv.h>
19ab3cbe4bSSiva Chandra Reddy #include <signal.h>
20ab3cbe4bSSiva Chandra Reddy 
21ab3cbe4bSSiva Chandra Reddy // This test enables an exception and verifies that raising that exception
22ab3cbe4bSSiva Chandra Reddy // triggers SIGFPE.
231df0dbfcSMichael Jones TEST(LlvmLibcExceptionStatusTest, RaiseAndCrash) {
24a2569a76SGuillaume Chatelet #if defined(LIBC_TARGET_ARCH_IS_AARCH64)
25c5cfbe40SSiva Chandra Reddy   // Few aarch64 HW implementations do not trap exceptions. We skip this test
26c5cfbe40SSiva Chandra Reddy   // completely on such HW.
27c5cfbe40SSiva Chandra Reddy   //
28c5cfbe40SSiva Chandra Reddy   // Whether HW supports trapping exceptions or not is deduced by enabling an
29c5cfbe40SSiva Chandra Reddy   // exception and reading back to see if the exception got enabled. If the
30c5cfbe40SSiva Chandra Reddy   // exception did not get enabled, then it means that the HW does not support
31c5cfbe40SSiva Chandra Reddy   // trapping exceptions.
321c92911eSMichael Jones   __llvm_libc::fputil::disable_except(FE_ALL_EXCEPT);
331c92911eSMichael Jones   __llvm_libc::fputil::enable_except(FE_DIVBYZERO);
341c92911eSMichael Jones   if (__llvm_libc::fputil::get_except() == 0)
35c5cfbe40SSiva Chandra Reddy     return;
36a2569a76SGuillaume Chatelet #endif // defined(LIBC_TARGET_ARCH_IS_AARCH64)
37c5cfbe40SSiva Chandra Reddy 
38ab3cbe4bSSiva Chandra Reddy   // TODO: Install a floating point exception handler and verify that the
39ab3cbe4bSSiva Chandra Reddy   // the expected exception was raised. One will have to longjmp back from
40ab3cbe4bSSiva Chandra Reddy   // that exception handler, so such a testing can be done after we have
41ab3cbe4bSSiva Chandra Reddy   // longjmp implemented.
42ab3cbe4bSSiva Chandra Reddy 
43ab3cbe4bSSiva Chandra Reddy   int excepts[] = {FE_DIVBYZERO, FE_INVALID, FE_INEXACT, FE_OVERFLOW,
44ab3cbe4bSSiva Chandra Reddy                    FE_UNDERFLOW};
45ab3cbe4bSSiva Chandra Reddy 
46cb2e2d50SMichael Jones   // We '|' the individual exception flags instead of using FE_ALL_EXCEPT
47cb2e2d50SMichael Jones   // as it can include non-standard extensions. Note that we should be able
48cb2e2d50SMichael Jones   // to compile this file with headers from other libcs as well.
4925226f3eSMichael Jones   constexpr int ALL_EXCEPTS =
50cb2e2d50SMichael Jones       FE_DIVBYZERO | FE_INVALID | FE_INEXACT | FE_OVERFLOW | FE_UNDERFLOW;
51cb2e2d50SMichael Jones 
52ab3cbe4bSSiva Chandra Reddy   for (int e : excepts) {
531c92911eSMichael Jones     __llvm_libc::fputil::disable_except(FE_ALL_EXCEPT);
541c92911eSMichael Jones     __llvm_libc::fputil::enable_except(e);
55ab3cbe4bSSiva Chandra Reddy     ASSERT_EQ(__llvm_libc::feclearexcept(FE_ALL_EXCEPT), 0);
56ab3cbe4bSSiva Chandra Reddy     // Raising all exceptions except |e| should not call the
57ab3cbe4bSSiva Chandra Reddy     // SIGFPE handler. They should set the exception flag though,
58ff384700SSiva Chandra Reddy     // so we verify that. Since other exceptions like FE_DIVBYZERO
59ff384700SSiva Chandra Reddy     // can raise FE_INEXACT as well, we don't verify the other
60ff384700SSiva Chandra Reddy     // exception flags when FE_INEXACT is enabled.
61ff384700SSiva Chandra Reddy     if (e != FE_INEXACT) {
6225226f3eSMichael Jones       int others = ALL_EXCEPTS & ~e;
63ab3cbe4bSSiva Chandra Reddy       ASSERT_EQ(__llvm_libc::feraiseexcept(others), 0);
64ab3cbe4bSSiva Chandra Reddy       ASSERT_EQ(__llvm_libc::fetestexcept(others), others);
65ff384700SSiva Chandra Reddy     }
66ab3cbe4bSSiva Chandra Reddy 
67c24c18bbSSiva Chandra Reddy     ASSERT_RAISES_FP_EXCEPT([=] {
68c24c18bbSSiva Chandra Reddy       // In test frameworks like Fuchsia's zxtest, this translates to
69c24c18bbSSiva Chandra Reddy       // a death test which runs this closure in a different thread. So,
70c24c18bbSSiva Chandra Reddy       // we enable the exception again inside this closure so that the
71c24c18bbSSiva Chandra Reddy       // exception gets enabled for the thread running this closure.
721c92911eSMichael Jones       __llvm_libc::fputil::enable_except(e);
73c24c18bbSSiva Chandra Reddy       __llvm_libc::feraiseexcept(e);
74c24c18bbSSiva Chandra Reddy     });
75c24c18bbSSiva Chandra Reddy 
76c24c18bbSSiva Chandra Reddy     // Cleanup.
771c92911eSMichael Jones     __llvm_libc::fputil::disable_except(FE_ALL_EXCEPT);
78c24c18bbSSiva Chandra Reddy     ASSERT_EQ(__llvm_libc::feclearexcept(FE_ALL_EXCEPT), 0);
79ab3cbe4bSSiva Chandra Reddy   }
80ab3cbe4bSSiva Chandra Reddy }
81