[flang] Fix setting mxcsr on MSVC
authorIsuru Fernando <isuruf@gmail.com>
Wed, 8 Jul 2020 12:19:01 +0000 (07:19 -0500)
committerIsuru Fernando <isuruf@gmail.com>
Wed, 8 Jul 2020 12:25:25 +0000 (07:25 -0500)
Reviewers: sscalpone, jdoerfert, #flang, DavidTruby, jeanPerier

Reviewed By: jeanPerier

Subscribers: richard.barton.arm, jeanPerier, ro, llvm-commits

Tags: #llvm, #flang

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

flang/lib/Evaluate/host.cpp
flang/lib/Evaluate/host.h
flang/unittests/Evaluate/fp-testing.cpp
flang/unittests/Evaluate/fp-testing.h

index ea83127..c9aa5c4 100644 (file)
@@ -11,6 +11,9 @@
 #include "flang/Common/idioms.h"
 #include "llvm/Support/Errno.h"
 #include <cfenv>
+#if __x86_64__
+#include <xmmintrin.h>
+#endif
 
 namespace Fortran::evaluate::host {
 using namespace Fortran::parser::literals;
@@ -18,39 +21,42 @@ using namespace Fortran::parser::literals;
 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());
     return;
   }
-  if (fegetenv(&currentFenv_) != 0) {
+  if (fegetenv(&currentFenv) != 0) {
     common::die("Folding with host runtime: fegetenv() failed: %s",
         llvm::sys::StrError(errno).c_str());
     return;
   }
 #if __x86_64__
   hasSubnormalFlushingHardwareControl_ = true;
+  originalMxcsr = _mm_getcsr();
+  unsigned int currentMxcsr{originalMxcsr};
   if (context.flushSubnormalsToZero()) {
-    currentFenv_.__mxcsr |= 0x8000; // result
-    currentFenv_.__mxcsr |= 0x0040; // operands
+    currentMxcsr |= 0x8000;
+    currentMxcsr |= 0x0040;
   } else {
-    currentFenv_.__mxcsr &= ~0x8000; // result
-    currentFenv_.__mxcsr &= ~0x0040; // operands
+    currentMxcsr &= ~0x8000;
+    currentMxcsr &= ~0x0040;
   }
 #elif defined(__aarch64__)
 #if defined(__GNU_LIBRARY__)
   hasSubnormalFlushingHardwareControl_ = true;
   if (context.flushSubnormalsToZero()) {
-    currentFenv_.__fpcr |= (1U << 24); // control register
+    currentFenv.__fpcr |= (1U << 24); // control register
   } else {
-    currentFenv_.__fpcr &= ~(1U << 24); // control register
+    currentFenv.__fpcr &= ~(1U << 24); // control register
   }
 #elif defined(__BIONIC__)
   hasSubnormalFlushingHardwareControl_ = true;
   if (context.flushSubnormalsToZero()) {
-    currentFenv_.__control |= (1U << 24); // control register
+    currentFenv.__control |= (1U << 24); // control register
   } else {
-    currentFenv_.__control &= ~(1U << 24); // control register
+    currentFenv.__control &= ~(1U << 24); // control register
   }
 #else
   // If F18 is built with other C libraries on AArch64, software flushing will
@@ -70,11 +76,15 @@ void HostFloatingPointEnvironment::SetUpHostFloatingPointEnvironment(
   hardwareFlagsAreReliable_ = false;
 #endif
   errno = 0;
-  if (fesetenv(&currentFenv_) != 0) {
+  if (fesetenv(&currentFenv) != 0) {
     common::die("Folding with host runtime: fesetenv() failed: %s",
         llvm::sys::StrError(errno).c_str());
     return;
   }
+#if __x86_64__
+  _mm_setcsr(currentMxcsr);
+#endif
+
   switch (context.rounding().mode) {
   case common::RoundingMode::TiesToEven:
     fesetround(FE_TONEAREST);
@@ -141,6 +151,10 @@ void HostFloatingPointEnvironment::CheckAndRestoreFloatingPointEnvironment(
         "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
index 20355ae..2fac042 100644 (file)
@@ -41,7 +41,9 @@ public:
 
 private:
   std::fenv_t originalFenv_;
-  std::fenv_t currentFenv_;
+#if __x86_64__
+  unsigned int originalMxcsr;
+#endif
   RealFlags flags_;
   bool hasSubnormalFlushingHardwareControl_{false};
   bool hardwareFlagsAreReliable_{true};
index 66ab7b2..94d8d50 100644 (file)
@@ -3,6 +3,9 @@
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
+#if __x86_64__
+#include <xmmintrin.h>
+#endif
 
 using Fortran::common::RoundingMode;
 using Fortran::evaluate::RealFlag;
@@ -20,31 +23,38 @@ ScopedHostFloatingPointEnvironment::ScopedHostFloatingPointEnvironment(
         llvm::sys::StrError(errno).c_str());
     std::abort();
   }
-  if (fegetenv(&currentFenv_) != 0) {
+  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) {
-    currentFenv_.__mxcsr |= 0x0040;
+    currentMxcsr |= 0x0040;
   } else {
-    currentFenv_.__mxcsr &= ~0x0040;
+    currentMxcsr &= ~0x0040;
   }
   if (flushSubnormalResultsToZero) {
-    currentFenv_.__mxcsr |= 0x8000;
+    currentMxcsr |= 0x8000;
   } else {
-    currentFenv_.__mxcsr &= ~0x8000;
+    currentMxcsr &= ~0x8000;
   }
 #else
   // TODO others
 #endif
   errno = 0;
-  if (fesetenv(&currentFenv_) != 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() {
@@ -54,6 +64,9 @@ ScopedHostFloatingPointEnvironment::~ScopedHostFloatingPointEnvironment() {
         stderr, "fesetenv() failed: %s\n", llvm::sys::StrError(errno).c_str());
     std::abort();
   }
+#if __x86_64__
+  _mm_setcsr(originalMxcsr);
+#endif
 }
 
 void ScopedHostFloatingPointEnvironment::ClearFlags() const {
index 760e976..ee06765 100644 (file)
@@ -19,7 +19,9 @@ public:
 
 private:
   fenv_t originalFenv_;
-  fenv_t currentFenv_;
+#if __x86_64__
+  unsigned int originalMxcsr;
+#endif
 };
 
 #endif // FORTRAN_TEST_EVALUATE_FP_TESTING_H_