#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_FENVIMPL_H
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_FENVIMPL_H
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/architectures.h"
#if !defined(LIBC_TARGET_ARCH_IS_X86)
#error "Invalid include"
#endif
#include <stdint.h>
#include "hdr/types/fenv_t.h"
#include "src/__support/macros/sanitizer.h"
namespace LIBC_NAMESPACE_DECL {
namespace fputil {
namespace internal {
struct RoundingControlValue { … };
static constexpr uint16_t X87_ROUNDING_CONTROL_BIT_POSITION = …;
static constexpr uint16_t MXCSR_ROUNDING_CONTROL_BIT_POSITION = …;
struct ExceptionFlags { … };
static constexpr uint16_t X87_EXCEPTION_CONTROL_BIT_POSITION = …;
static constexpr uint16_t X87_EXCEPTION_CONTROL_BIT_POSITION_HIGH = …;
static constexpr uint16_t MXCSR_EXCEPTION_CONTOL_BIT_POISTION = …;
LIBC_INLINE uint16_t get_status_value_for_except(int excepts) { … }
LIBC_INLINE int exception_status_to_macro(uint16_t status) { … }
struct X87StateDescriptor { … };
LIBC_INLINE uint16_t get_x87_control_word() { … }
LIBC_INLINE void write_x87_control_word(uint16_t w) { … }
LIBC_INLINE uint16_t get_x87_status_word() { … }
LIBC_INLINE void clear_x87_exceptions() { … }
LIBC_INLINE uint32_t get_mxcsr() { … }
LIBC_INLINE void write_mxcsr(uint32_t w) { … }
LIBC_INLINE void get_x87_state_descriptor(X87StateDescriptor &s) { … }
LIBC_INLINE void write_x87_state_descriptor(const X87StateDescriptor &s) { … }
LIBC_INLINE void fwait() { … }
}
LIBC_INLINE int enable_except(int excepts) { … }
LIBC_INLINE int disable_except(int excepts) { … }
LIBC_INLINE int get_except() { … }
LIBC_INLINE int clear_except(int excepts) { … }
LIBC_INLINE int test_except(int excepts) { … }
LIBC_INLINE int set_except(int excepts) { … }
LIBC_INLINE int raise_except(int excepts) { … }
LIBC_INLINE int get_round() { … }
LIBC_INLINE int set_round(int mode) { … }
namespace internal {
#if defined(_WIN32)
struct FPState {
uint32_t control_word;
uint32_t status_word;
};
#elif defined(__APPLE__)
struct FPState {
uint16_t control_word;
uint16_t status_word;
uint32_t mxcsr;
uint8_t reserved[8];
};
#else
struct FPState { … };
#endif
}
static_assert …;
#ifdef _WIN32
struct WinExceptionFlags {
static constexpr uint32_t INEXACT_WIN = 0x01;
static constexpr uint32_t UNDERFLOW_WIN = 0x02;
static constexpr uint32_t OVERFLOW_WIN = 0x04;
static constexpr uint32_t DIV_BY_ZERO_WIN = 0x08;
static constexpr uint32_t INVALID_WIN = 0x10;
static constexpr uint32_t DENORMAL_WIN = 0x20;
static constexpr uint32_t HIGH_OFFSET = 24;
static constexpr uint32_t HIGH_INEXACT = INEXACT_WIN << HIGH_OFFSET;
static constexpr uint32_t HIGH_UNDERFLOW = UNDERFLOW_WIN << HIGH_OFFSET;
static constexpr uint32_t HIGH_OVERFLOW = OVERFLOW_WIN << HIGH_OFFSET;
static constexpr uint32_t HIGH_DIV_BY_ZERO = DIV_BY_ZERO_WIN << HIGH_OFFSET;
static constexpr uint32_t HIGH_INVALID = INVALID_WIN << HIGH_OFFSET;
static constexpr uint32_t HIGH_DENORMAL = DENORMAL_WIN << HIGH_OFFSET;
};
LIBC_INLINE int get_env(fenv_t *envp) {
internal::FPState *state = reinterpret_cast<internal::FPState *>(envp);
uint32_t status_word = 0;
uint32_t control_word = 0;
uint32_t mxcsr = internal::get_mxcsr();
status_word |= (mxcsr & (internal::ExceptionFlags::INVALID_F |
internal::ExceptionFlags::DENORMAL_F))
<< 4;
status_word |= (mxcsr & internal::ExceptionFlags::DIV_BY_ZERO_F) << 1;
status_word |= (mxcsr & internal::ExceptionFlags::OVERFLOW_F) >> 1;
status_word |= (mxcsr & internal::ExceptionFlags::UNDERFLOW_F) >> 3;
status_word |= (mxcsr & internal::ExceptionFlags::INEXACT_F) >> 5;
status_word |= status_word << WinExceptionFlags::HIGH_OFFSET;
control_word |= (mxcsr & ((internal::ExceptionFlags::INVALID_F |
internal::ExceptionFlags::DENORMAL_F)
<< 7)) >>
3;
control_word |= (mxcsr & (internal::ExceptionFlags::DIV_BY_ZERO_F << 7)) >> 6;
control_word |= (mxcsr & (internal::ExceptionFlags::OVERFLOW_F << 7)) >> 8;
control_word |= (mxcsr & (internal::ExceptionFlags::UNDERFLOW_F << 7)) >> 10;
control_word |= (mxcsr & (internal::ExceptionFlags::INEXACT_F << 7)) >> 12;
control_word |= control_word << WinExceptionFlags::HIGH_OFFSET;
control_word |= (mxcsr & 0x6000) >> 5;
control_word |= (mxcsr & 0x6000) << 17;
control_word |= (mxcsr & 0x8000) >> 5;
control_word |= (((mxcsr & 0x8000) >> 9) ^ (mxcsr & 0x0040)) << 5;
state->control_word = control_word;
state->status_word = status_word;
return 0;
}
LIBC_INLINE int set_env(const fenv_t *envp) {
const internal::FPState *state =
reinterpret_cast<const internal::FPState *>(envp);
uint32_t mxcsr = 0;
mxcsr |= static_cast<uint16_t>(
(state->status_word &
(WinExceptionFlags::HIGH_DENORMAL | WinExceptionFlags::HIGH_INVALID)) >>
28);
mxcsr |= static_cast<uint16_t>(
(state->status_word & WinExceptionFlags::HIGH_DIV_BY_ZERO) >> 25);
mxcsr |= static_cast<uint16_t>(
(state->status_word & WinExceptionFlags::HIGH_OVERFLOW) >> 23);
mxcsr |= static_cast<uint16_t>(
(state->status_word & WinExceptionFlags::HIGH_UNDERFLOW) >> 21);
mxcsr |= static_cast<uint16_t>(
(state->status_word & WinExceptionFlags::HIGH_INEXACT) >> 19);
mxcsr |= static_cast<uint16_t>(
(((state->control_word & 0x800) >> 1) ^ (state->control_word & 0x400)) >>
4);
mxcsr |= static_cast<uint16_t>(
(state->control_word &
(WinExceptionFlags::HIGH_DENORMAL | WinExceptionFlags::HIGH_INVALID)) >>
21);
mxcsr |= static_cast<uint16_t>(
(state->control_word & WinExceptionFlags::HIGH_DIV_BY_ZERO) >> 18);
mxcsr |= static_cast<uint16_t>(
(state->control_word & WinExceptionFlags::HIGH_OVERFLOW) >> 16);
mxcsr |= static_cast<uint16_t>(
(state->control_word & WinExceptionFlags::HIGH_UNDERFLOW) >> 14);
mxcsr |= static_cast<uint16_t>(
(state->control_word & WinExceptionFlags::HIGH_INEXACT) >> 12);
mxcsr |= static_cast<uint16_t>((state->control_word & 0xc0000000) >> 17);
mxcsr |= static_cast<uint16_t>((state->control_word & 0x400) << 5);
internal::write_mxcsr(mxcsr);
return 0;
}
#else
LIBC_INLINE int get_env(fenv_t *envp) { … }
LIBC_INLINE int set_env(const fenv_t *envp) { … }
#endif
}
}
#endif