ReactOS  0.4.15-dev-5499-g1341c38
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 
18 unsigned 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 
36 void 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 
79 struct
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) },
105 };
106 
107 void Test_controlfp(void)
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)
124 void 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 
138 typedef enum _FP_OP
139 {
146 } FP_OP;
147 
148 struct
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)},
163  { OP_Overflow, 0xffffffff, _SW_OVERFLOW | _SW_INEXACT, 0, ON_IX86(0x28) ON_AMD64(0xffa8) ON_ARM(0) },
166  { OP_ZeroDivide, 0xffffffff, _SW_ZERODIVIDE, 0, ON_IX86(0x4) ON_AMD64(0xff84) 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)},
176 #endif
177 };
178 
179 void Test_exceptions(void)
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 
195  _controlfp(g_exception_Testcases[i].Fpcw, 0xffffffff);
196 #if defined(_M_IX86) || defined(_M_AMD64) // || defined(_M_ARM64) ?
198  _control87(g_exception_Testcases[i].Fpcw, 0xffffffff);
199 #endif
200 
201  _SEH2_TRY
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 
257 START_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 
280  Test_controlfp();
281 #if defined(_M_IX86) || defined(_M_AMD64)
282  Test_control87();
283 #endif
284  Test_exceptions();
285 }
__MINGW_NOTHROW _CRTIMP unsigned int __cdecl _statusfp(void)
Definition: _statusfp.c:11
_SEH2_TRY
Definition: create.c:4226
unsigned int Fpcw
Definition: fpcontrol.c:151
#define ON_ARM(x)
Definition: fpcontrol.c:76
#define _MM_MASK_INEXACT
Definition: xmmintrin.h:107
Definition: pdh_main.c:93
void set_native_fpcw(unsigned int value)
Definition: fpcontrol.c:36
#define _EM_DENORMAL
Definition: float.h:48
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
unsigned int Native
Definition: fpcontrol.c:84
unsigned int _mm_getcsr(void)
Definition: xmmintrin.h:535
__MINGW_NOTHROW void __cdecl _fpreset(void)
Definition: _fpreset.c:10
void Test_controlfp(void)
Definition: fpcontrol.c:107
void _mm_setcsr(unsigned int a)
Definition: xmmintrin.h:542
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG x1
Definition: winddi.h:3706
#define _DN_SAVE
Definition: float.h:62
unsigned int ExceptionCode
Definition: fpcontrol.c:153
#define DBL_MAX
Definition: gcc_float.h:108
__MINGW_NOTHROW _CRTIMP unsigned int __cdecl _clearfp(void)
Definition: _clearfp.c:11
unsigned int __cdecl _control87(unsigned int, unsigned int)
Definition: _control87.c:16
__asm__("\n\t \ NewInt3Handler:\n\t \ pushl $" STR(REASON_INT3) "\n\t \ // call debugger loop\n\t \ jmp NewInt31Handler\n\t \ ")
#define _MM_FLUSH_ZERO_ON
Definition: xmmintrin.h:116
#define _EM_INVALID
Definition: float.h:47
#define _MCW_EM
Definition: float.h:40
_SEH2_END
Definition: create.c:4400
#define STATUS_FLOAT_DIVIDE_BY_ZERO
Definition: ntstatus.h:378
#define STATUS_FLOAT_INEXACT_RESULT
Definition: ntstatus.h:379
#define ON_IX86(x)
Definition: fpcontrol.c:64
#define ok_hex(expression, result)
Definition: atltest.h:94
#define _EM_ZERODIVIDE
Definition: float.h:49
#define _MM_MASK_OVERFLOW
Definition: xmmintrin.h:105
#define STATUS_FLOAT_UNDERFLOW
Definition: ntstatus.h:383
unsigned short(__cdecl typeof(TIFFCurrentDirectory))(struct tiff *)
Definition: typeof.h:94
#define _IC_PROJECTIVE
Definition: float.h:54
void Test_exceptions(void)
Definition: fpcontrol.c:179
#define STATUS_FLOAT_OVERFLOW
Definition: ntstatus.h:381
START_TEST(fpcontrol)
Definition: fpcontrol.c:257
#define a
Definition: ke_i.h:78
#define e
Definition: ke_i.h:82
#define _MM_MASK_INVALID
Definition: xmmintrin.h:102
#define _SW_DENORMAL
Definition: float.h:90
#define _MM_MASK_UNDERFLOW
Definition: xmmintrin.h:106
enum _FP_OP FP_OP
#define _SW_INVALID
Definition: float.h:89
#define _SW_UNDERFLOW
Definition: float.h:86
_FP_OP
Definition: fpcontrol.c:138
#define _DN_FLUSH_OPERANDS_SAVE_RESULTS
Definition: float.h:64
#define b
Definition: ke_i.h:79
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:406
#define _DN_SAVE_OPERANDS_FLUSH_RESULTS
Definition: float.h:65
#define _RC_NEAR
Definition: float.h:58
#define _RC_UP
Definition: float.h:56
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
unsigned int Mask
Definition: fpcontrol.c:82
FP_OP Operation
Definition: fpcontrol.c:150
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define _countof(array)
Definition: sndvol32.h:68
#define _IC_AFFINE
Definition: float.h:53
unsigned int Result
Definition: fpcontrol.c:83
#define _MM_MASK_DENORM
Definition: xmmintrin.h:103
#define _MM_ROUND_DOWN
Definition: xmmintrin.h:111
unsigned int Value
Definition: fpcontrol.c:81
#define _EM_INEXACT
Definition: float.h:52
#define _RC_CHOP
Definition: float.h:55
unsigned int get_native_fpcw(void)
Definition: fpcontrol.c:18
#define _MM_ROUND_TOWARD_ZERO
Definition: xmmintrin.h:113
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
static float(__cdecl *square_half_float)(float x
#define ok(value,...)
Definition: atltest.h:57
#define _EM_OVERFLOW
Definition: float.h:50
unsigned int FpStatus
Definition: fpcontrol.c:152
#define _RC_DOWN
Definition: float.h:57
#define _MM_MASK_DIV_ZERO
Definition: xmmintrin.h:104
#define _EM_UNDERFLOW
Definition: float.h:51
#define DBL_MIN
Definition: gcc_float.h:125
struct @1556 g_exception_Testcases[]
#define ON_AMD64(x)
Definition: fpcontrol.c:70
struct @1555 g_controlfp_Testcases[]
#define _DN_FLUSH
Definition: float.h:63
#define _MM_ROUND_NEAREST
Definition: xmmintrin.h:110
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:40
#define _SW_INEXACT
Definition: float.h:85
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:165
#define _MM_ROUND_UP
Definition: xmmintrin.h:112
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
#define STATUS_FLOAT_INVALID_OPERATION
Definition: ntstatus.h:380
#define _SW_OVERFLOW
Definition: float.h:87
#define _SW_ZERODIVIDE
Definition: float.h:88
__MINGW_NOTHROW _CRTIMP unsigned int __cdecl _controlfp(_In_ unsigned int unNew, _In_ unsigned int unMask)
Definition: ps.c:97