ReactOS 0.4.15-dev-7924-g5949c20
fpcontrol.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS api tests
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Tests for fp control functions
5 * COPYRIGHT: Copyright 2022 Timo Kreuzer <timo.kreuzer@reactos.org>
6 */
7
8#include <ntstatus.h>
9#define WIN32_NO_STATUS
10#include <windows.h>
11
12#include <apitest.h>
13#include <xmmintrin.h>
14#include <float.h>
15#include <pseh/pseh2.h>
16
17
18unsigned int get_native_fpcw(void)
19{
20#ifdef _M_AMD64
21 return _mm_getcsr();
22#elif defined (_M_IX86)
23 unsigned short fpcw;
24#if defined(_MSC_VER)
25 __asm fstsw[fpcw];
26#else
27 __asm__ __volatile__("fstsw %0" : "=m" (fpcw) : );
28#endif
29 return fpcw;
30#else
31 #error "Unsupported architecture"
32 return 0;
33#endif
34}
35
36void set_native_fpcw(unsigned int value)
37{
38#ifdef _M_AMD64
40#elif defined (_M_IX86)
41 unsigned short fpcw = (unsigned short)value;
42#if defined(_MSC_VER)
43 __asm fldcw[fpcw];
44#else
45 __asm__ __volatile__("fldcw %0" : : "m" (fpcw));
46#endif
47#else
48#error "Unsupported architecture"
49#endif
50}
51
52/*
53 _clear87
54 _clearfp
55 _controlfp_s
56 _set_controlfp
57 _statusfp
58 __control87_2
59*/
60
61#ifdef _M_IX86
62#define ON_IX86(x) x
63#else
64#define ON_IX86(x)
65#endif
66
67#ifdef _M_AMD64
68#define ON_AMD64(x) x
69#else
70#define ON_AMD64(x)
71#endif
72
73#ifdef _M_ARM
74#define ON_ARM(x) x
75#else
76#define ON_ARM(x)
77#endif
78
79struct
80{
81 unsigned int Value;
82 unsigned int Mask;
83 unsigned int Result;
84 unsigned int Native;
86{
87 { 0xffffffff, 0xffffffff, ON_IX86(0x30e031f) ON_AMD64(0x308031f) ON_ARM(0), ON_IX86(0) ON_AMD64(0xff80) ON_ARM(0) },
88 { 0, 0xffffffff, 0x80000, ON_IX86(0) ON_AMD64(0x100) ON_ARM(0) },
89 { 0xffffffff, 0x14, 0x80014, ON_IX86(0) ON_AMD64(0x580) ON_ARM(0) },
106
108{
109 unsigned int i, native_fpcw, fpcw;
110
111 for (i = 0; i < _countof(g_controlfp_Testcases); i++)
112 {
114 ok(fpcw == g_controlfp_Testcases[i].Result, "[%u] _controlfp failed: expected 0x%x, got 0x%x\n", i, g_controlfp_Testcases[i].Result, fpcw);
115 native_fpcw = get_native_fpcw();
116 ok(native_fpcw == g_controlfp_Testcases[i].Native, "[%u] wrong native_fpcw: expected 0x%x, got 0x%x\n", i, g_controlfp_Testcases[i].Native, native_fpcw);
117 }
118
119 /* Restore sane state */
120 _fpreset();
121}
122
123#if defined(_M_IX86) || defined(_M_AMD64)
124void Test_control87(void)
125{
126 unsigned int native_fpcw, fpcw;
127
128 fpcw = _control87(0, 0xffffffff);
129 ok(fpcw == 0, "_control87 failed: expected 0x%x, got 0x%x\n", 0, fpcw);
130 native_fpcw = get_native_fpcw();
131 ok_hex(native_fpcw, ON_IX86(0) ON_AMD64(0));
132
133 /* Restore sane state */
134 _fpreset();
135}
136#endif
137
138typedef enum _FP_OP
139{
147
148struct
149{
151 unsigned int Fpcw;
152 unsigned int FpStatus;
153 unsigned int ExceptionCode;
154 unsigned int Native;
156{
157 { OP_Inexact, 0xffffffff, _SW_UNDERFLOW | _SW_INEXACT ON_IX86(| _SW_DENORMAL), 0, ON_IX86(0x32) ON_AMD64(0xffb0) ON_ARM(0)},
160 { OP_Underflow, 0xffffffff, _SW_UNDERFLOW | _SW_INEXACT, 0, ON_IX86(0x30) ON_AMD64(0xffb0) ON_ARM(0)},
161 { OP_Underflow, ~_EM_UNDERFLOW, _SW_UNDERFLOW | _SW_INEXACT, STATUS_FLOAT_UNDERFLOW, ON_IX86(0x3800) ON_AMD64(0xf7b0) ON_ARM(0) },
163 { OP_Overflow, 0xffffffff, _SW_OVERFLOW | _SW_INEXACT, 0, ON_IX86(0x28) ON_AMD64(0xffa8) ON_ARM(0) },
164 { OP_Overflow, ~_EM_OVERFLOW, _SW_OVERFLOW | _SW_INEXACT, STATUS_FLOAT_OVERFLOW, ON_IX86(0x3800) ON_AMD64(0xfba8) ON_ARM(0) },
166 { OP_ZeroDivide, 0xffffffff, _SW_ZERODIVIDE, 0, ON_IX86(0x4) ON_AMD64(0xff84) ON_ARM(0) },
167 { OP_ZeroDivide, ~_EM_ZERODIVIDE, _SW_ZERODIVIDE, STATUS_FLOAT_DIVIDE_BY_ZERO, ON_IX86(0x3000) ON_AMD64(0xfd84) ON_ARM(0) },
169 { OP_Invalid, 0xffffffff, _SW_INVALID, 0, ON_IX86(0x1) ON_AMD64(0xff81) ON_ARM(0) },
172#if defined(_M_IX86) || defined(_M_AMD64) // || defined(_M_ARM64) ?
173 { OP_Denormal, 0xffffffff, _SW_DENORMAL | _SW_INEXACT ON_AMD64(| _SW_UNDERFLOW), 0, ON_IX86(0x22) ON_AMD64(0xffb2) ON_ARM(0)},
174 { OP_Denormal, ~_EM_DENORMAL, _SW_DENORMAL, STATUS_FLOAT_INVALID_OPERATION, ON_IX86(0x3800) ON_AMD64(0xfe82) ON_ARM(0) },
176#endif
178
180{
181 volatile double a, b;
182 unsigned long long ull;
183 volatile long status = 0;
184
185 unsigned int i, exp_fpstatus, native_fpcw, statusfp;
186
187 for (i = 0; i < _countof(g_exception_Testcases); i++)
188 {
189 /* Start clean */
190 status = 0;
191 _fpreset();
192 _clearfp();
193 ok_hex(_statusfp(), 0);
194
196#if defined(_M_IX86) || defined(_M_AMD64) // || defined(_M_ARM64) ?
199#endif
200
202 {
204 {
205 case OP_Inexact:
206 a = 1e-40;
207 b = (float)(a + 1e-40);
208 break;
209 case OP_Underflow:
210 a = DBL_MIN;
211 b = a / 3.0e16;
212 break;
213 case OP_Overflow:
214 a = DBL_MAX;
215 b = a * 3.0;
216 break;
217 case OP_ZeroDivide:
218 a = 0.0;
219 b = 1.0 / a;
220 break;
221 case OP_Invalid:
222 ull = 0x7FF0000000000001ull;
223 a = *(double*)&ull;
224 b = a * 2;
225 break;
226 case OP_Denormal:
227 a = DBL_MIN;
228 b = a - 4.9406564584124654e-324;
229 break;
230 default:
231 (void)b;
232 }
233 native_fpcw = get_native_fpcw();
234 statusfp = _clearfp();
235 }
237 {
238#ifdef _M_IX86
239 /* On x86 we need to clear before doing any other fp operations, otherwise it will throw again */
240 statusfp = _clearfp();
241 native_fpcw = get_native_fpcw();
242#else
243 native_fpcw = get_native_fpcw();
244 statusfp = _clearfp();
245#endif
247 }
248 _SEH2_END;
249
250 exp_fpstatus = g_exception_Testcases[i].FpStatus;
251 ok(statusfp == exp_fpstatus, "[%u] Wrong value for _statusfp(). Expected 0x%lx, got 0x%lx\n", i, exp_fpstatus, statusfp);
252 ok(status == g_exception_Testcases[i].ExceptionCode, "[%u] Wrong value for status. Expected 0x%lx, got 0x%lx\n", i, g_exception_Testcases[i].ExceptionCode, status);
253 ok(native_fpcw == g_exception_Testcases[i].Native, "[%u] wrong native_fpcw: expected 0x%x, got 0x%x\n", i, g_exception_Testcases[i].Native, native_fpcw);
254 }
255}
256
257START_TEST(fpcontrol)
258{
259 unsigned int native_fpcw, fpcw, fpstatus;
260
261 /* Test native start fpcw */
262 native_fpcw = get_native_fpcw();
263 ok_hex(native_fpcw, ON_IX86(0) ON_AMD64(0x1f80) ON_ARM(0) );
264
265 /* Test start fpcw */
266 fpcw = _controlfp(0, 0);
267 ok_hex(fpcw, ON_IX86(0x9001f) ON_AMD64(0x8001f) ON_ARM(0));
268
269 /* Test start status */
270 fpstatus = _statusfp();
271 ok_hex(fpstatus, 0);
272
273 /* Test _fpreset */
274 fpcw = _controlfp(0, 0xffffffff);
275 ok_hex(fpcw, 0x80000);
276 _fpreset();
277 fpcw = _controlfp(0, 0);
278 ok_hex(fpcw, ON_IX86(0x9001f) ON_AMD64(0x8001f) ON_ARM(0));
279
281#if defined(_M_IX86) || defined(_M_AMD64)
282 Test_control87();
283#endif
285}
#define ok_hex(expression, result)
Definition: atltest.h:94
#define ok(value,...)
Definition: atltest.h:57
#define START_TEST(x)
Definition: atltest.h:75
unsigned short(__cdecl typeof(TIFFCurrentDirectory))(struct tiff *)
Definition: typeof.h:94
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
void Test_controlfp(void)
Definition: fpcontrol.c:107
#define ON_IX86(x)
Definition: fpcontrol.c:64
unsigned int Result
Definition: fpcontrol.c:83
FP_OP Operation
Definition: fpcontrol.c:150
unsigned int get_native_fpcw(void)
Definition: fpcontrol.c:18
void Test_exceptions(void)
Definition: fpcontrol.c:179
void set_native_fpcw(unsigned int value)
Definition: fpcontrol.c:36
enum _FP_OP FP_OP
struct @1591 g_controlfp_Testcases[]
unsigned int Mask
Definition: fpcontrol.c:82
_FP_OP
Definition: fpcontrol.c:139
@ OP_Overflow
Definition: fpcontrol.c:142
@ OP_ZeroDivide
Definition: fpcontrol.c:143
@ OP_Underflow
Definition: fpcontrol.c:141
@ OP_Inexact
Definition: fpcontrol.c:140
@ OP_Invalid
Definition: fpcontrol.c:144
@ OP_Denormal
Definition: fpcontrol.c:145
unsigned int FpStatus
Definition: fpcontrol.c:152
#define ON_ARM(x)
Definition: fpcontrol.c:76
unsigned int Fpcw
Definition: fpcontrol.c:151
unsigned int Value
Definition: fpcontrol.c:81
#define ON_AMD64(x)
Definition: fpcontrol.c:70
struct @1592 g_exception_Testcases[]
unsigned int ExceptionCode
Definition: fpcontrol.c:153
unsigned int Native
Definition: fpcontrol.c:84
#define DBL_MIN
Definition: gcc_float.h:125
#define DBL_MAX
Definition: gcc_float.h:108
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define _IC_AFFINE
Definition: float.h:53
#define _DN_SAVE_OPERANDS_FLUSH_RESULTS
Definition: float.h:65
#define _RC_UP
Definition: float.h:56
#define _SW_INEXACT
Definition: float.h:85
#define _SW_OVERFLOW
Definition: float.h:87
#define _EM_UNDERFLOW
Definition: float.h:51
#define _SW_DENORMAL
Definition: float.h:90
#define _EM_ZERODIVIDE
Definition: float.h:49
#define _EM_INEXACT
Definition: float.h:52
#define _EM_OVERFLOW
Definition: float.h:50
#define _DN_SAVE
Definition: float.h:62
__MINGW_NOTHROW _CRTIMP unsigned int __cdecl _controlfp(_In_ unsigned int unNew, _In_ unsigned int unMask)
__MINGW_NOTHROW void __cdecl _fpreset(void)
Definition: _fpreset.c:10
#define _EM_INVALID
Definition: float.h:47
#define _SW_ZERODIVIDE
Definition: float.h:88
#define _DN_FLUSH
Definition: float.h:63
__MINGW_NOTHROW _CRTIMP unsigned int __cdecl _clearfp(void)
Definition: _clearfp.c:11
#define _IC_PROJECTIVE
Definition: float.h:54
#define _DN_FLUSH_OPERANDS_SAVE_RESULTS
Definition: float.h:64
#define _EM_DENORMAL
Definition: float.h:48
__MINGW_NOTHROW _CRTIMP unsigned int __cdecl _statusfp(void)
Definition: _statusfp.c:11
#define _RC_NEAR
Definition: float.h:58
#define _SW_UNDERFLOW
Definition: float.h:86
#define _RC_DOWN
Definition: float.h:57
#define _RC_CHOP
Definition: float.h:55
#define _SW_INVALID
Definition: float.h:89
#define e
Definition: ke_i.h:82
#define a
Definition: ke_i.h:78
#define b
Definition: ke_i.h:79
unsigned int __cdecl _control87(unsigned int, unsigned int)
Definition: _control87.c:16
static float(__cdecl *square_half_float)(float x
#define STATUS_FLOAT_UNDERFLOW
Definition: ntstatus.h:383
#define STATUS_FLOAT_OVERFLOW
Definition: ntstatus.h:381
#define STATUS_FLOAT_DIVIDE_BY_ZERO
Definition: ntstatus.h:378
#define STATUS_FLOAT_INVALID_OPERATION
Definition: ntstatus.h:380
#define STATUS_FLOAT_INEXACT_RESULT
Definition: ntstatus.h:379
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
__asm__(".p2align 4, 0x90\n" ".seh_proc __seh2_global_filter_func\n" "__seh2_global_filter_func:\n" "\tpush %rbp\n" "\t.seh_pushreg %rbp\n" "\tsub $32, %rsp\n" "\t.seh_stackalloc 32\n" "\t.seh_endprologue\n" "\tmov %rdx, %rbp\n" "\tjmp *%rax\n" "__seh2_global_filter_func_exit:\n" "\t.p2align 4\n" "\tadd $32, %rsp\n" "\tpop %rbp\n" "\tret\n" "\t.seh_endproc")
#define _countof(array)
Definition: sndvol32.h:68
Definition: ps.c:97
Definition: pdh_main.c:94
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
#define _MM_MASK_INVALID
Definition: xmmintrin.h:102
#define _MM_MASK_DENORM
Definition: xmmintrin.h:103
void _mm_setcsr(unsigned int a)
Definition: xmmintrin.h:542
#define _MM_ROUND_NEAREST
Definition: xmmintrin.h:110
#define _MM_ROUND_DOWN
Definition: xmmintrin.h:111
#define _MM_MASK_DIV_ZERO
Definition: xmmintrin.h:104
#define _MM_ROUND_UP
Definition: xmmintrin.h:112
#define _MM_ROUND_TOWARD_ZERO
Definition: xmmintrin.h:113
#define _MM_MASK_OVERFLOW
Definition: xmmintrin.h:105
#define _MM_MASK_INEXACT
Definition: xmmintrin.h:107
unsigned int _mm_getcsr(void)
Definition: xmmintrin.h:535
#define _MM_MASK_UNDERFLOW
Definition: xmmintrin.h:106
#define _MM_FLUSH_ZERO_ON
Definition: xmmintrin.h:116