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