xref: /reactos/sdk/include/ucrt/fenv.h (revision faedd8ff)
104e0dc4aSTimo Kreuzer //
204e0dc4aSTimo Kreuzer // fenv.h
304e0dc4aSTimo Kreuzer //
404e0dc4aSTimo Kreuzer //      Copyright (c) Microsoft Corporation. All rights reserved.
504e0dc4aSTimo Kreuzer //
604e0dc4aSTimo Kreuzer // Floating point environment library.
704e0dc4aSTimo Kreuzer //
804e0dc4aSTimo Kreuzer #pragma once
904e0dc4aSTimo Kreuzer #ifndef _FENV // include guard for 3rd party interop
1004e0dc4aSTimo Kreuzer #define _FENV
1104e0dc4aSTimo Kreuzer 
1204e0dc4aSTimo Kreuzer #include <corecrt.h>
1304e0dc4aSTimo Kreuzer #include <float.h>
1404e0dc4aSTimo Kreuzer 
1504e0dc4aSTimo Kreuzer #pragma warning(push)
1604e0dc4aSTimo Kreuzer #pragma warning(disable: _UCRT_DISABLED_WARNINGS)
1704e0dc4aSTimo Kreuzer _UCRT_DISABLE_CLANG_WARNINGS
1804e0dc4aSTimo Kreuzer 
1904e0dc4aSTimo Kreuzer _CRT_BEGIN_C_HEADER
2004e0dc4aSTimo Kreuzer 
2104e0dc4aSTimo Kreuzer 
2204e0dc4aSTimo Kreuzer 
2304e0dc4aSTimo Kreuzer #define FE_TONEAREST  _RC_NEAR
2404e0dc4aSTimo Kreuzer #define FE_UPWARD     _RC_UP
2504e0dc4aSTimo Kreuzer #define FE_DOWNWARD   _RC_DOWN
2604e0dc4aSTimo Kreuzer #define FE_TOWARDZERO _RC_CHOP
2704e0dc4aSTimo Kreuzer 
2804e0dc4aSTimo Kreuzer #define FE_ROUND_MASK _MCW_RC
2904e0dc4aSTimo Kreuzer 
3004e0dc4aSTimo Kreuzer _ACRTIMP int __cdecl fegetround(void);
3104e0dc4aSTimo Kreuzer _ACRTIMP int __cdecl fesetround(_In_ int _Round);
3204e0dc4aSTimo Kreuzer 
3304e0dc4aSTimo Kreuzer 
3404e0dc4aSTimo Kreuzer 
3504e0dc4aSTimo Kreuzer #if !defined _M_CEE
3604e0dc4aSTimo Kreuzer 
3704e0dc4aSTimo Kreuzer     typedef unsigned long fexcept_t;
3804e0dc4aSTimo Kreuzer 
3904e0dc4aSTimo Kreuzer     typedef struct fenv_t
4004e0dc4aSTimo Kreuzer     {
4104e0dc4aSTimo Kreuzer         unsigned long _Fe_ctl, _Fe_stat;
4204e0dc4aSTimo Kreuzer     } fenv_t;
4304e0dc4aSTimo Kreuzer 
4404e0dc4aSTimo Kreuzer 
4504e0dc4aSTimo Kreuzer 
4604e0dc4aSTimo Kreuzer     #define FE_INEXACT   _SW_INEXACT       // _EM_INEXACT     0x00000001 inexact (precision)
4704e0dc4aSTimo Kreuzer     #define FE_UNDERFLOW _SW_UNDERFLOW     // _EM_UNDERFLOW   0x00000002 underflow
4804e0dc4aSTimo Kreuzer     #define FE_OVERFLOW  _SW_OVERFLOW      // _EM_OVERFLOW    0x00000004 overflow
4904e0dc4aSTimo Kreuzer     #define FE_DIVBYZERO _SW_ZERODIVIDE    // _EM_ZERODIVIDE  0x00000008 zero divide
5004e0dc4aSTimo Kreuzer     #define FE_INVALID   _SW_INVALID       // _EM_INVALID     0x00000010 invalid
5104e0dc4aSTimo Kreuzer 
5204e0dc4aSTimo Kreuzer     #define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
5304e0dc4aSTimo Kreuzer 
5404e0dc4aSTimo Kreuzer     _ACRTIMP int __cdecl fegetenv(_Out_ fenv_t* _Env);
5504e0dc4aSTimo Kreuzer     _ACRTIMP int __cdecl fesetenv(_In_ fenv_t const* _Env);
5604e0dc4aSTimo Kreuzer     _ACRTIMP int __cdecl feclearexcept(_In_ int _Flags);
5704e0dc4aSTimo Kreuzer     _ACRTIMP _Success_(return == 0) int __cdecl feholdexcept(_Out_ fenv_t* _Env);
5804e0dc4aSTimo Kreuzer     _ACRTIMP int __cdecl fetestexcept(_In_ int _Flags);
5904e0dc4aSTimo Kreuzer     _ACRTIMP int __cdecl fegetexceptflag(_Out_ fexcept_t* _Except, _In_ int _TestFlags);
6004e0dc4aSTimo Kreuzer     _ACRTIMP int __cdecl fesetexceptflag(_In_ fexcept_t const* _Except, _In_ int _SetFlags);
6104e0dc4aSTimo Kreuzer 
6204e0dc4aSTimo Kreuzer     #if !defined __midl // MIDL does not support compound initializers
6304e0dc4aSTimo Kreuzer         // In the original implementation (_Fenv0), the global variable was zero
6404e0dc4aSTimo Kreuzer         // initialized, indicating no exceptions are masked.  In the current
6504e0dc4aSTimo Kreuzer         // implementation (_Fenv1), the global variable is initialized with all
6604e0dc4aSTimo Kreuzer         // exceptions masked, which is the actual initial environment.
6704e0dc4aSTimo Kreuzer         #if defined _M_IX86
6804e0dc4aSTimo Kreuzer             __declspec(selectany) extern const fenv_t _Fenv1 = { 0x3f3f103f, 0 };
6904e0dc4aSTimo Kreuzer         #elif defined _M_X64
7004e0dc4aSTimo Kreuzer             __declspec(selectany) extern const fenv_t _Fenv1 = { 0x3f00003f, 0 };
7104e0dc4aSTimo Kreuzer         #else
7204e0dc4aSTimo Kreuzer             __declspec(selectany) extern const fenv_t _Fenv1 = { 0x0000003f, 0 };
7304e0dc4aSTimo Kreuzer         #endif
7404e0dc4aSTimo Kreuzer     #endif
7504e0dc4aSTimo Kreuzer 
7604e0dc4aSTimo Kreuzer     #define FE_DFL_ENV (&_Fenv1)
7704e0dc4aSTimo Kreuzer 
7804e0dc4aSTimo Kreuzer 
7904e0dc4aSTimo Kreuzer 
8004e0dc4aSTimo Kreuzer     // feraiseexcept is defined inline in this header so that it is compiled
8104e0dc4aSTimo Kreuzer     // with the same /arch setting as is specified in the consuming application,
8204e0dc4aSTimo Kreuzer     // rather than the /arch:IA32 setting with which the CRT sources are built.
8304e0dc4aSTimo Kreuzer     // optimizer has to be turned off to avoid optimizing out since the function
8404e0dc4aSTimo Kreuzer     // doesn't have side effects.
8504e0dc4aSTimo Kreuzer     //
8604e0dc4aSTimo Kreuzer     // feupdateenv is inline because it calls feraiseexcept.
8704e0dc4aSTimo Kreuzer     #if _CRT_FUNCTIONS_REQUIRED
8804e0dc4aSTimo Kreuzer         #if !defined(_BEGIN_PRAGMA_OPTIMIZE_DISABLE)
8904e0dc4aSTimo Kreuzer             #define _BEGIN_PRAGMA_OPTIMIZE_DISABLE(flags, bug, reason) \
9004e0dc4aSTimo Kreuzer                 __pragma(optimize(flags, off))
9104e0dc4aSTimo Kreuzer             #define _BEGIN_PRAGMA_OPTIMIZE_ENABLE(flags, bug, reason) \
9204e0dc4aSTimo Kreuzer                 __pragma(optimize(flags, on))
9304e0dc4aSTimo Kreuzer             #define _END_PRAGMA_OPTIMIZE() \
9404e0dc4aSTimo Kreuzer                 __pragma(optimize("", on))
9504e0dc4aSTimo Kreuzer         #endif
9604e0dc4aSTimo Kreuzer         _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.")
feraiseexcept(_In_ int _Except)9704e0dc4aSTimo Kreuzer         __inline int __CRTDECL feraiseexcept(_In_ int _Except)
9804e0dc4aSTimo Kreuzer         {
9904e0dc4aSTimo Kreuzer             static struct
10004e0dc4aSTimo Kreuzer             {
10104e0dc4aSTimo Kreuzer                 int    _Except_Val;
10204e0dc4aSTimo Kreuzer                 double _Num;
10304e0dc4aSTimo Kreuzer                 double _Denom;
10404e0dc4aSTimo Kreuzer             } const _Table[] =
10504e0dc4aSTimo Kreuzer             {  // Raise exception by evaluating num / denom:
10604e0dc4aSTimo Kreuzer                 {FE_INVALID,   0.0,    0.0    },
10704e0dc4aSTimo Kreuzer                 {FE_DIVBYZERO, 1.0,    0.0    },
10804e0dc4aSTimo Kreuzer                 {FE_OVERFLOW,  1e+300, 1e-300 },
10904e0dc4aSTimo Kreuzer                 {FE_UNDERFLOW, 1e-300, 1e+300 },
11004e0dc4aSTimo Kreuzer                 {FE_INEXACT,   2.0,    3.0    }
11104e0dc4aSTimo Kreuzer             };
11204e0dc4aSTimo Kreuzer 
11304e0dc4aSTimo Kreuzer             double _Ans = 0.0;
11404e0dc4aSTimo Kreuzer             (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.
11504e0dc4aSTimo Kreuzer             size_t _Index;
11604e0dc4aSTimo Kreuzer 
11704e0dc4aSTimo Kreuzer             if ((_Except &= FE_ALL_EXCEPT) == 0)
11804e0dc4aSTimo Kreuzer             {
11904e0dc4aSTimo Kreuzer                 return 0;
12004e0dc4aSTimo Kreuzer             }
12104e0dc4aSTimo Kreuzer 
12204e0dc4aSTimo Kreuzer             // Raise the exceptions not masked:
12304e0dc4aSTimo Kreuzer             for (_Index = 0; _Index < sizeof(_Table) / sizeof(_Table[0]); ++_Index)
12404e0dc4aSTimo Kreuzer             {
12504e0dc4aSTimo Kreuzer                 if ((_Except & _Table[_Index]._Except_Val) != 0)
12604e0dc4aSTimo Kreuzer                 {
12704e0dc4aSTimo Kreuzer                     _Ans = _Table[_Index]._Num / _Table[_Index]._Denom;
12804e0dc4aSTimo Kreuzer 
12904e0dc4aSTimo Kreuzer                     // x87 exceptions are raised immediately before execution of the
13004e0dc4aSTimo Kreuzer                     // next floating point instruction.  If we're using /arch:IA32,
13104e0dc4aSTimo Kreuzer                     // force the exception to be raised immediately:
13204e0dc4aSTimo Kreuzer                     #if defined _M_IX86 && _M_IX86_FP == 0 && !defined _M_HYBRID_X86_ARM64
133*faedd8ffSTimo Kreuzer                     #ifdef _MSC_VER
13404e0dc4aSTimo Kreuzer                     __asm fwait;
135*faedd8ffSTimo Kreuzer                     #else
136*faedd8ffSTimo Kreuzer                     __asm__ __volatile__("fwait");
137*faedd8ffSTimo Kreuzer                     #endif
13804e0dc4aSTimo Kreuzer                     #endif
13904e0dc4aSTimo Kreuzer                 }
14004e0dc4aSTimo Kreuzer             }
14104e0dc4aSTimo Kreuzer 
14204e0dc4aSTimo Kreuzer             return 0;
14304e0dc4aSTimo Kreuzer         }
_END_PRAGMA_OPTIMIZE()14404e0dc4aSTimo Kreuzer         _END_PRAGMA_OPTIMIZE()
14504e0dc4aSTimo Kreuzer 
14604e0dc4aSTimo Kreuzer         __inline int __CRTDECL feupdateenv(_In_ const fenv_t *_Penv)
14704e0dc4aSTimo Kreuzer         {
14804e0dc4aSTimo Kreuzer             int _Except = fetestexcept(FE_ALL_EXCEPT);
14904e0dc4aSTimo Kreuzer 
15004e0dc4aSTimo Kreuzer             if (fesetenv(_Penv) != 0 || feraiseexcept(_Except) != 0)
15104e0dc4aSTimo Kreuzer             {
15204e0dc4aSTimo Kreuzer                 return 1;
15304e0dc4aSTimo Kreuzer             }
15404e0dc4aSTimo Kreuzer 
15504e0dc4aSTimo Kreuzer             return 0;
15604e0dc4aSTimo Kreuzer         }
15704e0dc4aSTimo Kreuzer     #endif // _CRT_FUNCTIONS_REQUIRED
15804e0dc4aSTimo Kreuzer 
15904e0dc4aSTimo Kreuzer #endif // !defined _M_CEE && !defined _CORECRT_BUILD
16004e0dc4aSTimo Kreuzer 
16104e0dc4aSTimo Kreuzer _CRT_END_C_HEADER
16204e0dc4aSTimo Kreuzer _UCRT_RESTORE_CLANG_WARNINGS
16304e0dc4aSTimo Kreuzer #pragma warning(pop) // _UCRT_DISABLED_WARNINGS
16404e0dc4aSTimo Kreuzer #endif // _FENV
165