brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.1 KiB · 5da5097 Raw
651 lines · c
1//===-- x86_64 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_X86_64_FENVIMPL_H10#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_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_X86)17#error "Invalid include"18#endif19 20#include "hdr/stdint_proxy.h"21#include "hdr/types/fenv_t.h"22#include "src/__support/macros/sanitizer.h"23 24namespace LIBC_NAMESPACE_DECL {25namespace fputil {26 27namespace internal {28 29// Normally, one should be able to define FE_* macros to the exact rounding mode30// encodings. However, since we want LLVM libc to be compiled against headers31// from other libcs, we cannot assume that FE_* macros are always defined in32// such a manner. So, we will define enums corresponding to the x86_64 bit33// encodings. The implementations can map from FE_* to the corresponding enum34// values.35 36// The rounding control values in the x87 control register and the MXCSR37// register have the same 2-bit enoding but have different bit positions.38// See below for the bit positions.39struct RoundingControlValue {40  static constexpr uint16_t TO_NEAREST = 0x0;41  static constexpr uint16_t DOWNWARD = 0x1;42  static constexpr uint16_t UPWARD = 0x2;43  static constexpr uint16_t TOWARD_ZERO = 0x3;44};45 46static constexpr uint16_t X87_ROUNDING_CONTROL_BIT_POSITION = 10;47static constexpr uint16_t MXCSR_ROUNDING_CONTROL_BIT_POSITION = 13;48 49// The exception flags in the x87 status register and the MXCSR have the same50// encoding as well as the same bit positions.51struct ExceptionFlags {52  static constexpr uint16_t INVALID_F = 0x1;53  // Some libcs define __FE_DENORM corresponding to the denormal input54  // exception and include it in FE_ALL_EXCEPTS. We define and use it to55  // support compiling against headers provided by such libcs.56  static constexpr uint16_t DENORMAL_F = 0x2;57  static constexpr uint16_t DIV_BY_ZERO_F = 0x4;58  static constexpr uint16_t OVERFLOW_F = 0x8;59  static constexpr uint16_t UNDERFLOW_F = 0x10;60  static constexpr uint16_t INEXACT_F = 0x20;61};62 63// The exception control bits occupy six bits, one bit for each exception.64// In the x87 control word, they occupy the first 6 bits. In the MXCSR65// register, they occupy bits 7 to 12.66static constexpr uint16_t X87_EXCEPTION_CONTROL_BIT_POSITION = 0;67static constexpr uint16_t X87_EXCEPTION_CONTROL_BIT_POSITION_HIGH = 24;68static constexpr uint16_t MXCSR_EXCEPTION_CONTOL_BIT_POISTION = 7;69 70// Exception flags are individual bits in the corresponding registers.71// So, we just OR the bit values to get the full set of exceptions.72LIBC_INLINE uint16_t get_status_value_for_except(int excepts) {73  // We will make use of the fact that exception control bits are single74  // bit flags in the control registers.75  return ((excepts & FE_INVALID) ? ExceptionFlags::INVALID_F : 0) |76#ifdef __FE_DENORM77         ((excepts & __FE_DENORM) ? ExceptionFlags::DENORMAL_F : 0) |78#endif // __FE_DENORM79         ((excepts & FE_DIVBYZERO) ? ExceptionFlags::DIV_BY_ZERO_F : 0) |80         ((excepts & FE_OVERFLOW) ? ExceptionFlags::OVERFLOW_F : 0) |81         ((excepts & FE_UNDERFLOW) ? ExceptionFlags::UNDERFLOW_F : 0) |82         ((excepts & FE_INEXACT) ? ExceptionFlags::INEXACT_F : 0);83}84 85LIBC_INLINE int exception_status_to_macro(uint16_t status) {86  return ((status & ExceptionFlags::INVALID_F) ? FE_INVALID : 0) |87#ifdef __FE_DENORM88         ((status & ExceptionFlags::DENORMAL_F) ? __FE_DENORM : 0) |89#endif // __FE_DENORM90         ((status & ExceptionFlags::DIV_BY_ZERO_F) ? FE_DIVBYZERO : 0) |91         ((status & ExceptionFlags::OVERFLOW_F) ? FE_OVERFLOW : 0) |92         ((status & ExceptionFlags::UNDERFLOW_F) ? FE_UNDERFLOW : 0) |93         ((status & ExceptionFlags::INEXACT_F) ? FE_INEXACT : 0);94}95 96struct X87StateDescriptor {97  uint16_t control_word;98  uint16_t unused1;99  uint16_t status_word;100  uint16_t unused2;101  // TODO: Elaborate the remaining 20 bytes as required.102  uint32_t _[5];103};104 105LIBC_INLINE uint16_t get_x87_control_word() {106  uint16_t w;107  __asm__ __volatile__("fnstcw %0" : "=m"(w)::);108  MSAN_UNPOISON(&w, sizeof(w));109  return w;110}111 112LIBC_INLINE void write_x87_control_word(uint16_t w) {113  __asm__ __volatile__("fldcw %0" : : "m"(w) :);114}115 116LIBC_INLINE uint16_t get_x87_status_word() {117  uint16_t w;118  __asm__ __volatile__("fnstsw %0" : "=m"(w)::);119  MSAN_UNPOISON(&w, sizeof(w));120  return w;121}122 123LIBC_INLINE void clear_x87_exceptions() {124  __asm__ __volatile__("fnclex" : : :);125}126 127LIBC_INLINE uint32_t get_mxcsr() {128  uint32_t w;129  __asm__ __volatile__("stmxcsr %0" : "=m"(w)::);130  MSAN_UNPOISON(&w, sizeof(w));131  return w;132}133 134LIBC_INLINE void write_mxcsr(uint32_t w) {135  __asm__ __volatile__("ldmxcsr %0" : : "m"(w) :);136}137 138LIBC_INLINE void get_x87_state_descriptor(X87StateDescriptor &s) {139  __asm__ __volatile__("fnstenv %0" : "=m"(s));140  MSAN_UNPOISON(&s, sizeof(s));141}142 143LIBC_INLINE void write_x87_state_descriptor(const X87StateDescriptor &s) {144  __asm__ __volatile__("fldenv %0" : : "m"(s) :);145}146 147LIBC_INLINE void fwait() { __asm__ __volatile__("fwait"); }148 149} // namespace internal150 151LIBC_INLINE int enable_except(int excepts) {152  // In the x87 control word and in MXCSR, an exception is blocked153  // if the corresponding bit is set. That is the reason for all the154  // bit-flip operations below as we need to turn the bits to zero155  // to enable them.156 157  uint16_t bit_mask = internal::get_status_value_for_except(excepts);158 159  uint16_t x87_cw = internal::get_x87_control_word();160  uint16_t old_excepts = ~x87_cw & 0x3F; // Save previously enabled exceptions.161  x87_cw &= ~bit_mask;162  internal::write_x87_control_word(x87_cw);163 164  // Enabling SSE exceptions via MXCSR is a nice thing to do but165  // might not be of much use practically as SSE exceptions and the x87166  // exceptions are independent of each other.167  uint32_t mxcsr = internal::get_mxcsr();168  mxcsr &= ~(bit_mask << internal::MXCSR_EXCEPTION_CONTOL_BIT_POISTION);169  internal::write_mxcsr(mxcsr);170 171  // Since the x87 exceptions and SSE exceptions are independent of each,172  // it doesn't make much sence to report both in the return value. Most173  // often, the standard floating point functions deal with FPU operations174  // so we will retrun only the old x87 exceptions.175  return internal::exception_status_to_macro(old_excepts);176}177 178LIBC_INLINE int disable_except(int excepts) {179  // In the x87 control word and in MXCSR, an exception is blocked180  // if the corresponding bit is set.181 182  uint16_t bit_mask = internal::get_status_value_for_except(excepts);183 184  uint16_t x87_cw = internal::get_x87_control_word();185  uint16_t old_excepts = ~x87_cw & 0x3F; // Save previously enabled exceptions.186  x87_cw |= bit_mask;187  internal::write_x87_control_word(x87_cw);188 189  // Just like in enable_except, it is not clear if disabling SSE exceptions190  // is required. But, we will still do it only as a "nice thing to do".191  uint32_t mxcsr = internal::get_mxcsr();192  mxcsr |= (bit_mask << internal::MXCSR_EXCEPTION_CONTOL_BIT_POISTION);193  internal::write_mxcsr(mxcsr);194 195  return internal::exception_status_to_macro(old_excepts);196}197 198LIBC_INLINE int get_except() {199  uint16_t mxcsr = static_cast<uint16_t>(internal::get_mxcsr());200  uint16_t enabled_excepts = ~(mxcsr >> 7) & 0x3F;201  return internal::exception_status_to_macro(enabled_excepts);202}203 204LIBC_INLINE int clear_except(int excepts) {205  internal::X87StateDescriptor state;206  internal::get_x87_state_descriptor(state);207  state.status_word &=208      static_cast<uint16_t>(~internal::get_status_value_for_except(excepts));209  internal::write_x87_state_descriptor(state);210 211  uint32_t mxcsr = internal::get_mxcsr();212  mxcsr &= ~internal::get_status_value_for_except(excepts);213  internal::write_mxcsr(mxcsr);214  return 0;215}216 217LIBC_INLINE int test_except(int excepts) {218  uint16_t status_word = internal::get_x87_status_word();219  uint32_t mxcsr = internal::get_mxcsr();220  // Check both x87 status word and MXCSR.221  uint16_t status_value = internal::get_status_value_for_except(excepts);222  return internal::exception_status_to_macro(223      static_cast<uint16_t>(status_value & (status_word | mxcsr)));224}225 226// Sets the exception flags but does not trigger the exception handler.227LIBC_INLINE int set_except(int excepts) {228  uint16_t status_value = internal::get_status_value_for_except(excepts);229  internal::X87StateDescriptor state;230  internal::get_x87_state_descriptor(state);231  state.status_word |= status_value;232  internal::write_x87_state_descriptor(state);233 234  uint32_t mxcsr = internal::get_mxcsr();235  mxcsr |= status_value;236  internal::write_mxcsr(mxcsr);237 238  return 0;239}240 241template <bool SKIP_X87_FPU = false> LIBC_INLINE int raise_except(int excepts) {242  uint16_t status_value = internal::get_status_value_for_except(excepts);243 244  // We set the status flag for exception one at a time and call the245  // fwait instruction to actually get the processor to raise the246  // exception by calling the exception handler. This scheme is per247  // the description in "8.6 X87 FPU EXCEPTION SYNCHRONIZATION"248  // of the "Intel 64 and IA-32 Architectures Software Developer's249  // Manual, Vol 1".250 251  // FPU status word is read for each exception separately as the252  // exception handler can potentially write to it (typically to clear253  // the corresponding exception flag). By reading it separately, we254  // ensure that the writes by the exception handler are maintained255  // when raising the next exception.256 257  auto raise_helper = [](uint16_t singleExceptFlag) {258    if constexpr (!SKIP_X87_FPU) {259      internal::X87StateDescriptor state;260      internal::get_x87_state_descriptor(state);261      state.status_word |= singleExceptFlag;262      internal::write_x87_state_descriptor(state);263    }264 265    uint32_t mxcsr = 0;266    mxcsr = internal::get_mxcsr();267    mxcsr |= singleExceptFlag;268    internal::write_mxcsr(mxcsr);269    internal::fwait();270  };271 272  if (status_value & internal::ExceptionFlags::INVALID_F)273    raise_helper(internal::ExceptionFlags::INVALID_F);274  if (status_value & internal::ExceptionFlags::DIV_BY_ZERO_F)275    raise_helper(internal::ExceptionFlags::DIV_BY_ZERO_F);276  if (status_value & internal::ExceptionFlags::OVERFLOW_F)277    raise_helper(internal::ExceptionFlags::OVERFLOW_F);278  if (status_value & internal::ExceptionFlags::UNDERFLOW_F)279    raise_helper(internal::ExceptionFlags::UNDERFLOW_F);280  if (status_value & internal::ExceptionFlags::INEXACT_F)281    raise_helper(internal::ExceptionFlags::INEXACT_F);282#ifdef __FE_DENORM283  if (status_value & internal::ExceptionFlags::DENORMAL_F) {284    raise_helper(internal::ExceptionFlags::DENORMAL_F);285  }286#endif // __FE_DENORM287 288  // There is no special synchronization scheme available to289  // raise SEE exceptions. So, we will ignore that for now.290  // Just plain writing to the MXCSR register does not guarantee291  // the exception handler will be called.292 293  return 0;294}295 296LIBC_INLINE int get_round() {297  uint16_t bit_value =298      (internal::get_mxcsr() >> internal::MXCSR_ROUNDING_CONTROL_BIT_POSITION) &299      0x3;300  switch (bit_value) {301  case internal::RoundingControlValue::TO_NEAREST:302    return FE_TONEAREST;303  case internal::RoundingControlValue::DOWNWARD:304    return FE_DOWNWARD;305  case internal::RoundingControlValue::UPWARD:306    return FE_UPWARD;307  case internal::RoundingControlValue::TOWARD_ZERO:308    return FE_TOWARDZERO;309  default:310    return -1; // Error value.311  }312}313 314LIBC_INLINE int set_round(int mode) {315  uint16_t bit_value;316  switch (mode) {317  case FE_TONEAREST:318    bit_value = internal::RoundingControlValue::TO_NEAREST;319    break;320  case FE_DOWNWARD:321    bit_value = internal::RoundingControlValue::DOWNWARD;322    break;323  case FE_UPWARD:324    bit_value = internal::RoundingControlValue::UPWARD;325    break;326  case FE_TOWARDZERO:327    bit_value = internal::RoundingControlValue::TOWARD_ZERO;328    break;329  default:330    return 1; // To indicate failure331  }332 333  uint16_t x87_value = static_cast<uint16_t>(334      bit_value << internal::X87_ROUNDING_CONTROL_BIT_POSITION);335  uint16_t x87_control = internal::get_x87_control_word();336  x87_control = static_cast<uint16_t>(337      (x87_control &338       ~(uint16_t(0x3) << internal::X87_ROUNDING_CONTROL_BIT_POSITION)) |339      x87_value);340  internal::write_x87_control_word(x87_control);341 342  uint32_t mxcsr_value = bit_value343                         << internal::MXCSR_ROUNDING_CONTROL_BIT_POSITION;344  uint32_t mxcsr_control = internal::get_mxcsr();345  mxcsr_control = (mxcsr_control &346                   ~(0x3 << internal::MXCSR_ROUNDING_CONTROL_BIT_POSITION)) |347                  mxcsr_value;348  internal::write_mxcsr(mxcsr_control);349 350  return 0;351}352 353namespace internal {354 355#if defined(_WIN32)356// MSVC fenv.h defines a very simple representation of the floating point state357// which just consists of control and status words of the x87 unit.358struct FPState {359  uint32_t control_word;360  uint32_t status_word;361};362#elif defined(__APPLE__)363struct FPState {364  uint16_t control_word;365  uint16_t status_word;366  uint32_t mxcsr;367  uint8_t reserved[8];368};369#else370struct FPState {371  X87StateDescriptor x87_status;372  uint32_t mxcsr;373};374#endif // _WIN32375 376} // namespace internal377 378static_assert(379    sizeof(fenv_t) == sizeof(internal::FPState),380    "Internal floating point state does not match the public fenv_t type.");381 382#ifdef _WIN32383 384// The exception flags in the Windows FEnv struct and the MXCSR have almost385// reversed bit positions.386struct WinExceptionFlags {387  static constexpr uint32_t INEXACT_WIN = 0x01;388  static constexpr uint32_t UNDERFLOW_WIN = 0x02;389  static constexpr uint32_t OVERFLOW_WIN = 0x04;390  static constexpr uint32_t DIV_BY_ZERO_WIN = 0x08;391  static constexpr uint32_t INVALID_WIN = 0x10;392  static constexpr uint32_t DENORMAL_WIN = 0x20;393 394  // The Windows FEnv struct has a second copy of all of these bits in the high395  // byte of the 32 bit control word. These are used as the source of truth when396  // calling fesetenv.397  static constexpr uint32_t HIGH_OFFSET = 24;398 399  static constexpr uint32_t HIGH_INEXACT = INEXACT_WIN << HIGH_OFFSET;400  static constexpr uint32_t HIGH_UNDERFLOW = UNDERFLOW_WIN << HIGH_OFFSET;401  static constexpr uint32_t HIGH_OVERFLOW = OVERFLOW_WIN << HIGH_OFFSET;402  static constexpr uint32_t HIGH_DIV_BY_ZERO = DIV_BY_ZERO_WIN << HIGH_OFFSET;403  static constexpr uint32_t HIGH_INVALID = INVALID_WIN << HIGH_OFFSET;404  static constexpr uint32_t HIGH_DENORMAL = DENORMAL_WIN << HIGH_OFFSET;405};406 407/*408    fenv_t control word format:409 410    Windows (at least for x64) uses a 4 byte control fenv control word stored in411    a 32 bit integer. The first byte contains just the rounding mode and the412    exception masks, while the last two bytes contain that same information as413    well as the flush-to-zero and denormals-are-zero flags. The flags are414    represented with a truth table:415 416    00 - No flags set417    01 - Flush-to-zero and Denormals-are-zero set418    11 - Flush-to-zero set419    10 - Denormals-are-zero set420 421    U represents unused.422 423     +-----Rounding Mode-----+424     |                       |425    ++                      ++426    ||                      ||427    RRMMMMMM UUUUUUUU UUUUFFRR UUMMMMMM428      |    |              ||     |    |429      +----+      flags---++     +----+430           |                          |431           +------Exception Masks-----+432 433 434    fenv_t status word format:435 436    The status word is a lot simpler for this conversion, since only the437    exception flags are used in the MXCSR.438 439      +----+---Exception Flags---+----+440      |    |                     |    |441    UUEEEEEE UUUUUUUU UUUUUUUU UUEEEEEE442 443 444 445    MXCSR Format:446 447    The MXCSR format is the same information, just organized differently. Since448    the fenv_t struct for windows doesn't include the mxcsr bits, they must be449    generated from the control word bits.450 451      Exception Masks---+           +---Exception Flags452                        |           |453     Flush-to-zero---+  +----+ +----+454                     |  |    | |    |455                     FRRMMMMMMDEEEEEE456                      ||      |457                      ++      +---Denormals-are-zero458                      |459                      +---Rounding Mode460 461 462    The mask and flag order is as follows:463 464    fenv_t      mxcsr465 466    denormal    inexact467    invalid     underflow468    div by 0    overflow469    overflow    div by 0470    underflow   denormal471    inexact     invalid472 473    This is almost reverse, except for denormal and invalid which are in the474    same order in both.475  */476 477LIBC_INLINE int get_env(fenv_t *envp) {478  internal::FPState *state = reinterpret_cast<internal::FPState *>(envp);479 480  uint32_t status_word = 0;481  uint32_t control_word = 0;482 483  uint32_t mxcsr = internal::get_mxcsr();484 485  // Set exception flags in the status word486  status_word |= (mxcsr & (internal::ExceptionFlags::INVALID_F |487                           internal::ExceptionFlags::DENORMAL_F))488                 << 4;489  status_word |= (mxcsr & internal::ExceptionFlags::DIV_BY_ZERO_F) << 1;490  status_word |= (mxcsr & internal::ExceptionFlags::OVERFLOW_F) >> 1;491  status_word |= (mxcsr & internal::ExceptionFlags::UNDERFLOW_F) >> 3;492  status_word |= (mxcsr & internal::ExceptionFlags::INEXACT_F) >> 5;493  status_word |= status_word << WinExceptionFlags::HIGH_OFFSET;494 495  // Set exception masks in bits 0-5 and 24-29496  control_word |= (mxcsr & ((internal::ExceptionFlags::INVALID_F |497                             internal::ExceptionFlags::DENORMAL_F)498                            << 7)) >>499                  3;500  control_word |= (mxcsr & (internal::ExceptionFlags::DIV_BY_ZERO_F << 7)) >> 6;501  control_word |= (mxcsr & (internal::ExceptionFlags::OVERFLOW_F << 7)) >> 8;502  control_word |= (mxcsr & (internal::ExceptionFlags::UNDERFLOW_F << 7)) >> 10;503  control_word |= (mxcsr & (internal::ExceptionFlags::INEXACT_F << 7)) >> 12;504  control_word |= control_word << WinExceptionFlags::HIGH_OFFSET;505 506  // Set rounding in bits 8-9 and 30-31507  control_word |= (mxcsr & 0x6000) >> 5;508  control_word |= (mxcsr & 0x6000) << 17;509 510  // Set flush-to-zero in bit 10511  control_word |= (mxcsr & 0x8000) >> 5;512 513  // Set denormals-are-zero xor flush-to-zero in bit 11514  control_word |= (((mxcsr & 0x8000) >> 9) ^ (mxcsr & 0x0040)) << 5;515 516  state->control_word = control_word;517  state->status_word = status_word;518  return 0;519}520 521LIBC_INLINE int set_env(const fenv_t *envp) {522  const internal::FPState *state =523      reinterpret_cast<const internal::FPState *>(envp);524 525  uint32_t mxcsr = 0;526 527  // Set exception flags from the status word528  mxcsr |= static_cast<uint16_t>(529      (state->status_word &530       (WinExceptionFlags::HIGH_DENORMAL | WinExceptionFlags::HIGH_INVALID)) >>531      28);532  mxcsr |= static_cast<uint16_t>(533      (state->status_word & WinExceptionFlags::HIGH_DIV_BY_ZERO) >> 25);534  mxcsr |= static_cast<uint16_t>(535      (state->status_word & WinExceptionFlags::HIGH_OVERFLOW) >> 23);536  mxcsr |= static_cast<uint16_t>(537      (state->status_word & WinExceptionFlags::HIGH_UNDERFLOW) >> 21);538  mxcsr |= static_cast<uint16_t>(539      (state->status_word & WinExceptionFlags::HIGH_INEXACT) >> 19);540 541  // Set denormals-are-zero from bit 10 xor bit 11542  mxcsr |= static_cast<uint16_t>(543      (((state->control_word & 0x800) >> 1) ^ (state->control_word & 0x400)) >>544      4);545 546  // Set exception masks from bits 24-29547  mxcsr |= static_cast<uint16_t>(548      (state->control_word &549       (WinExceptionFlags::HIGH_DENORMAL | WinExceptionFlags::HIGH_INVALID)) >>550      21);551  mxcsr |= static_cast<uint16_t>(552      (state->control_word & WinExceptionFlags::HIGH_DIV_BY_ZERO) >> 18);553  mxcsr |= static_cast<uint16_t>(554      (state->control_word & WinExceptionFlags::HIGH_OVERFLOW) >> 16);555  mxcsr |= static_cast<uint16_t>(556      (state->control_word & WinExceptionFlags::HIGH_UNDERFLOW) >> 14);557  mxcsr |= static_cast<uint16_t>(558      (state->control_word & WinExceptionFlags::HIGH_INEXACT) >> 12);559 560  // Set rounding from bits 30-31561  mxcsr |= static_cast<uint16_t>((state->control_word & 0xc0000000) >> 17);562 563  // Set flush-to-zero from bit 10564  mxcsr |= static_cast<uint16_t>((state->control_word & 0x400) << 5);565 566  internal::write_mxcsr(mxcsr);567  return 0;568}569#else570LIBC_INLINE int get_env(fenv_t *envp) {571  internal::FPState *state = reinterpret_cast<internal::FPState *>(envp);572#ifdef __APPLE__573  internal::X87StateDescriptor x87_status;574  internal::get_x87_state_descriptor(x87_status);575  state->control_word = x87_status.control_word;576  state->status_word = x87_status.status_word;577#else578  internal::get_x87_state_descriptor(state->x87_status);579#endif // __APPLE__580  state->mxcsr = internal::get_mxcsr();581  return 0;582}583 584LIBC_INLINE int set_env(const fenv_t *envp) {585  // envp contains everything including pieces like the current586  // top of FPU stack. We cannot arbitrarily change them. So, we first587  // read the current status and update only those pieces which are588  // not disruptive.589  internal::X87StateDescriptor x87_status;590  internal::get_x87_state_descriptor(x87_status);591 592  if (envp == FE_DFL_ENV) {593    // Reset the exception flags in the status word.594    x87_status.status_word &= ~uint16_t(0x3F);595    // Reset other non-sensitive parts of the status word.596    for (int i = 0; i < 5; i++)597      x87_status._[i] = 0;598    // In the control word, we do the following:599    // 1. Mask all exceptions600    // 2. Set rounding mode to round-to-nearest601    // 3. Set the internal precision to double extended precision.602    x87_status.control_word |= uint16_t(0x3F);         // Mask all exceptions.603    x87_status.control_word &= ~(uint16_t(0x3) << 10); // Round to nearest.604    x87_status.control_word |= (uint16_t(0x3) << 8);   // Extended precision.605    internal::write_x87_state_descriptor(x87_status);606 607    // We take the exact same approach MXCSR register as well.608    // MXCSR has two additional fields, "flush-to-zero" and609    // "denormals-are-zero". We reset those bits. Also, MXCSR does not610    // have a field which controls the precision of internal operations.611    uint32_t mxcsr = internal::get_mxcsr();612    mxcsr &= ~uint16_t(0x3F);        // Clear exception flags.613    mxcsr &= ~(uint16_t(0x1) << 6);  // Reset denormals-are-zero614    mxcsr |= (uint16_t(0x3F) << 7);  // Mask exceptions615    mxcsr &= ~(uint16_t(0x3) << 13); // Round to nearest.616    mxcsr &= ~(uint16_t(0x1) << 15); // Reset flush-to-zero617    internal::write_mxcsr(mxcsr);618 619    return 0;620  }621 622  const internal::FPState *fpstate =623      reinterpret_cast<const internal::FPState *>(envp);624 625  // Copy the exception status flags from envp.626  x87_status.status_word &= ~uint16_t(0x3F);627#ifdef __APPLE__628  x87_status.status_word |= (fpstate->status_word & 0x3F);629  // We can set the x87 control word as is as there no sensitive bits.630  x87_status.control_word = fpstate->control_word;631#else632  x87_status.status_word |= (fpstate->x87_status.status_word & 0x3F);633  // Copy other non-sensitive parts of the status word.634  for (int i = 0; i < 5; i++)635    x87_status._[i] = fpstate->x87_status._[i];636  // We can set the x87 control word as is as there no sensitive bits.637  x87_status.control_word = fpstate->x87_status.control_word;638#endif // __APPLE__639  internal::write_x87_state_descriptor(x87_status);640 641  // We can write the MXCSR state as is as there are no sensitive bits.642  internal::write_mxcsr(fpstate->mxcsr);643  return 0;644}645#endif646 647} // namespace fputil648} // namespace LIBC_NAMESPACE_DECL649 650#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_FENVIMPL_H651