xref: /reactos/sdk/include/ucrt/fenv.h (revision de3a6706)
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