125 lines · cpp
1//===-- lib/Testing/fp-testing.cpp ------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "flang/Testing/fp-testing.h"10#include "llvm/Support/Errno.h"11#include <cstdio>12#include <cstdlib>13#include <cstring>14#if __x86_64__ || _M_X6415#include <xmmintrin.h>16#endif17 18using Fortran::common::RealFlag;19using Fortran::common::RoundingMode;20 21ScopedHostFloatingPointEnvironment::ScopedHostFloatingPointEnvironment(22#if __x86_64__ || _M_X6423 bool treatSubnormalOperandsAsZero, bool flushSubnormalResultsToZero24#else25 bool, bool26#endif27) {28 errno = 0;29 if (feholdexcept(&originalFenv_) != 0) {30 std::fprintf(stderr, "feholdexcept() failed: %s\n",31 llvm::sys::StrError(errno).c_str());32 std::abort();33 }34 fenv_t currentFenv;35 if (fegetenv(¤tFenv) != 0) {36 std::fprintf(37 stderr, "fegetenv() failed: %s\n", llvm::sys::StrError(errno).c_str());38 std::abort();39 }40 41#if __x86_64__ || _M_X6442 originalMxcsr = _mm_getcsr();43 unsigned int currentMxcsr{originalMxcsr};44 if (treatSubnormalOperandsAsZero) {45 currentMxcsr |= 0x0040;46 } else {47 currentMxcsr &= ~0x0040;48 }49 if (flushSubnormalResultsToZero) {50 currentMxcsr |= 0x8000;51 } else {52 currentMxcsr &= ~0x8000;53 }54#else55 // TODO others56#endif57 errno = 0;58 if (fesetenv(¤tFenv) != 0) {59 std::fprintf(60 stderr, "fesetenv() failed: %s\n", llvm::sys::StrError(errno).c_str());61 std::abort();62 }63#if __x86_64__64 _mm_setcsr(currentMxcsr);65#endif66}67 68ScopedHostFloatingPointEnvironment::~ScopedHostFloatingPointEnvironment() {69 errno = 0;70 if (fesetenv(&originalFenv_) != 0) {71 std::fprintf(72 stderr, "fesetenv() failed: %s\n", llvm::sys::StrError(errno).c_str());73 std::abort();74 }75#if __x86_64__ || _M_X6476 _mm_setcsr(originalMxcsr);77#endif78}79 80void ScopedHostFloatingPointEnvironment::ClearFlags() const {81 feclearexcept(FE_ALL_EXCEPT);82}83 84RealFlags ScopedHostFloatingPointEnvironment::CurrentFlags() {85 int exceptions = fetestexcept(FE_ALL_EXCEPT);86 RealFlags flags;87 if (exceptions & FE_INVALID) {88 flags.set(RealFlag::InvalidArgument);89 }90 if (exceptions & FE_DIVBYZERO) {91 flags.set(RealFlag::DivideByZero);92 }93 if (exceptions & FE_OVERFLOW) {94 flags.set(RealFlag::Overflow);95 }96 if (exceptions & FE_UNDERFLOW) {97 flags.set(RealFlag::Underflow);98 }99 if (exceptions & FE_INEXACT) {100 flags.set(RealFlag::Inexact);101 }102 return flags;103}104 105void ScopedHostFloatingPointEnvironment::SetRounding(Rounding rounding) {106 switch (rounding.mode) {107 case RoundingMode::TiesToEven:108 fesetround(FE_TONEAREST);109 break;110 case RoundingMode::ToZero:111 fesetround(FE_TOWARDZERO);112 break;113 case RoundingMode::Up:114 fesetround(FE_UPWARD);115 break;116 case RoundingMode::Down:117 fesetround(FE_DOWNWARD);118 break;119 case RoundingMode::TiesAwayFromZero:120 std::fprintf(stderr, "SetRounding: TiesAwayFromZero not available");121 std::abort();122 break;123 }124}125