diff --git a/libc/src/__support/FPUtil/aarch64/FEnvImpl.h b/libc/src/__support/FPUtil/aarch64/FEnvImpl.h --- a/libc/src/__support/FPUtil/aarch64/FEnvImpl.h +++ b/libc/src/__support/FPUtil/aarch64/FEnvImpl.h @@ -89,6 +89,13 @@ return FEnv::exceptionStatusToMacro(oldExcepts); } +static inline int getExcept() { + uint32_t controlWord = FEnv::getControlWord(); + int enabledExcepts = + (controlWord >> FEnv::ExceptionControlFlagsBitPosition) & 0x1F; + return FEnv::exceptionStatusToMacro(enabledExcepts); +} + static inline int clearExcept(int excepts) { uint32_t statusWord = FEnv::getStatusWord(); uint32_t toClear = FEnv::getStatusValueForExcept(excepts); diff --git a/libc/src/__support/FPUtil/x86_64/FEnvImpl.h b/libc/src/__support/FPUtil/x86_64/FEnvImpl.h --- a/libc/src/__support/FPUtil/x86_64/FEnvImpl.h +++ b/libc/src/__support/FPUtil/x86_64/FEnvImpl.h @@ -187,6 +187,12 @@ return internal::exceptionStatusToMacro(oldExcepts); } +static inline int getExcept() { + uint16_t x87CW = internal::getX87ControlWord(); + uint16_t enabledExcepts = ~x87CW & 0x3F; + return internal::exceptionStatusToMacro(enabledExcepts); +} + static inline int clearExcept(int excepts) { internal::X87StateDescriptor state; internal::getX87StateDescriptor(state); diff --git a/libc/test/src/fenv/enabled_exceptions_test.cpp b/libc/test/src/fenv/enabled_exceptions_test.cpp --- a/libc/test/src/fenv/enabled_exceptions_test.cpp +++ b/libc/test/src/fenv/enabled_exceptions_test.cpp @@ -20,6 +20,20 @@ // This test enables an exception and verifies that raising that exception // triggers SIGFPE. TEST(LlvmLibcExceptionStatusTest, RaiseAndCrash) { +#ifdef __aarch64__ + // Few aarch64 HW implementations do not trap exceptions. We skip this test + // completely on such HW. + // + // Whether HW supports trapping exceptions or not is deduced by enabling an + // exception and reading back to see if the exception got enabled. If the + // exception did not get enabled, then it means that the HW does not support + // trapping exceptions. + __llvm_libc::fputil::disableExcept(FE_ALL_EXCEPT); + __llvm_libc::fputil::enableExcept(FE_DIVBYZERO); + if (__llvm_libc::fputil::getExcept() == 0) + return; +#endif + // TODO: Install a floating point exception handler and verify that the // the expected exception was raised. One will have to longjmp back from // that exception handler, so such a testing can be done after we have diff --git a/libc/test/src/fenv/feholdexcept_test.cpp b/libc/test/src/fenv/feholdexcept_test.cpp --- a/libc/test/src/fenv/feholdexcept_test.cpp +++ b/libc/test/src/fenv/feholdexcept_test.cpp @@ -15,6 +15,20 @@ #include TEST(LlvmLibcFEnvTest, RaiseAndCrash) { +#ifdef __aarch64__ + // Few aarch64 HW implementations do not trap exceptions. We skip this test + // completely on such HW. + // + // Whether HW supports trapping exceptions or not is deduced by enabling an + // exception and reading back to see if the exception got enabled. If the + // exception did not get enabled, then it means that the HW does not support + // trapping exceptions. + __llvm_libc::fputil::disableExcept(FE_ALL_EXCEPT); + __llvm_libc::fputil::enableExcept(FE_DIVBYZERO); + if (__llvm_libc::fputil::getExcept() == 0) + return; +#endif + int excepts[] = {FE_DIVBYZERO, FE_INVALID, FE_INEXACT, FE_OVERFLOW, FE_UNDERFLOW};