reactos/sdk/include/ucrt/fenv.h
2025-01-30 11:30:32 +02:00

169 lines
5.9 KiB
C

//
// fenv.h
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Floating point environment library.
//
#pragma once
#ifndef _FENV // include guard for 3rd party interop
#define _FENV
#include <corecrt.h>
#include <float.h>
#pragma warning(push)
#pragma warning(disable: _UCRT_DISABLED_WARNINGS)
_UCRT_DISABLE_CLANG_WARNINGS
_CRT_BEGIN_C_HEADER
#define FE_TONEAREST _RC_NEAR
#define FE_UPWARD _RC_UP
#define FE_DOWNWARD _RC_DOWN
#define FE_TOWARDZERO _RC_CHOP
#define FE_ROUND_MASK _MCW_RC
_ACRTIMP int __cdecl fegetround(void);
_ACRTIMP int __cdecl fesetround(_In_ int _Round);
#if !defined _M_CEE
typedef unsigned long fexcept_t;
typedef struct fenv_t
{
unsigned long _Fe_ctl, _Fe_stat;
} fenv_t;
#define FE_INEXACT _SW_INEXACT // _EM_INEXACT 0x00000001 inexact (precision)
#define FE_UNDERFLOW _SW_UNDERFLOW // _EM_UNDERFLOW 0x00000002 underflow
#define FE_OVERFLOW _SW_OVERFLOW // _EM_OVERFLOW 0x00000004 overflow
#define FE_DIVBYZERO _SW_ZERODIVIDE // _EM_ZERODIVIDE 0x00000008 zero divide
#define FE_INVALID _SW_INVALID // _EM_INVALID 0x00000010 invalid
#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
_ACRTIMP int __cdecl fegetenv(_Out_ fenv_t* _Env);
_ACRTIMP int __cdecl fesetenv(_In_ fenv_t const* _Env);
_ACRTIMP int __cdecl feclearexcept(_In_ int _Flags);
_ACRTIMP _Success_(return == 0) int __cdecl feholdexcept(_Out_ fenv_t* _Env);
_ACRTIMP int __cdecl fetestexcept(_In_ int _Flags);
_ACRTIMP int __cdecl fegetexceptflag(_Out_ fexcept_t* _Except, _In_ int _TestFlags);
_ACRTIMP int __cdecl fesetexceptflag(_In_ fexcept_t const* _Except, _In_ int _SetFlags);
#if !defined __midl // MIDL does not support compound initializers
// In the original implementation (_Fenv0), the global variable was zero
// initialized, indicating no exceptions are masked. In the current
// implementation (_Fenv1), the global variable is initialized with all
// exceptions masked, which is the actual initial environment.
#ifdef __cplusplus
#define CPP_EXTERN extern
#else
#define CPP_EXTERN
#endif
#if defined _M_IX86
CPP_EXTERN __declspec(selectany) const fenv_t _Fenv1 = { 0x3f3f103f, 0 };
#elif defined _M_X64
CPP_EXTERN __declspec(selectany) const fenv_t _Fenv1 = { 0x3f00003f, 0 };
#else
CPP_EXTERN __declspec(selectany) const fenv_t _Fenv1 = { 0x0000003f, 0 };
#endif
#endif
#define FE_DFL_ENV (&_Fenv1)
// feraiseexcept is defined inline in this header so that it is compiled
// with the same /arch setting as is specified in the consuming application,
// rather than the /arch:IA32 setting with which the CRT sources are built.
// optimizer has to be turned off to avoid optimizing out since the function
// doesn't have side effects.
//
// feupdateenv is inline because it calls feraiseexcept.
#if _CRT_FUNCTIONS_REQUIRED
#if !defined(_BEGIN_PRAGMA_OPTIMIZE_DISABLE)
#define _BEGIN_PRAGMA_OPTIMIZE_DISABLE(flags, bug, reason) \
__pragma(optimize(flags, off))
#define _BEGIN_PRAGMA_OPTIMIZE_ENABLE(flags, bug, reason) \
__pragma(optimize(flags, on))
#define _END_PRAGMA_OPTIMIZE() \
__pragma(optimize("", on))
#endif
_BEGIN_PRAGMA_OPTIMIZE_DISABLE("", MSFT:4499495, "If optimizations are on, the floating-point exception might not get triggered (because the compiler optimizes it out), breaking the function.")
__inline int __CRTDECL feraiseexcept(_In_ int _Except)
{
static struct
{
int _Except_Val;
double _Num;
double _Denom;
} const _Table[] =
{ // Raise exception by evaluating num / denom:
{FE_INVALID, 0.0, 0.0 },
{FE_DIVBYZERO, 1.0, 0.0 },
{FE_OVERFLOW, 1e+300, 1e-300 },
{FE_UNDERFLOW, 1e-300, 1e+300 },
{FE_INEXACT, 2.0, 3.0 }
};
double _Ans = 0.0;
(void) _Ans; // Suppress set-but-not-used warnings. _Ans is not "used" in the traditional static-analysis sense, but it is needed to trigger a floating point exception below.
size_t _Index;
if ((_Except &= FE_ALL_EXCEPT) == 0)
{
return 0;
}
// Raise the exceptions not masked:
for (_Index = 0; _Index < sizeof(_Table) / sizeof(_Table[0]); ++_Index)
{
if ((_Except & _Table[_Index]._Except_Val) != 0)
{
_Ans = _Table[_Index]._Num / _Table[_Index]._Denom;
// x87 exceptions are raised immediately before execution of the
// next floating point instruction. If we're using /arch:IA32,
// force the exception to be raised immediately:
#if defined _M_IX86 && _M_IX86_FP == 0 && !defined _M_HYBRID_X86_ARM64
#ifdef _MSC_VER
__asm fwait;
#else
__asm__ __volatile__("fwait");
#endif
#endif
}
}
return 0;
}
_END_PRAGMA_OPTIMIZE()
__inline int __CRTDECL feupdateenv(_In_ const fenv_t *_Penv)
{
int _Except = fetestexcept(FE_ALL_EXCEPT);
if (fesetenv(_Penv) != 0 || feraiseexcept(_Except) != 0)
{
return 1;
}
return 0;
}
#endif // _CRT_FUNCTIONS_REQUIRED
#endif // !defined _M_CEE && !defined _CORECRT_BUILD
_CRT_END_C_HEADER
_UCRT_RESTORE_CLANG_WARNINGS
#pragma warning(pop) // _UCRT_DISABLED_WARNINGS
#endif // _FENV