1 // 2 // fenv.h 3 // 4 // Copyright (c) Microsoft Corporation. All rights reserved. 5 // 6 // Floating point environment library. 7 // 8 #pragma once 9 #ifndef _FENV // include guard for 3rd party interop 10 #define _FENV 11 12 #include <corecrt.h> 13 #include <float.h> 14 15 #pragma warning(push) 16 #pragma warning(disable: _UCRT_DISABLED_WARNINGS) 17 _UCRT_DISABLE_CLANG_WARNINGS 18 19 _CRT_BEGIN_C_HEADER 20 21 22 23 #define FE_TONEAREST _RC_NEAR 24 #define FE_UPWARD _RC_UP 25 #define FE_DOWNWARD _RC_DOWN 26 #define FE_TOWARDZERO _RC_CHOP 27 28 #define FE_ROUND_MASK _MCW_RC 29 30 _ACRTIMP int __cdecl fegetround(void); 31 _ACRTIMP int __cdecl fesetround(_In_ int _Round); 32 33 34 35 #if !defined _M_CEE 36 37 typedef unsigned long fexcept_t; 38 39 typedef struct fenv_t 40 { 41 unsigned long _Fe_ctl, _Fe_stat; 42 } fenv_t; 43 44 45 46 #define FE_INEXACT _SW_INEXACT // _EM_INEXACT 0x00000001 inexact (precision) 47 #define FE_UNDERFLOW _SW_UNDERFLOW // _EM_UNDERFLOW 0x00000002 underflow 48 #define FE_OVERFLOW _SW_OVERFLOW // _EM_OVERFLOW 0x00000004 overflow 49 #define FE_DIVBYZERO _SW_ZERODIVIDE // _EM_ZERODIVIDE 0x00000008 zero divide 50 #define FE_INVALID _SW_INVALID // _EM_INVALID 0x00000010 invalid 51 52 #define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) 53 54 _ACRTIMP int __cdecl fegetenv(_Out_ fenv_t* _Env); 55 _ACRTIMP int __cdecl fesetenv(_In_ fenv_t const* _Env); 56 _ACRTIMP int __cdecl feclearexcept(_In_ int _Flags); 57 _ACRTIMP _Success_(return == 0) int __cdecl feholdexcept(_Out_ fenv_t* _Env); 58 _ACRTIMP int __cdecl fetestexcept(_In_ int _Flags); 59 _ACRTIMP int __cdecl fegetexceptflag(_Out_ fexcept_t* _Except, _In_ int _TestFlags); 60 _ACRTIMP int __cdecl fesetexceptflag(_In_ fexcept_t const* _Except, _In_ int _SetFlags); 61 62 #if !defined __midl // MIDL does not support compound initializers 63 // In the original implementation (_Fenv0), the global variable was zero 64 // initialized, indicating no exceptions are masked. In the current 65 // implementation (_Fenv1), the global variable is initialized with all 66 // exceptions masked, which is the actual initial environment. 67 #if defined _M_IX86 68 __declspec(selectany) extern const fenv_t _Fenv1 = { 0x3f3f103f, 0 }; 69 #elif defined _M_X64 70 __declspec(selectany) extern const fenv_t _Fenv1 = { 0x3f00003f, 0 }; 71 #else 72 __declspec(selectany) extern const fenv_t _Fenv1 = { 0x0000003f, 0 }; 73 #endif 74 #endif 75 76 #define FE_DFL_ENV (&_Fenv1) 77 78 79 80 // feraiseexcept is defined inline in this header so that it is compiled 81 // with the same /arch setting as is specified in the consuming application, 82 // rather than the /arch:IA32 setting with which the CRT sources are built. 83 // optimizer has to be turned off to avoid optimizing out since the function 84 // doesn't have side effects. 85 // 86 // feupdateenv is inline because it calls feraiseexcept. 87 #if _CRT_FUNCTIONS_REQUIRED 88 #if !defined(_BEGIN_PRAGMA_OPTIMIZE_DISABLE) 89 #define _BEGIN_PRAGMA_OPTIMIZE_DISABLE(flags, bug, reason) \ 90 __pragma(optimize(flags, off)) 91 #define _BEGIN_PRAGMA_OPTIMIZE_ENABLE(flags, bug, reason) \ 92 __pragma(optimize(flags, on)) 93 #define _END_PRAGMA_OPTIMIZE() \ 94 __pragma(optimize("", on)) 95 #endif 96 _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)97 __inline int __CRTDECL feraiseexcept(_In_ int _Except) 98 { 99 static struct 100 { 101 int _Except_Val; 102 double _Num; 103 double _Denom; 104 } const _Table[] = 105 { // Raise exception by evaluating num / denom: 106 {FE_INVALID, 0.0, 0.0 }, 107 {FE_DIVBYZERO, 1.0, 0.0 }, 108 {FE_OVERFLOW, 1e+300, 1e-300 }, 109 {FE_UNDERFLOW, 1e-300, 1e+300 }, 110 {FE_INEXACT, 2.0, 3.0 } 111 }; 112 113 double _Ans = 0.0; 114 (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. 115 size_t _Index; 116 117 if ((_Except &= FE_ALL_EXCEPT) == 0) 118 { 119 return 0; 120 } 121 122 // Raise the exceptions not masked: 123 for (_Index = 0; _Index < sizeof(_Table) / sizeof(_Table[0]); ++_Index) 124 { 125 if ((_Except & _Table[_Index]._Except_Val) != 0) 126 { 127 _Ans = _Table[_Index]._Num / _Table[_Index]._Denom; 128 129 // x87 exceptions are raised immediately before execution of the 130 // next floating point instruction. If we're using /arch:IA32, 131 // force the exception to be raised immediately: 132 #if defined _M_IX86 && _M_IX86_FP == 0 && !defined _M_HYBRID_X86_ARM64 133 #ifdef _MSC_VER 134 __asm fwait; 135 #else 136 __asm__ __volatile__("fwait"); 137 #endif 138 #endif 139 } 140 } 141 142 return 0; 143 } _END_PRAGMA_OPTIMIZE()144 _END_PRAGMA_OPTIMIZE() 145 146 __inline int __CRTDECL feupdateenv(_In_ const fenv_t *_Penv) 147 { 148 int _Except = fetestexcept(FE_ALL_EXCEPT); 149 150 if (fesetenv(_Penv) != 0 || feraiseexcept(_Except) != 0) 151 { 152 return 1; 153 } 154 155 return 0; 156 } 157 #endif // _CRT_FUNCTIONS_REQUIRED 158 159 #endif // !defined _M_CEE && !defined _CORECRT_BUILD 160 161 _CRT_END_C_HEADER 162 _UCRT_RESTORE_CLANG_WARNINGS 163 #pragma warning(pop) // _UCRT_DISABLED_WARNINGS 164 #endif // _FENV 165