[libc] Skip fenv exception tests on aarch64 if HW doesn't support exceptions.

Reviewed By: michaelrj

Differential Revision: https://reviews.llvm.org/D109538

GitOrigin-RevId: c5cfbe40de6ef3eb7958cffdd9eee2eb8b6c77b9
diff --git a/src/__support/FPUtil/aarch64/FEnvImpl.h b/src/__support/FPUtil/aarch64/FEnvImpl.h
index 9508246..36d6caa 100644
--- a/src/__support/FPUtil/aarch64/FEnvImpl.h
+++ b/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/src/__support/FPUtil/x86_64/FEnvImpl.h b/src/__support/FPUtil/x86_64/FEnvImpl.h
index 88623b9..d5bb703 100644
--- a/src/__support/FPUtil/x86_64/FEnvImpl.h
+++ b/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/test/src/fenv/enabled_exceptions_test.cpp b/test/src/fenv/enabled_exceptions_test.cpp
index 3d2b02f..b971e71 100644
--- a/test/src/fenv/enabled_exceptions_test.cpp
+++ b/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/test/src/fenv/feholdexcept_test.cpp b/test/src/fenv/feholdexcept_test.cpp
index 5233e1b..3f8401f 100644
--- a/test/src/fenv/feholdexcept_test.cpp
+++ b/test/src/fenv/feholdexcept_test.cpp
@@ -15,6 +15,20 @@
 #include <fenv.h>
 
 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};