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 #ifdef __cplusplus 68 #define CPP_EXTERN extern 69 #else 70 #define CPP_EXTERN 71 #endif 72 #if defined _M_IX86 73 CPP_EXTERN __declspec(selectany) const fenv_t _Fenv1 = { 0x3f3f103f, 0 }; 74 #elif defined _M_X64 75 CPP_EXTERN __declspec(selectany) const fenv_t _Fenv1 = { 0x3f00003f, 0 }; 76 #else 77 CPP_EXTERN __declspec(selectany) const fenv_t _Fenv1 = { 0x0000003f, 0 }; 78 #endif 79 #endif 80 81 #define FE_DFL_ENV (&_Fenv1) 82 83 84 85 // feraiseexcept is defined inline in this header so that it is compiled 86 // with the same /arch setting as is specified in the consuming application, 87 // rather than the /arch:IA32 setting with which the CRT sources are built. 88 // optimizer has to be turned off to avoid optimizing out since the function 89 // doesn't have side effects. 90 // 91 // feupdateenv is inline because it calls feraiseexcept. 92 #if _CRT_FUNCTIONS_REQUIRED 93 #if !defined(_BEGIN_PRAGMA_OPTIMIZE_DISABLE) 94 #define _BEGIN_PRAGMA_OPTIMIZE_DISABLE(flags, bug, reason) \ 95 __pragma(optimize(flags, off)) 96 #define _BEGIN_PRAGMA_OPTIMIZE_ENABLE(flags, bug, reason) \ 97 __pragma(optimize(flags, on)) 98 #define _END_PRAGMA_OPTIMIZE() \ 99 __pragma(optimize("", on)) 100 #endif 101 _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.") 102 __inline int __CRTDECL feraiseexcept(_In_ int _Except) 103 { 104 static struct 105 { 106 int _Except_Val; 107 double _Num; 108 double _Denom; 109 } const _Table[] = 110 { // Raise exception by evaluating num / denom: 111 {FE_INVALID, 0.0, 0.0 }, 112 {FE_DIVBYZERO, 1.0, 0.0 }, 113 {FE_OVERFLOW, 1e+300, 1e-300 }, 114 {FE_UNDERFLOW, 1e-300, 1e+300 }, 115 {FE_INEXACT, 2.0, 3.0 } 116 }; 117 118 double _Ans = 0.0; 119 (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. 120 size_t _Index; 121 122 if ((_Except &= FE_ALL_EXCEPT) == 0) 123 { 124 return 0; 125 } 126 127 // Raise the exceptions not masked: 128 for (_Index = 0; _Index < sizeof(_Table) / sizeof(_Table[0]); ++_Index) 129 { 130 if ((_Except & _Table[_Index]._Except_Val) != 0) 131 { 132 _Ans = _Table[_Index]._Num / _Table[_Index]._Denom; 133 134 // x87 exceptions are raised immediately before execution of the 135 // next floating point instruction. If we're using /arch:IA32, 136 // force the exception to be raised immediately: 137 #if defined _M_IX86 && _M_IX86_FP == 0 && !defined _M_HYBRID_X86_ARM64 138 #ifdef _MSC_VER 139 __asm fwait; 140 #else 141 __asm__ __volatile__("fwait"); 142 #endif 143 #endif 144 } 145 } 146 147 return 0; 148 } 149 _END_PRAGMA_OPTIMIZE() 150 151 __inline int __CRTDECL feupdateenv(_In_ const fenv_t *_Penv) 152 { 153 int _Except = fetestexcept(FE_ALL_EXCEPT); 154 155 if (fesetenv(_Penv) != 0 || feraiseexcept(_Except) != 0) 156 { 157 return 1; 158 } 159 160 return 0; 161 } 162 #endif // _CRT_FUNCTIONS_REQUIRED 163 164 #endif // !defined _M_CEE && !defined _CORECRT_BUILD 165 166 _CRT_END_C_HEADER 167 _UCRT_RESTORE_CLANG_WARNINGS 168 #pragma warning(pop) // _UCRT_DISABLED_WARNINGS 169 #endif // _FENV 170