summaryrefslogtreecommitdiff
path: root/flang/lib/Testing/fp-testing.cpp
diff options
context:
space:
mode:
authorMichael Kruse <llvm-project@meinersbur.de>2025-02-06 21:45:51 +0100
committerGitHub <noreply@github.com>2025-02-06 21:45:51 +0100
commit02fa340711d9b990b50a0daf65eb850404884137 (patch)
tree87ab80eead7342cb2a430dc875bca320dfedde76 /flang/lib/Testing/fp-testing.cpp
parent624dc00e766a1554febea289ec0f3a90f0c8047c (diff)
[Flang] Promote FortranEvaluateTesting library (#124417)
The non-GTest library will be shared by unittests of Flang and Flang-RT. Promote it as a regular library for use by both projects. In the long term, we may want to convert these to regular GTest checks to avoid having multiple testing frameworks.
Diffstat (limited to 'flang/lib/Testing/fp-testing.cpp')
-rw-r--r--flang/lib/Testing/fp-testing.cpp124
1 files changed, 124 insertions, 0 deletions
diff --git a/flang/lib/Testing/fp-testing.cpp b/flang/lib/Testing/fp-testing.cpp
new file mode 100644
index 000000000000..5e1728e8df5e
--- /dev/null
+++ b/flang/lib/Testing/fp-testing.cpp
@@ -0,0 +1,124 @@
+//===-- lib/Testing/fp-testing.cpp ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Testing/fp-testing.h"
+#include "llvm/Support/Errno.h"
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#if __x86_64__
+#include <xmmintrin.h>
+#endif
+
+using Fortran::common::RealFlag;
+using Fortran::common::RoundingMode;
+
+ScopedHostFloatingPointEnvironment::ScopedHostFloatingPointEnvironment(
+#if __x86_64__
+ bool treatSubnormalOperandsAsZero, bool flushSubnormalResultsToZero
+#else
+ bool, bool
+#endif
+) {
+ errno = 0;
+ if (feholdexcept(&originalFenv_) != 0) {
+ std::fprintf(stderr, "feholdexcept() failed: %s\n",
+ llvm::sys::StrError(errno).c_str());
+ std::abort();
+ }
+ fenv_t currentFenv;
+ if (fegetenv(&currentFenv) != 0) {
+ std::fprintf(
+ stderr, "fegetenv() failed: %s\n", llvm::sys::StrError(errno).c_str());
+ std::abort();
+ }
+
+#if __x86_64__
+ originalMxcsr = _mm_getcsr();
+ unsigned int currentMxcsr{originalMxcsr};
+ if (treatSubnormalOperandsAsZero) {
+ currentMxcsr |= 0x0040;
+ } else {
+ currentMxcsr &= ~0x0040;
+ }
+ if (flushSubnormalResultsToZero) {
+ currentMxcsr |= 0x8000;
+ } else {
+ currentMxcsr &= ~0x8000;
+ }
+#else
+ // TODO others
+#endif
+ errno = 0;
+ if (fesetenv(&currentFenv) != 0) {
+ std::fprintf(
+ stderr, "fesetenv() failed: %s\n", llvm::sys::StrError(errno).c_str());
+ std::abort();
+ }
+#if __x86_64__
+ _mm_setcsr(currentMxcsr);
+#endif
+}
+
+ScopedHostFloatingPointEnvironment::~ScopedHostFloatingPointEnvironment() {
+ errno = 0;
+ if (fesetenv(&originalFenv_) != 0) {
+ std::fprintf(
+ stderr, "fesetenv() failed: %s\n", llvm::sys::StrError(errno).c_str());
+ std::abort();
+ }
+#if __x86_64__
+ _mm_setcsr(originalMxcsr);
+#endif
+}
+
+void ScopedHostFloatingPointEnvironment::ClearFlags() const {
+ feclearexcept(FE_ALL_EXCEPT);
+}
+
+RealFlags ScopedHostFloatingPointEnvironment::CurrentFlags() {
+ int exceptions = fetestexcept(FE_ALL_EXCEPT);
+ RealFlags flags;
+ if (exceptions & FE_INVALID) {
+ flags.set(RealFlag::InvalidArgument);
+ }
+ if (exceptions & FE_DIVBYZERO) {
+ flags.set(RealFlag::DivideByZero);
+ }
+ if (exceptions & FE_OVERFLOW) {
+ flags.set(RealFlag::Overflow);
+ }
+ if (exceptions & FE_UNDERFLOW) {
+ flags.set(RealFlag::Underflow);
+ }
+ if (exceptions & FE_INEXACT) {
+ flags.set(RealFlag::Inexact);
+ }
+ return flags;
+}
+
+void ScopedHostFloatingPointEnvironment::SetRounding(Rounding rounding) {
+ switch (rounding.mode) {
+ case RoundingMode::TiesToEven:
+ fesetround(FE_TONEAREST);
+ break;
+ case RoundingMode::ToZero:
+ fesetround(FE_TOWARDZERO);
+ break;
+ case RoundingMode::Up:
+ fesetround(FE_UPWARD);
+ break;
+ case RoundingMode::Down:
+ fesetround(FE_DOWNWARD);
+ break;
+ case RoundingMode::TiesAwayFromZero:
+ std::fprintf(stderr, "SetRounding: TiesAwayFromZero not available");
+ std::abort();
+ break;
+ }
+}