[flang] Fix setting mxcsr on MSVC

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
This commit is contained in:
Isuru Fernando 2020-07-08 07:19:01 -05:00
parent 9114900287
commit 2ebf4b6e4c
4 changed files with 49 additions and 18 deletions

View 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

View 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};

View 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 {

View 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_