diff --git a/flang/lib/Evaluate/host.h b/flang/lib/Evaluate/host.h --- a/flang/lib/Evaluate/host.h +++ b/flang/lib/Evaluate/host.h @@ -41,7 +41,9 @@ private: std::fenv_t originalFenv_; - std::fenv_t currentFenv_; +#if __x86_64__ + unsigned int originalMxcsr; +#endif RealFlags flags_; bool hasSubnormalFlushingHardwareControl_{false}; bool hardwareFlagsAreReliable_{true}; diff --git a/flang/lib/Evaluate/host.cpp b/flang/lib/Evaluate/host.cpp --- a/flang/lib/Evaluate/host.cpp +++ b/flang/lib/Evaluate/host.cpp @@ -11,6 +11,9 @@ #include "flang/Common/idioms.h" #include "llvm/Support/Errno.h" #include +#if __x86_64__ +#include +#endif namespace Fortran::evaluate::host { using namespace Fortran::parser::literals; @@ -18,6 +21,7 @@ void HostFloatingPointEnvironment::SetUpHostFloatingPointEnvironment( FoldingContext &context) { errno = 0; + std::fenv_t currentFenv_; if (feholdexcept(&originalFenv_) != 0) { common::die("Folding with host runtime: feholdexcept() failed: %s", llvm::sys::StrError(errno).c_str()); @@ -30,12 +34,14 @@ } #if __x86_64__ hasSubnormalFlushingHardwareControl_ = true; + originalMxcsr = _mm_getcsr(); + unsigned int newMxcsr{originalMxcsr}; if (context.flushSubnormalsToZero()) { - currentFenv_.__mxcsr |= 0x8000; // result - currentFenv_.__mxcsr |= 0x0040; // operands + newMxcsr |= 0x8000; + newMxcsr |= 0x0040; } else { - currentFenv_.__mxcsr &= ~0x8000; // result - currentFenv_.__mxcsr &= ~0x0040; // operands + newMxcsr &= ~0x8000; + newMxcsr &= ~0x0040; } #elif defined(__aarch64__) #if defined(__GNU_LIBRARY__) @@ -75,6 +81,10 @@ llvm::sys::StrError(errno).c_str()); return; } +#if __x86_64__ + _mm_setcsr(newMxcsr); +#endif + switch (context.rounding().mode) { case common::RoundingMode::TiesToEven: fesetround(FE_TONEAREST); @@ -141,6 +151,10 @@ "Folding with host runtime: fesetenv() failed while restoring fenv: %s", llvm::sys::StrError(errno).c_str()); } +#if __x86_64__ + _mm_setcsr(originalMxcsr); +#endif + errno = 0; } } // namespace Fortran::evaluate::host diff --git a/flang/unittests/Evaluate/fp-testing.h b/flang/unittests/Evaluate/fp-testing.h --- a/flang/unittests/Evaluate/fp-testing.h +++ b/flang/unittests/Evaluate/fp-testing.h @@ -19,7 +19,9 @@ private: fenv_t originalFenv_; - fenv_t currentFenv_; +#if __x86_64__ + unsigned int originalMxcsr; +#endif }; #endif // FORTRAN_TEST_EVALUATE_FP_TESTING_H_ diff --git a/flang/unittests/Evaluate/fp-testing.cpp b/flang/unittests/Evaluate/fp-testing.cpp --- a/flang/unittests/Evaluate/fp-testing.cpp +++ b/flang/unittests/Evaluate/fp-testing.cpp @@ -3,6 +3,9 @@ #include #include #include +#if __x86_64__ +#include +#endif using Fortran::common::RoundingMode; using Fortran::evaluate::RealFlag; @@ -20,21 +23,25 @@ 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 newMxcsr{originalMxcsr}; if (treatSubnormalOperandsAsZero) { - currentFenv_.__mxcsr |= 0x0040; + newMxcsr |= 0x0040; } else { - currentFenv_.__mxcsr &= ~0x0040; + newMxcsr &= ~0x0040; } if (flushSubnormalResultsToZero) { - currentFenv_.__mxcsr |= 0x8000; + newMxcsr |= 0x8000; } else { - currentFenv_.__mxcsr &= ~0x8000; + newMxcsr &= ~0x8000; } #else // TODO others @@ -45,6 +52,9 @@ stderr, "fesetenv() failed: %s\n", llvm::sys::StrError(errno).c_str()); std::abort(); } +#if __x86_64__ + _mm_setcsr(newMxcsr); +#endif } ScopedHostFloatingPointEnvironment::~ScopedHostFloatingPointEnvironment() { @@ -54,6 +64,9 @@ stderr, "fesetenv() failed: %s\n", llvm::sys::StrError(errno).c_str()); std::abort(); } +#if __x86_64__ + _mm_setcsr(originalMxcsr); +#endif } void ScopedHostFloatingPointEnvironment::ClearFlags() const {