1 #include "fp-testing.h" 2 #include "llvm/Support/Errno.h" 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 #if __x86_64__ 7 #include <xmmintrin.h> 8 #endif 9 10 using Fortran::common::RealFlag; 11 using Fortran::common::RoundingMode; 12 13 ScopedHostFloatingPointEnvironment::ScopedHostFloatingPointEnvironment( 14 #if __x86_64__ 15 bool treatSubnormalOperandsAsZero, bool flushSubnormalResultsToZero 16 #else 17 bool, bool 18 #endif 19 ) { 20 errno = 0; 21 if (feholdexcept(&originalFenv_) != 0) { 22 std::fprintf(stderr, "feholdexcept() failed: %s\n", 23 llvm::sys::StrError(errno).c_str()); 24 std::abort(); 25 } 26 fenv_t currentFenv; 27 if (fegetenv(¤tFenv) != 0) { 28 std::fprintf( 29 stderr, "fegetenv() failed: %s\n", llvm::sys::StrError(errno).c_str()); 30 std::abort(); 31 } 32 33 #if __x86_64__ 34 originalMxcsr = _mm_getcsr(); 35 unsigned int currentMxcsr{originalMxcsr}; 36 if (treatSubnormalOperandsAsZero) { 37 currentMxcsr |= 0x0040; 38 } else { 39 currentMxcsr &= ~0x0040; 40 } 41 if (flushSubnormalResultsToZero) { 42 currentMxcsr |= 0x8000; 43 } else { 44 currentMxcsr &= ~0x8000; 45 } 46 #else 47 // TODO others 48 #endif 49 errno = 0; 50 if (fesetenv(¤tFenv) != 0) { 51 std::fprintf( 52 stderr, "fesetenv() failed: %s\n", llvm::sys::StrError(errno).c_str()); 53 std::abort(); 54 } 55 #if __x86_64__ 56 _mm_setcsr(currentMxcsr); 57 #endif 58 } 59 60 ScopedHostFloatingPointEnvironment::~ScopedHostFloatingPointEnvironment() { 61 errno = 0; 62 if (fesetenv(&originalFenv_) != 0) { 63 std::fprintf( 64 stderr, "fesetenv() failed: %s\n", llvm::sys::StrError(errno).c_str()); 65 std::abort(); 66 } 67 #if __x86_64__ 68 _mm_setcsr(originalMxcsr); 69 #endif 70 } 71 72 void ScopedHostFloatingPointEnvironment::ClearFlags() const { 73 feclearexcept(FE_ALL_EXCEPT); 74 } 75 76 RealFlags ScopedHostFloatingPointEnvironment::CurrentFlags() { 77 int exceptions = fetestexcept(FE_ALL_EXCEPT); 78 RealFlags flags; 79 if (exceptions & FE_INVALID) { 80 flags.set(RealFlag::InvalidArgument); 81 } 82 if (exceptions & FE_DIVBYZERO) { 83 flags.set(RealFlag::DivideByZero); 84 } 85 if (exceptions & FE_OVERFLOW) { 86 flags.set(RealFlag::Overflow); 87 } 88 if (exceptions & FE_UNDERFLOW) { 89 flags.set(RealFlag::Underflow); 90 } 91 if (exceptions & FE_INEXACT) { 92 flags.set(RealFlag::Inexact); 93 } 94 return flags; 95 } 96 97 void ScopedHostFloatingPointEnvironment::SetRounding(Rounding rounding) { 98 switch (rounding.mode) { 99 case RoundingMode::TiesToEven: 100 fesetround(FE_TONEAREST); 101 break; 102 case RoundingMode::ToZero: 103 fesetround(FE_TOWARDZERO); 104 break; 105 case RoundingMode::Up: 106 fesetround(FE_UPWARD); 107 break; 108 case RoundingMode::Down: 109 fesetround(FE_DOWNWARD); 110 break; 111 case RoundingMode::TiesAwayFromZero: 112 std::fprintf(stderr, "SetRounding: TiesAwayFromZero not available"); 113 std::abort(); 114 break; 115 } 116 } 117