diff options
| author | Michael Kruse <llvm-project@meinersbur.de> | 2025-02-06 21:45:51 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-06 21:45:51 +0100 |
| commit | 02fa340711d9b990b50a0daf65eb850404884137 (patch) | |
| tree | 87ab80eead7342cb2a430dc875bca320dfedde76 /flang/lib/Testing/fp-testing.cpp | |
| parent | 624dc00e766a1554febea289ec0f3a90f0c8047c (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.cpp | 124 |
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(¤tFenv) != 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(¤tFenv) != 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; + } +} |
