brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.0 KiB · bf02496 Raw
161 lines · cpp
1//===-- lib/Evaluate/host.cpp ---------------------------------------------===//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 "host.h"10 11#include "flang/Common/idioms.h"12#include "llvm/Support/Errno.h"13#include <cfenv>14#if __x86_64__15#include <xmmintrin.h>16#endif17 18namespace Fortran::evaluate::host {19using namespace Fortran::parser::literals;20 21void HostFloatingPointEnvironment::SetUpHostFloatingPointEnvironment(22    FoldingContext &context) {23  errno = 0;24  std::fenv_t currentFenv;25  if (feholdexcept(&originalFenv_) != 0) {26    common::die("Folding with host runtime: feholdexcept() failed: %s",27        llvm::sys::StrError(errno).c_str());28    return;29  }30  if (fegetenv(&currentFenv) != 0) {31    common::die("Folding with host runtime: fegetenv() failed: %s",32        llvm::sys::StrError(errno).c_str());33    return;34  }35#if __x86_64__36  hasSubnormalFlushingHardwareControl_ = true;37  originalMxcsr = _mm_getcsr();38  unsigned int currentMxcsr{originalMxcsr};39  if (context.targetCharacteristics().areSubnormalsFlushedToZero()) {40    currentMxcsr |= 0x8000;41    currentMxcsr |= 0x0040;42  } else {43    currentMxcsr &= ~0x8000;44    currentMxcsr &= ~0x0040;45  }46#elif defined(__aarch64__)47#if defined(__GNU_LIBRARY__)48  hasSubnormalFlushingHardwareControl_ = true;49  if (context.targetCharacteristics().areSubnormalsFlushedToZero()) {50    currentFenv.__fpcr |= (1U << 24); // control register51  } else {52    currentFenv.__fpcr &= ~(1U << 24); // control register53  }54#elif defined(__BIONIC__)55  hasSubnormalFlushingHardwareControl_ = true;56  if (context.targetCharacteristics().areSubnormalsFlushedToZero()) {57    currentFenv.__control |= (1U << 24); // control register58  } else {59    currentFenv.__control &= ~(1U << 24); // control register60  }61#else62  // If F18 is built with other C libraries on AArch64, software flushing will63  // be performed around host library calls if subnormal flushing is requested64#endif65#else66  // If F18 is not built on one of the above host architecture, software67  // flushing will be performed around host library calls if needed.68#endif69 70#ifdef __clang__71  // clang does not ensure that floating point environment flags are meaningful.72  // It may perform optimizations that will impact the floating point73  // environment. For instance, libc++ complex float tan and tanh compilation74  // with clang -O2 introduces a division by zero on X86 in unused slots of xmm75  // registers. Therefore, fetestexcept should not be used.76  hardwareFlagsAreReliable_ = false;77#endif78  errno = 0;79  if (fesetenv(&currentFenv) != 0) {80    common::die("Folding with host runtime: fesetenv() failed: %s",81        llvm::sys::StrError(errno).c_str());82    return;83  }84#if __x86_64__85  _mm_setcsr(currentMxcsr);86#endif87 88  switch (context.targetCharacteristics().roundingMode().mode) {89  case common::RoundingMode::TiesToEven:90    fesetround(FE_TONEAREST);91    break;92  case common::RoundingMode::ToZero:93    fesetround(FE_TOWARDZERO);94    break;95  case common::RoundingMode::Up:96    fesetround(FE_UPWARD);97    break;98  case common::RoundingMode::Down:99    fesetround(FE_DOWNWARD);100    break;101  case common::RoundingMode::TiesAwayFromZero:102    fesetround(FE_TONEAREST);103    context.Warn(common::UsageWarning::FoldingFailure,104        "TiesAwayFromZero rounding mode is not available when folding constants with host runtime; using TiesToEven instead"_warn_en_US);105    break;106  }107  flags_.clear();108  errno = 0;109}110void HostFloatingPointEnvironment::CheckAndRestoreFloatingPointEnvironment(111    FoldingContext &context) {112  int errnoCapture{errno};113  if (hardwareFlagsAreReliable()) {114    int exceptions{fetestexcept(FE_ALL_EXCEPT)};115    if (exceptions & FE_INVALID) {116      flags_.set(RealFlag::InvalidArgument);117    }118    if (exceptions & FE_DIVBYZERO) {119      flags_.set(RealFlag::DivideByZero);120    }121    if (exceptions & FE_OVERFLOW) {122      flags_.set(RealFlag::Overflow);123    }124    if (exceptions & FE_UNDERFLOW) {125      flags_.set(RealFlag::Underflow);126    }127    if (exceptions & FE_INEXACT) {128      flags_.set(RealFlag::Inexact);129    }130  }131 132  if (flags_.empty()) {133    if (errnoCapture == EDOM) {134      flags_.set(RealFlag::InvalidArgument);135    }136    if (errnoCapture == ERANGE) {137      // can't distinguish over/underflow from errno138      flags_.set(RealFlag::Overflow);139    }140  }141 142  if (!flags_.empty()) {143    context.RealFlagWarnings(144        flags_, "evaluation of intrinsic function or operation");145  }146  errno = 0;147  if (fesetenv(&originalFenv_) != 0) {148    std::fprintf(149        stderr, "fesetenv() failed: %s\n", llvm::sys::StrError(errno).c_str());150    common::die(151        "Folding with host runtime: fesetenv() failed while restoring fenv: %s",152        llvm::sys::StrError(errno).c_str());153  }154#if __x86_64__155  _mm_setcsr(originalMxcsr);156#endif157 158  errno = 0;159}160} // namespace Fortran::evaluate::host161