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