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(¤tFenv) != 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(¤tFenv) != 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