brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.7 KiB · 18182ed Raw
286 lines · c
1//===-- aarch64 floating point env manipulation functions -------*- 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#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_AARCH64_FENVIMPL_H10#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_AARCH64_FENVIMPL_H11 12#include "src/__support/macros/attributes.h" // LIBC_INLINE13#include "src/__support/macros/config.h"14#include "src/__support/macros/properties/architectures.h"15 16#if !defined(LIBC_TARGET_ARCH_IS_AARCH64) || defined(__APPLE__)17#error "Invalid include"18#endif19 20#include <arm_acle.h>21 22#include "hdr/fenv_macros.h"23#include "hdr/stdint_proxy.h"24#include "hdr/types/fenv_t.h"25#include "src/__support/FPUtil/FPBits.h"26 27namespace LIBC_NAMESPACE_DECL {28namespace fputil {29struct FEnv {30  struct FPState {31    uint32_t ControlWord;32    uint32_t StatusWord;33  };34 35  static_assert(36      sizeof(fenv_t) == sizeof(FPState),37      "Internal floating point state does not match the public fenv_t type.");38 39  static constexpr uint32_t TONEAREST = 0x0;40  static constexpr uint32_t UPWARD = 0x1;41  static constexpr uint32_t DOWNWARD = 0x2;42  static constexpr uint32_t TOWARDZERO = 0x3;43 44  static constexpr uint32_t INVALID_F = 0x1;45  static constexpr uint32_t DIVBYZERO_F = 0x2;46  static constexpr uint32_t OVERFLOW_F = 0x4;47  static constexpr uint32_t UNDERFLOW_F = 0x8;48  static constexpr uint32_t INEXACT_F = 0x10;49 50  // Zero-th bit is the first bit.51  static constexpr uint32_t RoundingControlBitPosition = 22;52  static constexpr uint32_t ExceptionStatusFlagsBitPosition = 0;53  static constexpr uint32_t ExceptionControlFlagsBitPosition = 8;54 55  LIBC_INLINE static uint32_t getStatusValueForExcept(int excepts) {56    return ((excepts & FE_INVALID) ? INVALID_F : 0) |57           ((excepts & FE_DIVBYZERO) ? DIVBYZERO_F : 0) |58           ((excepts & FE_OVERFLOW) ? OVERFLOW_F : 0) |59           ((excepts & FE_UNDERFLOW) ? UNDERFLOW_F : 0) |60           ((excepts & FE_INEXACT) ? INEXACT_F : 0);61  }62 63  LIBC_INLINE static int exceptionStatusToMacro(uint32_t status) {64    return ((status & INVALID_F) ? FE_INVALID : 0) |65           ((status & DIVBYZERO_F) ? FE_DIVBYZERO : 0) |66           ((status & OVERFLOW_F) ? FE_OVERFLOW : 0) |67           ((status & UNDERFLOW_F) ? FE_UNDERFLOW : 0) |68           ((status & INEXACT_F) ? FE_INEXACT : 0);69  }70 71  static uint32_t getControlWord() {72#ifdef __clang__73    // GCC does not currently support __arm_rsr.74    return __arm_rsr("fpcr");75#else76    return __builtin_aarch64_get_fpcr();77#endif78  }79 80  static void writeControlWord(uint32_t fpcr) {81#ifdef __clang__82    // GCC does not currently support __arm_wsr.83    __arm_wsr("fpcr", fpcr);84#else85    __builtin_aarch64_set_fpcr(fpcr);86#endif87  }88 89  static uint32_t getStatusWord() {90#ifdef __clang__91    return __arm_rsr("fpsr");92#else93    return __builtin_aarch64_get_fpsr();94#endif95  }96 97  static void writeStatusWord(uint32_t fpsr) {98#ifdef __clang__99    __arm_wsr("fpsr", fpsr);100#else101    __builtin_aarch64_set_fpsr(fpsr);102#endif103  }104};105 106LIBC_INLINE int enable_except(int excepts) {107  uint32_t newExcepts = FEnv::getStatusValueForExcept(excepts);108  uint32_t controlWord = FEnv::getControlWord();109  int oldExcepts =110      (controlWord >> FEnv::ExceptionControlFlagsBitPosition) & 0x1F;111  controlWord |= (newExcepts << FEnv::ExceptionControlFlagsBitPosition);112  FEnv::writeControlWord(controlWord);113  return FEnv::exceptionStatusToMacro(static_cast<uint32_t>(oldExcepts));114}115 116LIBC_INLINE int disable_except(int excepts) {117  uint32_t disabledExcepts = FEnv::getStatusValueForExcept(excepts);118  uint32_t controlWord = FEnv::getControlWord();119  int oldExcepts =120      (controlWord >> FEnv::ExceptionControlFlagsBitPosition) & 0x1F;121  controlWord &= ~(disabledExcepts << FEnv::ExceptionControlFlagsBitPosition);122  FEnv::writeControlWord(controlWord);123  return FEnv::exceptionStatusToMacro(static_cast<uint32_t>(oldExcepts));124}125 126LIBC_INLINE int get_except() {127  uint32_t controlWord = FEnv::getControlWord();128  uint32_t enabledExcepts =129      (controlWord >> FEnv::ExceptionControlFlagsBitPosition) & 0x1F;130  return FEnv::exceptionStatusToMacro(enabledExcepts);131}132 133LIBC_INLINE int clear_except(int excepts) {134  uint32_t statusWord = FEnv::getStatusWord();135  uint32_t toClear = FEnv::getStatusValueForExcept(excepts);136  statusWord &= ~(toClear << FEnv::ExceptionStatusFlagsBitPosition);137  FEnv::writeStatusWord(statusWord);138  return 0;139}140 141LIBC_INLINE int test_except(int excepts) {142  uint32_t toTest = FEnv::getStatusValueForExcept(excepts);143  uint32_t statusWord = FEnv::getStatusWord();144  return FEnv::exceptionStatusToMacro(145      (statusWord >> FEnv::ExceptionStatusFlagsBitPosition) & toTest);146}147 148LIBC_INLINE int set_except(int excepts) {149  uint32_t statusWord = FEnv::getStatusWord();150  uint32_t statusValue = FEnv::getStatusValueForExcept(excepts);151  statusWord |= (statusValue << FEnv::ExceptionStatusFlagsBitPosition);152  FEnv::writeStatusWord(statusWord);153  return 0;154}155 156LIBC_INLINE int raise_except(int excepts) {157  float zero = 0.0f;158  float one = 1.0f;159  float largeValue = FPBits<float>::max_normal().get_val();160  float smallValue = FPBits<float>::min_normal().get_val();161  auto divfunc = [](float a, float b) {162    __asm__ __volatile__("ldr  s0, %0\n\t"163                         "ldr  s1, %1\n\t"164                         "fdiv s0, s0, s1\n\t"165                         : // No outputs166                         : "m"(a), "m"(b)167                         : "s0", "s1" /* s0 and s1 are clobbered */);168  };169 170  uint32_t toRaise = FEnv::getStatusValueForExcept(excepts);171  int result = 0;172 173  if (toRaise & FEnv::INVALID_F) {174    divfunc(zero, zero);175    uint32_t statusWord = FEnv::getStatusWord();176    if (!((statusWord >> FEnv::ExceptionStatusFlagsBitPosition) &177          FEnv::INVALID_F))178      result = -1;179  }180 181  if (toRaise & FEnv::DIVBYZERO_F) {182    divfunc(one, zero);183    uint32_t statusWord = FEnv::getStatusWord();184    if (!((statusWord >> FEnv::ExceptionStatusFlagsBitPosition) &185          FEnv::DIVBYZERO_F))186      result = -1;187  }188  if (toRaise & FEnv::OVERFLOW_F) {189    divfunc(largeValue, smallValue);190    uint32_t statusWord = FEnv::getStatusWord();191    if (!((statusWord >> FEnv::ExceptionStatusFlagsBitPosition) &192          FEnv::OVERFLOW_F))193      result = -1;194  }195  if (toRaise & FEnv::UNDERFLOW_F) {196    divfunc(smallValue, largeValue);197    uint32_t statusWord = FEnv::getStatusWord();198    if (!((statusWord >> FEnv::ExceptionStatusFlagsBitPosition) &199          FEnv::UNDERFLOW_F))200      result = -1;201  }202  if (toRaise & FEnv::INEXACT_F) {203    float two = 2.0f;204    float three = 3.0f;205    // 2.0 / 3.0 cannot be represented exactly in any radix 2 floating point206    // format.207    divfunc(two, three);208    uint32_t statusWord = FEnv::getStatusWord();209    if (!((statusWord >> FEnv::ExceptionStatusFlagsBitPosition) &210          FEnv::INEXACT_F))211      result = -1;212  }213  return result;214}215 216LIBC_INLINE int get_round() {217  uint32_t roundingMode =218      (FEnv::getControlWord() >> FEnv::RoundingControlBitPosition) & 0x3;219  switch (roundingMode) {220  case FEnv::TONEAREST:221    return FE_TONEAREST;222  case FEnv::DOWNWARD:223    return FE_DOWNWARD;224  case FEnv::UPWARD:225    return FE_UPWARD;226  case FEnv::TOWARDZERO:227    return FE_TOWARDZERO;228  default:229    return -1; // Error value.230  }231}232 233LIBC_INLINE int set_round(int mode) {234  uint16_t bitValue;235  switch (mode) {236  case FE_TONEAREST:237    bitValue = FEnv::TONEAREST;238    break;239  case FE_DOWNWARD:240    bitValue = FEnv::DOWNWARD;241    break;242  case FE_UPWARD:243    bitValue = FEnv::UPWARD;244    break;245  case FE_TOWARDZERO:246    bitValue = FEnv::TOWARDZERO;247    break;248  default:249    return 1; // To indicate failure250  }251 252  uint32_t controlWord = FEnv::getControlWord();253  controlWord &=254      static_cast<uint32_t>(~(0x3 << FEnv::RoundingControlBitPosition));255  controlWord |=256      static_cast<uint32_t>(bitValue << FEnv::RoundingControlBitPosition);257  FEnv::writeControlWord(controlWord);258 259  return 0;260}261 262LIBC_INLINE int get_env(fenv_t *envp) {263  FEnv::FPState *state = reinterpret_cast<FEnv::FPState *>(envp);264  state->ControlWord = FEnv::getControlWord();265  state->StatusWord = FEnv::getStatusWord();266  return 0;267}268 269LIBC_INLINE int set_env(const fenv_t *envp) {270  if (envp == FE_DFL_ENV) {271    // Default status and control words bits are all zeros so we just272    // write zeros.273    FEnv::writeStatusWord(0);274    FEnv::writeControlWord(0);275    return 0;276  }277  const FEnv::FPState *state = reinterpret_cast<const FEnv::FPState *>(envp);278  FEnv::writeControlWord(state->ControlWord);279  FEnv::writeStatusWord(state->StatusWord);280  return 0;281}282} // namespace fputil283} // namespace LIBC_NAMESPACE_DECL284 285#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_AARCH64_FENVIMPL_H286