VirtualBox

source: vbox/trunk/src/VBox/VMM/testcase/tstIEMAImpl.cpp@ 94409

Last change on this file since 94409 was 94409, checked in by vboxsync, 3 years ago

tstIEMAImpl: Split the data out and put it in separate files to avoid turning it into a compiler memory usage test. bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 155.8 KB
Line 
1/* $Id: tstIEMAImpl.cpp 94409 2022-03-31 10:42:18Z vboxsync $ */
2/** @file
3 * IEM Assembly Instruction Helper Testcase.
4 */
5
6/*
7 * Copyright (C) 2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include "../include/IEMInternal.h"
23
24#include <iprt/errcore.h>
25#include <VBox/log.h>
26#include <iprt/assert.h>
27#include <iprt/ctype.h>
28#include <iprt/getopt.h>
29#include <iprt/initterm.h>
30#include <iprt/message.h>
31#include <iprt/mp.h>
32#include <iprt/rand.h>
33#include <iprt/stream.h>
34#include <iprt/string.h>
35#include <iprt/test.h>
36
37#include "tstIEMAImpl.h"
38
39
40/*********************************************************************************************************************************
41* Defined Constants And Macros *
42*********************************************************************************************************************************/
43#define ENTRY(a_Name) ENTRY_EX(a_Name, 0)
44#define ENTRY_EX(a_Name, a_uExtra) \
45 { RT_XSTR(a_Name), iemAImpl_ ## a_Name, NULL, \
46 g_aTests_ ## a_Name, &g_cTests_ ## a_Name, \
47 a_uExtra, IEMTARGETCPU_EFL_BEHAVIOR_NATIVE /* means same for all here */ }
48
49#define ENTRY_INTEL(a_Name, a_fEflUndef) ENTRY_INTEL_EX(a_Name, a_fEflUndef, 0)
50#define ENTRY_INTEL_EX(a_Name, a_fEflUndef, a_uExtra) \
51 { RT_XSTR(a_Name) "_intel", iemAImpl_ ## a_Name ## _intel, iemAImpl_ ## a_Name, \
52 g_aTests_ ## a_Name ## _intel, &g_cTests_ ## a_Name ## _intel, \
53 a_uExtra, IEMTARGETCPU_EFL_BEHAVIOR_INTEL }
54
55#define ENTRY_AMD(a_Name, a_fEflUndef) ENTRY_AMD_EX(a_Name, a_fEflUndef, 0)
56#define ENTRY_AMD_EX(a_Name, a_fEflUndef, a_uExtra) \
57 { RT_XSTR(a_Name) "_amd", iemAImpl_ ## a_Name ## _amd, iemAImpl_ ## a_Name, \
58 g_aTests_ ## a_Name ## _amd, &g_cTests_ ## a_Name ## _amd, \
59 a_uExtra, IEMTARGETCPU_EFL_BEHAVIOR_AMD }
60
61#define TYPEDEF_SUBTEST_TYPE(a_TypeName, a_TestType, a_FunctionPtrType) \
62 typedef struct a_TypeName \
63 { \
64 const char *pszName; \
65 a_FunctionPtrType pfn; \
66 a_FunctionPtrType pfnNative; \
67 a_TestType const *paTests; \
68 uint32_t const *pcTests; \
69 uint32_t uExtra; \
70 uint8_t idxCpuEflFlavour; \
71 } a_TypeName
72
73
74/*********************************************************************************************************************************
75* Global Variables *
76*********************************************************************************************************************************/
77static RTTEST g_hTest;
78static uint8_t g_idxCpuEflFlavour = IEMTARGETCPU_EFL_BEHAVIOR_INTEL;
79#ifdef TSTIEMAIMPL_WITH_GENERATOR
80static uint32_t g_cZeroDstTests = 2;
81static uint32_t g_cZeroSrcTests = 4;
82#endif
83static uint8_t *g_pu8, *g_pu8Two;
84static uint16_t *g_pu16, *g_pu16Two;
85static uint32_t *g_pu32, *g_pu32Two, *g_pfEfl;
86static uint64_t *g_pu64, *g_pu64Two;
87static RTUINT128U *g_pu128, *g_pu128Two;
88
89static char g_aszBuf[16][256];
90static unsigned g_idxBuf = 0;
91
92
93/*********************************************************************************************************************************
94* Internal Functions *
95*********************************************************************************************************************************/
96static const char *FormatR80(PCRTFLOAT80U pr80);
97static const char *FormatR64(PCRTFLOAT64U pr64);
98static const char *FormatR32(PCRTFLOAT32U pr32);
99
100
101/*
102 * Random helpers.
103 */
104
105static uint32_t RandEFlags(void)
106{
107 uint32_t fEfl = RTRandU32();
108 return (fEfl & X86_EFL_LIVE_MASK) | X86_EFL_RA1_MASK;
109}
110
111#ifdef TSTIEMAIMPL_WITH_GENERATOR
112
113static uint8_t RandU8(void)
114{
115 return RTRandU32Ex(0, 0xff);
116}
117
118
119static uint16_t RandU16(void)
120{
121 return RTRandU32Ex(0, 0xffff);
122}
123
124
125static uint32_t RandU32(void)
126{
127 return RTRandU32();
128}
129
130#endif
131
132static uint64_t RandU64(void)
133{
134 return RTRandU64();
135}
136
137
138static RTUINT128U RandU128(void)
139{
140 RTUINT128U Ret;
141 Ret.s.Hi = RTRandU64();
142 Ret.s.Lo = RTRandU64();
143 return Ret;
144}
145
146#ifdef TSTIEMAIMPL_WITH_GENERATOR
147
148static uint8_t RandU8Dst(uint32_t iTest)
149{
150 if (iTest < g_cZeroDstTests)
151 return 0;
152 return RandU8();
153}
154
155
156static uint8_t RandU8Src(uint32_t iTest)
157{
158 if (iTest < g_cZeroSrcTests)
159 return 0;
160 return RandU8();
161}
162
163
164static uint16_t RandU16Dst(uint32_t iTest)
165{
166 if (iTest < g_cZeroDstTests)
167 return 0;
168 return RandU16();
169}
170
171
172static uint16_t RandU16Src(uint32_t iTest)
173{
174 if (iTest < g_cZeroSrcTests)
175 return 0;
176 return RandU16();
177}
178
179
180static uint32_t RandU32Dst(uint32_t iTest)
181{
182 if (iTest < g_cZeroDstTests)
183 return 0;
184 return RandU32();
185}
186
187
188static uint32_t RandU32Src(uint32_t iTest)
189{
190 if (iTest < g_cZeroSrcTests)
191 return 0;
192 return RandU32();
193}
194
195
196static uint64_t RandU64Dst(uint32_t iTest)
197{
198 if (iTest < g_cZeroDstTests)
199 return 0;
200 return RandU64();
201}
202
203
204static uint64_t RandU64Src(uint32_t iTest)
205{
206 if (iTest < g_cZeroSrcTests)
207 return 0;
208 return RandU64();
209}
210
211
212static uint16_t RandFcw(void)
213{
214 return RandU16() & ~X86_FCW_ZERO_MASK;
215}
216
217
218static uint16_t RandFsw(void)
219{
220 AssertCompile((X86_FSW_C_MASK | X86_FSW_XCPT_ES_MASK | X86_FSW_TOP_MASK | X86_FSW_B) == 0xffff);
221 return RandU16();
222}
223
224
225static void SafeR80FractionShift(PRTFLOAT80U pr80, uint8_t cShift)
226{
227 if (pr80->sj64.uFraction >= RT_BIT_64(cShift))
228 pr80->sj64.uFraction >>= cShift;
229 else
230 pr80->sj64.uFraction = (cShift % 19) + 1;
231}
232
233
234static RTFLOAT80U RandR80Ex(unsigned cTarget = 80, bool fIntTarget = false)
235{
236 Assert(cTarget == (!fIntTarget ? 80 : 16) || cTarget == 64 || cTarget == 32 || (cTarget == 59 && fIntTarget));
237
238 RTFLOAT80U r80;
239 r80.au64[0] = RandU64();
240 r80.au16[4] = RandU16();
241
242 /*
243 * Make it more likely that we get a good selection of special values.
244 */
245 uint8_t bType = RandU8() & 0x1f;
246 if (bType == 0 || bType == 1 || bType == 2 || bType == 3)
247 {
248 /* Zero (0), Pseudo-Infinity (1), Infinity (2), Indefinite (3). We only keep fSign here. */
249 r80.sj64.uExponent = bType == 0 ? 0 : 0x7fff;
250 r80.sj64.uFraction = bType <= 2 ? 0 : RT_BIT_64(62);
251 r80.sj64.fInteger = bType >= 2 ? 1 : 0;
252 AssertMsg(bType != 0 || RTFLOAT80U_IS_ZERO(&r80), ("%s\n", FormatR80(&r80)));
253 AssertMsg(bType != 1 || RTFLOAT80U_IS_PSEUDO_INF(&r80), ("%s\n", FormatR80(&r80)));
254 AssertMsg(bType != 2 || RTFLOAT80U_IS_INF(&r80), ("%s\n", FormatR80(&r80)));
255 AssertMsg(bType != 3 || RTFLOAT80U_IS_INDEFINITE(&r80), ("%s\n", FormatR80(&r80)));
256 }
257 else if (bType == 4 || bType == 5 || bType == 6 || bType == 7)
258 {
259 /* Denormals (4,5) and Pseudo denormals (6,7) */
260 if (bType & 1)
261 SafeR80FractionShift(&r80, r80.sj64.uExponent % 62);
262 else if (r80.sj64.uFraction == 0 && bType < 6)
263 r80.sj64.uFraction = RTRandU64Ex(1, RT_BIT_64(RTFLOAT80U_FRACTION_BITS) - 1);
264 r80.sj64.uExponent = 0;
265 r80.sj64.fInteger = bType >= 6;
266 AssertMsg(bType >= 6 || RTFLOAT80U_IS_DENORMAL(&r80), ("%s bType=%#x\n", FormatR80(&r80), bType));
267 AssertMsg(bType < 6 || RTFLOAT80U_IS_PSEUDO_DENORMAL(&r80), ("%s bType=%#x\n", FormatR80(&r80), bType));
268 }
269 else if (bType == 8 || bType == 9)
270 {
271 /* Pseudo NaN. */
272 if (bType & 1)
273 SafeR80FractionShift(&r80, r80.sj64.uExponent % 62);
274 else if (r80.sj64.uFraction == 0 && !r80.sj64.fInteger)
275 r80.sj64.uFraction = RTRandU64Ex(1, RT_BIT_64(RTFLOAT80U_FRACTION_BITS) - 1);
276 r80.sj64.uExponent = 0x7fff;
277 if (r80.sj64.fInteger)
278 r80.sj64.uFraction |= RT_BIT_64(62);
279 else
280 r80.sj64.uFraction &= ~RT_BIT_64(62);
281 r80.sj64.fInteger = 0;
282 AssertMsg(RTFLOAT80U_IS_PSEUDO_NAN(&r80), ("%s bType=%#x\n", FormatR80(&r80), bType));
283 AssertMsg(RTFLOAT80U_IS_NAN(&r80), ("%s bType=%#x\n", FormatR80(&r80), bType));
284 }
285 else if (bType == 10 || bType == 11)
286 {
287 /* Quiet and signalling NaNs (using fInteger to pick which). */
288 if (bType & 1)
289 SafeR80FractionShift(&r80, r80.sj64.uExponent % 62);
290 else if (r80.sj64.uFraction == 0)
291 r80.sj64.uFraction = RTRandU64Ex(1, RT_BIT_64(RTFLOAT80U_FRACTION_BITS) - 1);
292 r80.sj64.uExponent = 0x7fff;
293 if (r80.sj64.fInteger)
294 r80.sj64.uFraction |= RT_BIT_64(62);
295 else
296 r80.sj64.uFraction &= ~RT_BIT_64(62);
297 r80.sj64.fInteger = 1;
298 AssertMsg(RTFLOAT80U_IS_SIGNALLING_NAN(&r80) || RTFLOAT80U_IS_QUIET_NAN(&r80), ("%s\n", FormatR80(&r80)));
299 AssertMsg(RTFLOAT80U_IS_NAN(&r80), ("%s\n", FormatR80(&r80)));
300 }
301 else if (bType == 12 || bType == 13)
302 {
303 /* Unnormals */
304 if (bType & 1)
305 SafeR80FractionShift(&r80, RandU8() % 62);
306 r80.sj64.fInteger = 0;
307 if (r80.sj64.uExponent == RTFLOAT80U_EXP_MAX || r80.sj64.uExponent == 0)
308 r80.sj64.uExponent = (uint16_t)RTRandU32Ex(1, RTFLOAT80U_EXP_MAX - 1);
309 AssertMsg(RTFLOAT80U_IS_UNNORMAL(&r80), ("%s\n", FormatR80(&r80)));
310 }
311 else if (bType < 24)
312 {
313 /* Make sure we have lots of normalized values. */
314 if (!fIntTarget)
315 {
316 const unsigned uMinExp = cTarget == 64 ? RTFLOAT80U_EXP_BIAS - RTFLOAT64U_EXP_BIAS
317 : cTarget == 32 ? RTFLOAT80U_EXP_BIAS - RTFLOAT32U_EXP_BIAS : 0;
318 const unsigned uMaxExp = cTarget == 64 ? uMinExp + RTFLOAT64U_EXP_MAX
319 : cTarget == 32 ? uMinExp + RTFLOAT32U_EXP_MAX : RTFLOAT80U_EXP_MAX;
320 r80.sj64.fInteger = 1;
321 if (r80.sj64.uExponent <= uMinExp)
322 r80.sj64.uExponent = uMinExp + 1;
323 else if (r80.sj64.uExponent >= uMaxExp)
324 r80.sj64.uExponent = uMaxExp - 1;
325
326 if (bType == 14)
327 { /* All 1s is useful to testing rounding. Also try trigger special
328 behaviour by sometimes rounding out of range, while we're at it. */
329 r80.sj64.uFraction = RT_BIT_64(63) - 1;
330 uint8_t bExp = RandU8();
331 if ((bExp & 3) == 0)
332 r80.sj64.uExponent = uMaxExp - 1;
333 else if ((bExp & 3) == 1)
334 r80.sj64.uExponent = uMinExp + 1;
335 else if ((bExp & 3) == 2)
336 r80.sj64.uExponent = uMinExp - (bExp & 15); /* (small numbers are mapped to subnormal values) */
337 }
338 }
339 else
340 {
341 /* integer target: */
342 const unsigned uMinExp = RTFLOAT80U_EXP_BIAS;
343 const unsigned uMaxExp = RTFLOAT80U_EXP_BIAS + cTarget - 2;
344 r80.sj64.fInteger = 1;
345 if (r80.sj64.uExponent < uMinExp)
346 r80.sj64.uExponent = uMinExp;
347 else if (r80.sj64.uExponent > uMaxExp)
348 r80.sj64.uExponent = uMaxExp;
349
350 if (bType == 14)
351 { /* All 1s is useful to testing rounding. Also try trigger special
352 behaviour by sometimes rounding out of range, while we're at it. */
353 r80.sj64.uFraction = RT_BIT_64(63) - 1;
354 uint8_t bExp = RandU8();
355 if ((bExp & 3) == 0)
356 r80.sj64.uExponent = uMaxExp;
357 else if ((bExp & 3) == 1)
358 r80.sj64.uFraction &= ~(RT_BIT_64(cTarget - 1 - r80.sj64.uExponent) - 1); /* no rounding */
359 }
360 }
361
362 AssertMsg(RTFLOAT80U_IS_NORMAL(&r80), ("%s\n", FormatR80(&r80)));
363 }
364 return r80;
365}
366
367
368static RTFLOAT80U RandR80Src(uint32_t iTest)
369{
370 RT_NOREF(iTest);
371 return RandR80Ex();
372}
373
374
375static void SafeR64FractionShift(PRTFLOAT64U pr64, uint8_t cShift)
376{
377 if (pr64->s64.uFraction >= RT_BIT_64(cShift))
378 pr64->s64.uFraction >>= cShift;
379 else
380 pr64->s64.uFraction = (cShift % 19) + 1;
381}
382
383
384static RTFLOAT64U RandR64Src(uint32_t iTest)
385{
386 RT_NOREF(iTest);
387
388 RTFLOAT64U r64;
389 r64.u = RandU64();
390
391 /*
392 * Make it more likely that we get a good selection of special values.
393 * On average 6 out of 16 calls should return a special value.
394 */
395 uint8_t bType = RandU8() & 0xf;
396 if (bType == 0 || bType == 1)
397 {
398 /* 0 or Infinity. We only keep fSign here. */
399 r64.s.uExponent = bType == 0 ? 0 : 0x7ff;
400 r64.s.uFractionHigh = 0;
401 r64.s.uFractionLow = 0;
402 AssertMsg(bType != 0 || RTFLOAT64U_IS_ZERO(&r64), ("%s bType=%#x\n", FormatR64(&r64), bType));
403 AssertMsg(bType != 1 || RTFLOAT64U_IS_INF(&r64), ("%s bType=%#x\n", FormatR64(&r64), bType));
404 }
405 else if (bType == 2 || bType == 3)
406 {
407 /* Subnormals */
408 if (bType == 3)
409 SafeR64FractionShift(&r64, r64.s64.uExponent % 51);
410 else if (r64.s64.uFraction == 0)
411 r64.s64.uFraction = RTRandU64Ex(1, RT_BIT_64(RTFLOAT64U_FRACTION_BITS) - 1);
412 r64.s64.uExponent = 0;
413 AssertMsg(RTFLOAT64U_IS_SUBNORMAL(&r64), ("%s bType=%#x\n", FormatR64(&r64), bType));
414 }
415 else if (bType == 4 || bType == 5)
416 {
417 /* NaNs */
418 if (bType == 5)
419 SafeR64FractionShift(&r64, r64.s64.uExponent % 51);
420 else if (r64.s64.uFraction == 0)
421 r64.s64.uFraction = RTRandU64Ex(1, RT_BIT_64(RTFLOAT64U_FRACTION_BITS) - 1);
422 r64.s64.uExponent = 0x7ff;
423 AssertMsg(RTFLOAT64U_IS_NAN(&r64), ("%s bType=%#x\n", FormatR64(&r64), bType));
424 }
425 else if (bType < 12)
426 {
427 /* Make sure we have lots of normalized values. */
428 if (r64.s.uExponent == 0)
429 r64.s.uExponent = 1;
430 else if (r64.s.uExponent == 0x7ff)
431 r64.s.uExponent = 0x7fe;
432 AssertMsg(RTFLOAT64U_IS_NORMAL(&r64), ("%s bType=%#x\n", FormatR64(&r64), bType));
433 }
434 return r64;
435}
436
437
438static void SafeR32FractionShift(PRTFLOAT32U pr32, uint8_t cShift)
439{
440 if (pr32->s.uFraction >= RT_BIT_32(cShift))
441 pr32->s.uFraction >>= cShift;
442 else
443 pr32->s.uFraction = (cShift % 19) + 1;
444}
445
446
447static RTFLOAT32U RandR32Src(uint32_t iTest)
448{
449 RT_NOREF(iTest);
450
451 RTFLOAT32U r32;
452 r32.u = RandU32();
453
454 /*
455 * Make it more likely that we get a good selection of special values.
456 * On average 6 out of 16 calls should return a special value.
457 */
458 uint8_t bType = RandU8() & 0xf;
459 if (bType == 0 || bType == 1)
460 {
461 /* 0 or Infinity. We only keep fSign here. */
462 r32.s.uExponent = bType == 0 ? 0 : 0xff;
463 r32.s.uFraction = 0;
464 AssertMsg(bType != 0 || RTFLOAT32U_IS_ZERO(&r32), ("%s\n", FormatR32(&r32)));
465 AssertMsg(bType != 1 || RTFLOAT32U_IS_INF(&r32), ("%s\n", FormatR32(&r32)));
466 }
467 else if (bType == 2 || bType == 3)
468 {
469 /* Subnormals */
470 if (bType == 3)
471 SafeR32FractionShift(&r32, r32.s.uExponent % 22);
472 else if (r32.s.uFraction == 0)
473 r32.s.uFraction = RTRandU32Ex(1, RT_BIT_32(RTFLOAT32U_FRACTION_BITS) - 1);
474 r32.s.uExponent = 0;
475 AssertMsg(RTFLOAT32U_IS_SUBNORMAL(&r32), ("%s bType=%#x\n", FormatR32(&r32), bType));
476 }
477 else if (bType == 4 || bType == 5)
478 {
479 /* NaNs */
480 if (bType == 5)
481 SafeR32FractionShift(&r32, r32.s.uExponent % 22);
482 else if (r32.s.uFraction == 0)
483 r32.s.uFraction = RTRandU32Ex(1, RT_BIT_32(RTFLOAT32U_FRACTION_BITS) - 1);
484 r32.s.uExponent = 0xff;
485 AssertMsg(RTFLOAT32U_IS_NAN(&r32), ("%s bType=%#x\n", FormatR32(&r32), bType));
486 }
487 else if (bType < 12)
488 {
489 /* Make sure we have lots of normalized values. */
490 if (r32.s.uExponent == 0)
491 r32.s.uExponent = 1;
492 else if (r32.s.uExponent == 0xff)
493 r32.s.uExponent = 0xfe;
494 AssertMsg(RTFLOAT32U_IS_NORMAL(&r32), ("%s bType=%#x\n", FormatR32(&r32), bType));
495 }
496 return r32;
497}
498
499
500static RTPBCD80U RandD80Src(uint32_t iTest)
501{
502 if (iTest < 3)
503 {
504 RTPBCD80U d80Zero = RTPBCD80U_INIT_ZERO(!(iTest & 1));
505 return d80Zero;
506 }
507 if (iTest < 5)
508 {
509 RTPBCD80U d80Ind = RTPBCD80U_INIT_INDEFINITE();
510 return d80Ind;
511 }
512
513 RTPBCD80U d80;
514 uint8_t b = RandU8();
515 d80.s.fSign = b & 1;
516
517 if ((iTest & 7) >= 6)
518 {
519 /* Illegal */
520 d80.s.uPad = (iTest & 7) == 7 ? b >> 1 : 0;
521 for (size_t iPair = 0; iPair < RT_ELEMENTS(d80.s.abPairs); iPair++)
522 d80.s.abPairs[iPair] = RandU8();
523 }
524 else
525 {
526 /* Normal */
527 d80.s.uPad = 0;
528 for (size_t iPair = 0; iPair < RT_ELEMENTS(d80.s.abPairs); iPair++)
529 {
530 uint8_t const uLo = (uint8_t)RTRandU32Ex(0, 9);
531 uint8_t const uHi = (uint8_t)RTRandU32Ex(0, 9);
532 d80.s.abPairs[iPair] = RTPBCD80U_MAKE_PAIR(uHi, uLo);
533 }
534 }
535 return d80;
536}
537
538
539const char *GenFormatR80(PCRTFLOAT80U plrd)
540{
541 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
542 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "RTFLOAT80U_INIT_C(%d,%#RX64,%u)",
543 plrd->s.fSign, plrd->s.uMantissa, plrd->s.uExponent);
544 return pszBuf;
545}
546
547const char *GenFormatR64(PCRTFLOAT64U prd)
548{
549 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
550 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "RTFLOAT64U_INIT_C(%d,%#RX64,%u)",
551 prd->s.fSign, RT_MAKE_U64(prd->s.uFractionLow, prd->s.uFractionHigh), prd->s.uExponent);
552 return pszBuf;
553}
554
555
556const char *GenFormatR32(PCRTFLOAT32U pr)
557{
558 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
559 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "RTFLOAT32U_INIT_C(%d,%#RX32,%u)", pr->s.fSign, pr->s.uFraction, pr->s.uExponent);
560 return pszBuf;
561}
562
563
564const char *GenFormatD80(PCRTPBCD80U pd80)
565{
566 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
567 size_t off;
568 if (pd80->s.uPad == 0)
569 off = RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "RTPBCD80U_INIT_C(%d", pd80->s.fSign);
570 else
571 off = RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "RTPBCD80U_INIT_EX_C(%#x,%d", pd80->s.uPad, pd80->s.fSign);
572 size_t iPair = RT_ELEMENTS(pd80->s.abPairs);
573 while (iPair-- > 0)
574 off += RTStrPrintf(&pszBuf[off], sizeof(g_aszBuf[0]) - off, ",%d,%d",
575 RTPBCD80U_HI_DIGIT(pd80->s.abPairs[iPair]),
576 RTPBCD80U_LO_DIGIT(pd80->s.abPairs[iPair]));
577 pszBuf[off++] = ')';
578 pszBuf[off++] = '\0';
579 return pszBuf;
580}
581
582
583const char *GenFormatI64(int64_t i64)
584{
585 if (i64 == INT64_MIN) /* This one is problematic */
586 return "INT64_MIN";
587 if (i64 == INT64_MAX)
588 return "INT64_MAX";
589 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
590 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "INT64_C(%RI64)", i64);
591 return pszBuf;
592}
593
594
595const char *GenFormatI32(int32_t i32)
596{
597 if (i32 == INT32_MIN) /* This one is problematic */
598 return "INT32_MIN";
599 if (i32 == INT32_MAX)
600 return "INT32_MAX";
601 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
602 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "INT32_C(%RI32)", i32);
603 return pszBuf;
604}
605
606
607const char *GenFormatI16(int16_t i16)
608{
609 if (i16 == INT16_MIN) /* This one is problematic */
610 return "INT16_MIN";
611 if (i16 == INT16_MAX)
612 return "INT16_MAX";
613 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
614 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "INT16_C(%RI16)", i16);
615 return pszBuf;
616}
617
618
619static void GenerateHeader(PRTSTREAM pOut, const char *pszCpuDesc, const char *pszCpuType)
620{
621 /* We want to tag the generated source code with the revision that produced it. */
622 static char s_szRev[] = "$Revision: 94409 $";
623 const char *pszRev = RTStrStripL(strchr(s_szRev, ':') + 1);
624 size_t cchRev = 0;
625 while (RT_C_IS_DIGIT(pszRev[cchRev]))
626 cchRev++;
627
628 RTStrmPrintf(pOut,
629 "/* $Id: tstIEMAImpl.cpp 94409 2022-03-31 10:42:18Z vboxsync $ */\n"
630 "/** @file\n"
631 " * IEM Assembly Instruction Helper Testcase Data%s%s - r%.*s on %s.\n"
632 " */\n"
633 "\n"
634 "/*\n"
635 " * Copyright (C) 2022 Oracle Corporation\n"
636 " *\n"
637 " * This file is part of VirtualBox Open Source Edition (OSE), as\n"
638 " * available from http://www.virtualbox.org. This file is free software;\n"
639 " * you can redistribute it and/or modify it under the terms of the GNU\n"
640 " * General Public License (GPL) as published by the Free Software\n"
641 " * Foundation, in version 2 as it comes in the \"COPYING\" file of the\n"
642 " * VirtualBox OSE distribution. VirtualBox OSE is distributed in the\n"
643 " * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.\n"
644 " */\n"
645 "\n"
646 "#include \"tstIEMAImpl.h\"\n"
647 "\n"
648 ,
649 pszCpuType ? " " : "", pszCpuType ? pszCpuType : "", cchRev, pszRev, pszCpuDesc);
650}
651
652
653static PRTSTREAM GenerateOpenWithHdr(const char *pszFilename, const char *pszCpuDesc, const char *pszCpuType)
654{
655 PRTSTREAM pOut = NULL;
656 int rc = RTStrmOpen(pszFilename, "w", &pOut);
657 if (RT_SUCCESS(rc))
658 {
659 GenerateHeader(pOut, pszCpuDesc, pszCpuType);
660 return pOut;
661 }
662 RTMsgError("Failed to open %s for writing: %Rrc", pszFilename, rc);
663 return NULL;
664}
665
666
667static RTEXITCODE GenerateFooterAndClose(PRTSTREAM pOut, const char *pszFilename, RTEXITCODE rcExit)
668{
669 RTStrmPrintf(pOut,
670 "\n"
671 "/* end of file */\n");
672 int rc = RTStrmClose(pOut);
673 if (RT_SUCCESS(rc))
674 return rcExit;
675 return RTMsgErrorExitFailure("RTStrmClose failed on %s: %Rrc", pszFilename, rc);
676}
677
678
679static void GenerateArrayStart(PRTSTREAM pOut, const char *pszName, const char *pszType)
680{
681 RTStrmPrintf(pOut, "%s const g_aTests_%s[] =\n{\n", pszType, pszName);
682}
683
684
685static void GenerateArrayEnd(PRTSTREAM pOut, const char *pszName)
686{
687 RTStrmPrintf(pOut,
688 "};\n"
689 "uint32_t const g_cTests_%s = RT_ELEMENTS(g_aTests_%s);\n"
690 "\n",
691 pszName, pszName);
692}
693
694#endif /* TSTIEMAIMPL_WITH_GENERATOR */
695
696
697/*
698 * Test helpers.
699 */
700static const char *EFlagsDiff(uint32_t fActual, uint32_t fExpected)
701{
702 if (fActual == fExpected)
703 return "";
704
705 uint32_t const fXor = fActual ^ fExpected;
706 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
707 size_t cch = RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), " - %#x", fXor);
708
709 static struct
710 {
711 const char *pszName;
712 uint32_t fFlag;
713 } const s_aFlags[] =
714 {
715#define EFL_ENTRY(a_Flags) { #a_Flags, X86_EFL_ ## a_Flags }
716 EFL_ENTRY(CF),
717 EFL_ENTRY(PF),
718 EFL_ENTRY(AF),
719 EFL_ENTRY(ZF),
720 EFL_ENTRY(SF),
721 EFL_ENTRY(TF),
722 EFL_ENTRY(IF),
723 EFL_ENTRY(DF),
724 EFL_ENTRY(OF),
725 EFL_ENTRY(IOPL),
726 EFL_ENTRY(NT),
727 EFL_ENTRY(RF),
728 EFL_ENTRY(VM),
729 EFL_ENTRY(AC),
730 EFL_ENTRY(VIF),
731 EFL_ENTRY(VIP),
732 EFL_ENTRY(ID),
733 };
734 for (size_t i = 0; i < RT_ELEMENTS(s_aFlags); i++)
735 if (s_aFlags[i].fFlag & fXor)
736 cch += RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch,
737 s_aFlags[i].fFlag & fActual ? "/%s" : "/!%s", s_aFlags[i].pszName);
738 RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, "");
739 return pszBuf;
740}
741
742
743static const char *FswDiff(uint16_t fActual, uint16_t fExpected)
744{
745 if (fActual == fExpected)
746 return "";
747
748 uint16_t const fXor = fActual ^ fExpected;
749 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
750 size_t cch = RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), " - %#x", fXor);
751
752 static struct
753 {
754 const char *pszName;
755 uint32_t fFlag;
756 } const s_aFlags[] =
757 {
758#define FSW_ENTRY(a_Flags) { #a_Flags, X86_FSW_ ## a_Flags }
759 FSW_ENTRY(IE),
760 FSW_ENTRY(DE),
761 FSW_ENTRY(ZE),
762 FSW_ENTRY(OE),
763 FSW_ENTRY(UE),
764 FSW_ENTRY(PE),
765 FSW_ENTRY(SF),
766 FSW_ENTRY(ES),
767 FSW_ENTRY(C0),
768 FSW_ENTRY(C1),
769 FSW_ENTRY(C2),
770 FSW_ENTRY(C3),
771 FSW_ENTRY(B),
772 };
773 for (size_t i = 0; i < RT_ELEMENTS(s_aFlags); i++)
774 if (s_aFlags[i].fFlag & fXor)
775 cch += RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch,
776 s_aFlags[i].fFlag & fActual ? "/%s" : "/!%s", s_aFlags[i].pszName);
777 if (fXor & X86_FSW_TOP_MASK)
778 cch += RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, "/TOP%u!%u",
779 X86_FSW_TOP_GET(fActual), X86_FSW_TOP_GET(fExpected));
780 RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, "");
781 return pszBuf;
782}
783
784
785static const char *FormatFcw(uint16_t fFcw)
786{
787 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
788
789 const char *pszPC = NULL; /* (msc+gcc are too stupid) */
790 switch (fFcw & X86_FCW_PC_MASK)
791 {
792 case X86_FCW_PC_24: pszPC = "PC24"; break;
793 case X86_FCW_PC_RSVD: pszPC = "PCRSVD!"; break;
794 case X86_FCW_PC_53: pszPC = "PC53"; break;
795 case X86_FCW_PC_64: pszPC = "PC64"; break;
796 }
797
798 const char *pszRC = NULL; /* (msc+gcc are too stupid) */
799 switch (fFcw & X86_FCW_RC_MASK)
800 {
801 case X86_FCW_RC_NEAREST: pszRC = "NEAR"; break;
802 case X86_FCW_RC_DOWN: pszRC = "DOWN"; break;
803 case X86_FCW_RC_UP: pszRC = "UP"; break;
804 case X86_FCW_RC_ZERO: pszRC = "ZERO"; break;
805 }
806 size_t cch = RTStrPrintf(&pszBuf[0], sizeof(g_aszBuf[0]), "%s %s", pszPC, pszRC);
807
808 static struct
809 {
810 const char *pszName;
811 uint32_t fFlag;
812 } const s_aFlags[] =
813 {
814#define FCW_ENTRY(a_Flags) { #a_Flags, X86_FCW_ ## a_Flags }
815 FCW_ENTRY(IM),
816 FCW_ENTRY(DM),
817 FCW_ENTRY(ZM),
818 FCW_ENTRY(OM),
819 FCW_ENTRY(UM),
820 FCW_ENTRY(PM),
821 { "6M", 64 },
822 };
823 for (size_t i = 0; i < RT_ELEMENTS(s_aFlags); i++)
824 if (fFcw & s_aFlags[i].fFlag)
825 cch += RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, " %s", s_aFlags[i].pszName);
826
827 RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, "");
828 return pszBuf;
829}
830
831
832static const char *FormatR80(PCRTFLOAT80U pr80)
833{
834 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
835 RTStrFormatR80(pszBuf, sizeof(g_aszBuf[0]), pr80, 0, 0, RTSTR_F_SPECIAL);
836 return pszBuf;
837}
838
839
840static const char *FormatR64(PCRTFLOAT64U pr64)
841{
842 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
843 RTStrFormatR64(pszBuf, sizeof(g_aszBuf[0]), pr64, 0, 0, RTSTR_F_SPECIAL);
844 return pszBuf;
845}
846
847
848static const char *FormatR32(PCRTFLOAT32U pr32)
849{
850 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
851 RTStrFormatR32(pszBuf, sizeof(g_aszBuf[0]), pr32, 0, 0, RTSTR_F_SPECIAL);
852 return pszBuf;
853}
854
855
856static const char *FormatD80(PCRTPBCD80U pd80)
857{
858 /* There is only one indefinite endcoding (same as for 80-bit
859 floating point), so get it out of the way first: */
860 if (RTPBCD80U_IS_INDEFINITE(pd80))
861 return "Ind";
862
863 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
864 size_t off = 0;
865 pszBuf[off++] = pd80->s.fSign ? '-' : '+';
866 unsigned cBadDigits = 0;
867 size_t iPair = RT_ELEMENTS(pd80->s.abPairs);
868 while (iPair-- > 0)
869 {
870 static const char s_szDigits[] = "0123456789abcdef";
871 static const uint8_t s_bBadDigits[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 };
872 pszBuf[off++] = s_szDigits[RTPBCD80U_HI_DIGIT(pd80->s.abPairs[iPair])];
873 pszBuf[off++] = s_szDigits[RTPBCD80U_LO_DIGIT(pd80->s.abPairs[iPair])];
874 cBadDigits += s_bBadDigits[RTPBCD80U_HI_DIGIT(pd80->s.abPairs[iPair])]
875 + s_bBadDigits[RTPBCD80U_LO_DIGIT(pd80->s.abPairs[iPair])];
876 }
877 if (cBadDigits || pd80->s.uPad != 0)
878 off += RTStrPrintf(&pszBuf[off], sizeof(g_aszBuf[0]) - off, "[%u,%#x]", cBadDigits, pd80->s.uPad);
879 pszBuf[off] = '\0';
880 return pszBuf;
881}
882
883
884/*
885 * Binary operations.
886 */
887TYPEDEF_SUBTEST_TYPE(BINU8_T, BINU8_TEST_T, PFNIEMAIMPLBINU8);
888TYPEDEF_SUBTEST_TYPE(BINU16_T, BINU16_TEST_T, PFNIEMAIMPLBINU16);
889TYPEDEF_SUBTEST_TYPE(BINU32_T, BINU32_TEST_T, PFNIEMAIMPLBINU32);
890TYPEDEF_SUBTEST_TYPE(BINU64_T, BINU64_TEST_T, PFNIEMAIMPLBINU64);
891
892#ifdef TSTIEMAIMPL_WITH_GENERATOR
893# define GEN_BINARY_TESTS(a_cBits, a_Fmt, a_TestType) \
894static void BinU ## a_cBits ## Generate(PRTSTREAM pOut, PRTSTREAM pOutCpu, uint32_t cTests) \
895{ \
896 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aBinU ## a_cBits); iFn++) \
897 { \
898 PFNIEMAIMPLBINU ## a_cBits const pfn = g_aBinU ## a_cBits[iFn].pfnNative \
899 ? g_aBinU ## a_cBits[iFn].pfnNative : g_aBinU ## a_cBits[iFn].pfn; \
900 PRTSTREAM pOutFn = pOut; \
901 if (g_aBinU ## a_cBits[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE) \
902 { \
903 if (g_aBinU ## a_cBits[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour) \
904 continue; \
905 pOutFn = pOutCpu; \
906 } \
907 \
908 GenerateArrayStart(pOutFn, g_aBinU ## a_cBits[iFn].pszName, #a_TestType); \
909 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
910 { \
911 a_TestType Test; \
912 Test.fEflIn = RandEFlags(); \
913 Test.fEflOut = Test.fEflIn; \
914 Test.uDstIn = RandU ## a_cBits ## Dst(iTest); \
915 Test.uDstOut = Test.uDstIn; \
916 Test.uSrcIn = RandU ## a_cBits ## Src(iTest); \
917 if (g_aBinU ## a_cBits[iFn].uExtra) \
918 Test.uSrcIn &= a_cBits - 1; /* Restrict bit index according to operand width */ \
919 Test.uMisc = 0; \
920 pfn(&Test.uDstOut, Test.uSrcIn, &Test.fEflOut); \
921 RTStrmPrintf(pOutFn, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", " a_Fmt ", %#x }, /* #%u */\n", \
922 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uSrcIn, Test.uMisc, iTest); \
923 } \
924 GenerateArrayEnd(pOutFn, g_aBinU ## a_cBits[iFn].pszName); \
925 } \
926}
927#else
928# define GEN_BINARY_TESTS(a_cBits, a_Fmt, a_TestType)
929#endif
930
931#define TEST_BINARY_OPS(a_cBits, a_uType, a_Fmt, a_TestType, a_aSubTests) \
932GEN_BINARY_TESTS(a_cBits, a_Fmt, a_TestType) \
933\
934static void BinU ## a_cBits ## Test(void) \
935{ \
936 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
937 { \
938 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
939 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
940 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
941 PFNIEMAIMPLBINU ## a_cBits pfn = a_aSubTests[iFn].pfn; \
942 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
943 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
944 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
945 { \
946 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
947 { \
948 uint32_t fEfl = paTests[iTest].fEflIn; \
949 a_uType uDst = paTests[iTest].uDstIn; \
950 pfn(&uDst, paTests[iTest].uSrcIn, &fEfl); \
951 if ( uDst != paTests[iTest].uDstOut \
952 || fEfl != paTests[iTest].fEflOut) \
953 RTTestFailed(g_hTest, "#%u%s: efl=%#08x dst=" a_Fmt " src=" a_Fmt " -> efl=%#08x dst=" a_Fmt ", expected %#08x & " a_Fmt "%s - %s\n", \
954 iTest, !iVar ? "" : "/n", paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn, \
955 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut, \
956 EFlagsDiff(fEfl, paTests[iTest].fEflOut), \
957 uDst == paTests[iTest].uDstOut ? "eflags" : fEfl == paTests[iTest].fEflOut ? "dst" : "both"); \
958 else \
959 { \
960 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
961 *g_pfEfl = paTests[iTest].fEflIn; \
962 pfn(g_pu ## a_cBits, paTests[iTest].uSrcIn, g_pfEfl); \
963 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDstOut); \
964 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut); \
965 } \
966 } \
967 pfn = a_aSubTests[iFn].pfnNative; \
968 } \
969 } \
970}
971
972
973/*
974 * 8-bit binary operations.
975 */
976static const BINU8_T g_aBinU8[] =
977{
978 ENTRY(add_u8),
979 ENTRY(add_u8_locked),
980 ENTRY(adc_u8),
981 ENTRY(adc_u8_locked),
982 ENTRY(sub_u8),
983 ENTRY(sub_u8_locked),
984 ENTRY(sbb_u8),
985 ENTRY(sbb_u8_locked),
986 ENTRY(or_u8),
987 ENTRY(or_u8_locked),
988 ENTRY(xor_u8),
989 ENTRY(xor_u8_locked),
990 ENTRY(and_u8),
991 ENTRY(and_u8_locked),
992 ENTRY(cmp_u8),
993 ENTRY(test_u8),
994};
995TEST_BINARY_OPS(8, uint8_t, "%#04x", BINU8_TEST_T, g_aBinU8)
996
997
998/*
999 * 16-bit binary operations.
1000 */
1001static const BINU16_T g_aBinU16[] =
1002{
1003 ENTRY(add_u16),
1004 ENTRY(add_u16_locked),
1005 ENTRY(adc_u16),
1006 ENTRY(adc_u16_locked),
1007 ENTRY(sub_u16),
1008 ENTRY(sub_u16_locked),
1009 ENTRY(sbb_u16),
1010 ENTRY(sbb_u16_locked),
1011 ENTRY(or_u16),
1012 ENTRY(or_u16_locked),
1013 ENTRY(xor_u16),
1014 ENTRY(xor_u16_locked),
1015 ENTRY(and_u16),
1016 ENTRY(and_u16_locked),
1017 ENTRY(cmp_u16),
1018 ENTRY(test_u16),
1019 ENTRY_EX(bt_u16, 1),
1020 ENTRY_EX(btc_u16, 1),
1021 ENTRY_EX(btc_u16_locked, 1),
1022 ENTRY_EX(btr_u16, 1),
1023 ENTRY_EX(btr_u16_locked, 1),
1024 ENTRY_EX(bts_u16, 1),
1025 ENTRY_EX(bts_u16_locked, 1),
1026 ENTRY_AMD( bsf_u16, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1027 ENTRY_INTEL(bsf_u16, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1028 ENTRY_AMD( bsr_u16, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1029 ENTRY_INTEL(bsr_u16, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1030 ENTRY_AMD( imul_two_u16, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
1031 ENTRY_INTEL(imul_two_u16, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
1032 ENTRY(arpl),
1033};
1034TEST_BINARY_OPS(16, uint16_t, "%#06x", BINU16_TEST_T, g_aBinU16)
1035
1036
1037/*
1038 * 32-bit binary operations.
1039 */
1040static const BINU32_T g_aBinU32[] =
1041{
1042 ENTRY(add_u32),
1043 ENTRY(add_u32_locked),
1044 ENTRY(adc_u32),
1045 ENTRY(adc_u32_locked),
1046 ENTRY(sub_u32),
1047 ENTRY(sub_u32_locked),
1048 ENTRY(sbb_u32),
1049 ENTRY(sbb_u32_locked),
1050 ENTRY(or_u32),
1051 ENTRY(or_u32_locked),
1052 ENTRY(xor_u32),
1053 ENTRY(xor_u32_locked),
1054 ENTRY(and_u32),
1055 ENTRY(and_u32_locked),
1056 ENTRY(cmp_u32),
1057 ENTRY(test_u32),
1058 ENTRY_EX(bt_u32, 1),
1059 ENTRY_EX(btc_u32, 1),
1060 ENTRY_EX(btc_u32_locked, 1),
1061 ENTRY_EX(btr_u32, 1),
1062 ENTRY_EX(btr_u32_locked, 1),
1063 ENTRY_EX(bts_u32, 1),
1064 ENTRY_EX(bts_u32_locked, 1),
1065 ENTRY_AMD( bsf_u32, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1066 ENTRY_INTEL(bsf_u32, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1067 ENTRY_AMD( bsr_u32, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1068 ENTRY_INTEL(bsr_u32, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1069 ENTRY_AMD( imul_two_u32, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
1070 ENTRY_INTEL(imul_two_u32, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
1071};
1072TEST_BINARY_OPS(32, uint32_t, "%#010RX32", BINU32_TEST_T, g_aBinU32)
1073
1074
1075/*
1076 * 64-bit binary operations.
1077 */
1078static const BINU64_T g_aBinU64[] =
1079{
1080 ENTRY(add_u64),
1081 ENTRY(add_u64_locked),
1082 ENTRY(adc_u64),
1083 ENTRY(adc_u64_locked),
1084 ENTRY(sub_u64),
1085 ENTRY(sub_u64_locked),
1086 ENTRY(sbb_u64),
1087 ENTRY(sbb_u64_locked),
1088 ENTRY(or_u64),
1089 ENTRY(or_u64_locked),
1090 ENTRY(xor_u64),
1091 ENTRY(xor_u64_locked),
1092 ENTRY(and_u64),
1093 ENTRY(and_u64_locked),
1094 ENTRY(cmp_u64),
1095 ENTRY(test_u64),
1096 ENTRY_EX(bt_u64, 1),
1097 ENTRY_EX(btc_u64, 1),
1098 ENTRY_EX(btc_u64_locked, 1),
1099 ENTRY_EX(btr_u64, 1),
1100 ENTRY_EX(btr_u64_locked, 1),
1101 ENTRY_EX(bts_u64, 1),
1102 ENTRY_EX(bts_u64_locked, 1),
1103 ENTRY_AMD( bsf_u64, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1104 ENTRY_INTEL(bsf_u64, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1105 ENTRY_AMD( bsr_u64, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1106 ENTRY_INTEL(bsr_u64, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1107 ENTRY_AMD( imul_two_u64, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
1108 ENTRY_INTEL(imul_two_u64, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
1109};
1110TEST_BINARY_OPS(64, uint64_t, "%#018RX64", BINU64_TEST_T, g_aBinU64)
1111
1112
1113/*
1114 * XCHG
1115 */
1116static void XchgTest(void)
1117{
1118 RTTestSub(g_hTest, "xchg");
1119 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU8, (uint8_t *pu8Mem, uint8_t *pu8Reg));
1120 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU16,(uint16_t *pu16Mem, uint16_t *pu16Reg));
1121 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU32,(uint32_t *pu32Mem, uint32_t *pu32Reg));
1122 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU64,(uint64_t *pu64Mem, uint64_t *pu64Reg));
1123
1124 static struct
1125 {
1126 uint8_t cb; uint64_t fMask;
1127 union
1128 {
1129 uintptr_t pfn;
1130 FNIEMAIMPLXCHGU8 *pfnU8;
1131 FNIEMAIMPLXCHGU16 *pfnU16;
1132 FNIEMAIMPLXCHGU32 *pfnU32;
1133 FNIEMAIMPLXCHGU64 *pfnU64;
1134 } u;
1135 }
1136 s_aXchgWorkers[] =
1137 {
1138 { 1, UINT8_MAX, { (uintptr_t)iemAImpl_xchg_u8_locked } },
1139 { 2, UINT16_MAX, { (uintptr_t)iemAImpl_xchg_u16_locked } },
1140 { 4, UINT32_MAX, { (uintptr_t)iemAImpl_xchg_u32_locked } },
1141 { 8, UINT64_MAX, { (uintptr_t)iemAImpl_xchg_u64_locked } },
1142 { 1, UINT8_MAX, { (uintptr_t)iemAImpl_xchg_u8_unlocked } },
1143 { 2, UINT16_MAX, { (uintptr_t)iemAImpl_xchg_u16_unlocked } },
1144 { 4, UINT32_MAX, { (uintptr_t)iemAImpl_xchg_u32_unlocked } },
1145 { 8, UINT64_MAX, { (uintptr_t)iemAImpl_xchg_u64_unlocked } },
1146 };
1147 for (size_t i = 0; i < RT_ELEMENTS(s_aXchgWorkers); i++)
1148 {
1149 RTUINT64U uIn1, uIn2, uMem, uDst;
1150 uMem.u = uIn1.u = RTRandU64Ex(0, s_aXchgWorkers[i].fMask);
1151 uDst.u = uIn2.u = RTRandU64Ex(0, s_aXchgWorkers[i].fMask);
1152 if (uIn1.u == uIn2.u)
1153 uDst.u = uIn2.u = ~uIn2.u;
1154
1155 switch (s_aXchgWorkers[i].cb)
1156 {
1157 case 1:
1158 s_aXchgWorkers[i].u.pfnU8(g_pu8, g_pu8Two);
1159 s_aXchgWorkers[i].u.pfnU8(&uMem.au8[0], &uDst.au8[0]);
1160 break;
1161 case 2:
1162 s_aXchgWorkers[i].u.pfnU16(g_pu16, g_pu16Two);
1163 s_aXchgWorkers[i].u.pfnU16(&uMem.Words.w0, &uDst.Words.w0);
1164 break;
1165 case 4:
1166 s_aXchgWorkers[i].u.pfnU32(g_pu32, g_pu32Two);
1167 s_aXchgWorkers[i].u.pfnU32(&uMem.DWords.dw0, &uDst.DWords.dw0);
1168 break;
1169 case 8:
1170 s_aXchgWorkers[i].u.pfnU64(g_pu64, g_pu64Two);
1171 s_aXchgWorkers[i].u.pfnU64(&uMem.u, &uDst.u);
1172 break;
1173 default: RTTestFailed(g_hTest, "%d\n", s_aXchgWorkers[i].cb); break;
1174 }
1175
1176 if (uMem.u != uIn2.u || uDst.u != uIn1.u)
1177 RTTestFailed(g_hTest, "i=%u: %#RX64, %#RX64 -> %#RX64, %#RX64\n", i, uIn1.u, uIn2.u, uMem.u, uDst.u);
1178 }
1179}
1180
1181
1182/*
1183 * XADD
1184 */
1185static void XaddTest(void)
1186{
1187#define TEST_XADD(a_cBits, a_Type, a_Fmt) do { \
1188 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXADDU ## a_cBits, (a_Type *, a_Type *, uint32_t *)); \
1189 static struct \
1190 { \
1191 const char *pszName; \
1192 FNIEMAIMPLXADDU ## a_cBits *pfn; \
1193 BINU ## a_cBits ## _TEST_T const *paTests; \
1194 uint32_t const *pcTests; \
1195 } const s_aFuncs[] = \
1196 { \
1197 { "xadd_u" # a_cBits, iemAImpl_xadd_u ## a_cBits, \
1198 g_aTests_add_u ## a_cBits, &g_cTests_add_u ## a_cBits }, \
1199 { "xadd_u" # a_cBits "8_locked", iemAImpl_xadd_u ## a_cBits ## _locked, \
1200 g_aTests_add_u ## a_cBits, &g_cTests_add_u ## a_cBits }, \
1201 }; \
1202 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++) \
1203 { \
1204 RTTestSub(g_hTest, s_aFuncs[iFn].pszName); \
1205 uint32_t const cTests = *s_aFuncs[iFn].pcTests; \
1206 BINU ## a_cBits ## _TEST_T const * const paTests = s_aFuncs[iFn].paTests; \
1207 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
1208 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
1209 { \
1210 uint32_t fEfl = paTests[iTest].fEflIn; \
1211 a_Type uSrc = paTests[iTest].uSrcIn; \
1212 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
1213 s_aFuncs[iFn].pfn(g_pu ## a_cBits, &uSrc, &fEfl); \
1214 if ( fEfl != paTests[iTest].fEflOut \
1215 || *g_pu ## a_cBits != paTests[iTest].uDstOut \
1216 || uSrc != paTests[iTest].uDstIn) \
1217 RTTestFailed(g_hTest, "%s/#%u: efl=%#08x dst=" a_Fmt " src=" a_Fmt " -> efl=%#08x dst=" a_Fmt " src=" a_Fmt ", expected %#08x, " a_Fmt ", " a_Fmt "%s\n", \
1218 s_aFuncs[iFn].pszName, iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn, \
1219 fEfl, *g_pu ## a_cBits, uSrc, paTests[iTest].fEflOut, paTests[iTest].uDstOut, paTests[iTest].uDstIn, \
1220 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
1221 } \
1222 } \
1223 } while(0)
1224 TEST_XADD(8, uint8_t, "%#04x");
1225 TEST_XADD(16, uint16_t, "%#06x");
1226 TEST_XADD(32, uint32_t, "%#010RX32");
1227 TEST_XADD(64, uint64_t, "%#010RX64");
1228}
1229
1230
1231/*
1232 * CMPXCHG
1233 */
1234
1235static void CmpXchgTest(void)
1236{
1237#define TEST_CMPXCHG(a_cBits, a_Type, a_Fmt) do {\
1238 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLCMPXCHGU ## a_cBits, (a_Type *, a_Type *, a_Type, uint32_t *)); \
1239 static struct \
1240 { \
1241 const char *pszName; \
1242 FNIEMAIMPLCMPXCHGU ## a_cBits *pfn; \
1243 PFNIEMAIMPLBINU ## a_cBits pfnSub; \
1244 BINU ## a_cBits ## _TEST_T const *paTests; \
1245 uint32_t const *pcTests; \
1246 } const s_aFuncs[] = \
1247 { \
1248 { "cmpxchg_u" # a_cBits, iemAImpl_cmpxchg_u ## a_cBits, iemAImpl_sub_u ## a_cBits, \
1249 g_aTests_cmp_u ## a_cBits, &g_cTests_cmp_u ## a_cBits }, \
1250 { "cmpxchg_u" # a_cBits "_locked", iemAImpl_cmpxchg_u ## a_cBits ## _locked, iemAImpl_sub_u ## a_cBits, \
1251 g_aTests_cmp_u ## a_cBits, &g_cTests_cmp_u ## a_cBits }, \
1252 }; \
1253 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++) \
1254 { \
1255 RTTestSub(g_hTest, s_aFuncs[iFn].pszName); \
1256 BINU ## a_cBits ## _TEST_T const * const paTests = s_aFuncs[iFn].paTests; \
1257 uint32_t const cTests = *s_aFuncs[iFn].pcTests; \
1258 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
1259 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
1260 { \
1261 /* as is (99% likely to be negative). */ \
1262 uint32_t fEfl = paTests[iTest].fEflIn; \
1263 a_Type const uNew = paTests[iTest].uSrcIn + 0x42; \
1264 a_Type uA = paTests[iTest].uDstIn; \
1265 *g_pu ## a_cBits = paTests[iTest].uSrcIn; \
1266 a_Type const uExpect = uA != paTests[iTest].uSrcIn ? paTests[iTest].uSrcIn : uNew; \
1267 s_aFuncs[iFn].pfn(g_pu ## a_cBits, &uA, uNew, &fEfl); \
1268 if ( fEfl != paTests[iTest].fEflOut \
1269 || *g_pu ## a_cBits != uExpect \
1270 || uA != paTests[iTest].uSrcIn) \
1271 RTTestFailed(g_hTest, "%s/#%ua: efl=%#08x dst=" a_Fmt " cmp=" a_Fmt " new=" a_Fmt " -> efl=%#08x dst=" a_Fmt " old=" a_Fmt ", expected %#08x, " a_Fmt ", " a_Fmt "%s\n", \
1272 s_aFuncs[iFn].pszName, iTest, paTests[iTest].fEflIn, paTests[iTest].uSrcIn, paTests[iTest].uDstIn, \
1273 uNew, fEfl, *g_pu ## a_cBits, uA, paTests[iTest].fEflOut, uExpect, paTests[iTest].uSrcIn, \
1274 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
1275 /* positive */ \
1276 uint32_t fEflExpect = paTests[iTest].fEflIn; \
1277 uA = paTests[iTest].uDstIn; \
1278 s_aFuncs[iFn].pfnSub(&uA, uA, &fEflExpect); \
1279 fEfl = paTests[iTest].fEflIn; \
1280 uA = paTests[iTest].uDstIn; \
1281 *g_pu ## a_cBits = uA; \
1282 s_aFuncs[iFn].pfn(g_pu ## a_cBits, &uA, uNew, &fEfl); \
1283 if ( fEfl != fEflExpect \
1284 || *g_pu ## a_cBits != uNew \
1285 || uA != paTests[iTest].uDstIn) \
1286 RTTestFailed(g_hTest, "%s/#%ua: efl=%#08x dst=" a_Fmt " cmp=" a_Fmt " new=" a_Fmt " -> efl=%#08x dst=" a_Fmt " old=" a_Fmt ", expected %#08x, " a_Fmt ", " a_Fmt "%s\n", \
1287 s_aFuncs[iFn].pszName, iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uDstIn, \
1288 uNew, fEfl, *g_pu ## a_cBits, uA, fEflExpect, uNew, paTests[iTest].uDstIn, \
1289 EFlagsDiff(fEfl, fEflExpect)); \
1290 } \
1291 } \
1292 } while(0)
1293 TEST_CMPXCHG(8, uint8_t, "%#04RX8");
1294 TEST_CMPXCHG(16, uint16_t, "%#06x");
1295 TEST_CMPXCHG(32, uint32_t, "%#010RX32");
1296#if ARCH_BITS != 32 /* calling convension issue, skipping as it's an unsupported host */
1297 TEST_CMPXCHG(64, uint64_t, "%#010RX64");
1298#endif
1299}
1300
1301static void CmpXchg8bTest(void)
1302{
1303 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLCMPXCHG8B,(uint64_t *, PRTUINT64U, PRTUINT64U, uint32_t *));
1304 static struct
1305 {
1306 const char *pszName;
1307 FNIEMAIMPLCMPXCHG8B *pfn;
1308 } const s_aFuncs[] =
1309 {
1310 { "cmpxchg8b", iemAImpl_cmpxchg8b },
1311 { "cmpxchg8b_locked", iemAImpl_cmpxchg8b_locked },
1312 };
1313 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++)
1314 {
1315 RTTestSub(g_hTest, s_aFuncs[iFn].pszName);
1316 for (uint32_t iTest = 0; iTest < 4; iTest += 2)
1317 {
1318 uint64_t const uOldValue = RandU64();
1319 uint64_t const uNewValue = RandU64();
1320
1321 /* positive test. */
1322 RTUINT64U uA, uB;
1323 uB.u = uNewValue;
1324 uA.u = uOldValue;
1325 *g_pu64 = uOldValue;
1326 uint32_t fEflIn = RandEFlags();
1327 uint32_t fEfl = fEflIn;
1328 s_aFuncs[iFn].pfn(g_pu64, &uA, &uB, &fEfl);
1329 if ( fEfl != (fEflIn | X86_EFL_ZF)
1330 || *g_pu64 != uNewValue
1331 || uA.u != uOldValue)
1332 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=%#018RX64 cmp=%#018RX64 new=%#018RX64\n -> efl=%#08x dst=%#018RX64 old=%#018RX64,\n wanted %#08x, %#018RX64, %#018RX64%s\n",
1333 iTest, fEflIn, uOldValue, uOldValue, uNewValue,
1334 fEfl, *g_pu64, uA.u,
1335 (fEflIn | X86_EFL_ZF), uNewValue, uOldValue, EFlagsDiff(fEfl, fEflIn | X86_EFL_ZF));
1336 RTTEST_CHECK(g_hTest, uB.u == uNewValue);
1337
1338 /* negative */
1339 uint64_t const uExpect = ~uOldValue;
1340 *g_pu64 = uExpect;
1341 uA.u = uOldValue;
1342 uB.u = uNewValue;
1343 fEfl = fEflIn = RandEFlags();
1344 s_aFuncs[iFn].pfn(g_pu64, &uA, &uB, &fEfl);
1345 if ( fEfl != (fEflIn & ~X86_EFL_ZF)
1346 || *g_pu64 != uExpect
1347 || uA.u != uExpect)
1348 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=%#018RX64 cmp=%#018RX64 new=%#018RX64\n -> efl=%#08x dst=%#018RX64 old=%#018RX64,\n wanted %#08x, %#018RX64, %#018RX64%s\n",
1349 iTest + 1, fEflIn, uExpect, uOldValue, uNewValue,
1350 fEfl, *g_pu64, uA.u,
1351 (fEflIn & ~X86_EFL_ZF), uExpect, uExpect, EFlagsDiff(fEfl, fEflIn & ~X86_EFL_ZF));
1352 RTTEST_CHECK(g_hTest, uB.u == uNewValue);
1353 }
1354 }
1355}
1356
1357static void CmpXchg16bTest(void)
1358{
1359 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLCMPXCHG16B,(PRTUINT128U, PRTUINT128U, PRTUINT128U, uint32_t *));
1360 static struct
1361 {
1362 const char *pszName;
1363 FNIEMAIMPLCMPXCHG16B *pfn;
1364 } const s_aFuncs[] =
1365 {
1366 { "cmpxchg16b", iemAImpl_cmpxchg16b },
1367 { "cmpxchg16b_locked", iemAImpl_cmpxchg16b_locked },
1368#if !defined(RT_ARCH_ARM64)
1369 { "cmpxchg16b_fallback", iemAImpl_cmpxchg16b_fallback },
1370#endif
1371 };
1372 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++)
1373 {
1374#if !defined(IEM_WITHOUT_ASSEMBLY) && defined(RT_ARCH_AMD64)
1375 if (!(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_CX16))
1376 continue;
1377#endif
1378 RTTestSub(g_hTest, s_aFuncs[iFn].pszName);
1379 for (uint32_t iTest = 0; iTest < 4; iTest += 2)
1380 {
1381 RTUINT128U const uOldValue = RandU128();
1382 RTUINT128U const uNewValue = RandU128();
1383
1384 /* positive test. */
1385 RTUINT128U uA, uB;
1386 uB = uNewValue;
1387 uA = uOldValue;
1388 *g_pu128 = uOldValue;
1389 uint32_t fEflIn = RandEFlags();
1390 uint32_t fEfl = fEflIn;
1391 s_aFuncs[iFn].pfn(g_pu128, &uA, &uB, &fEfl);
1392 if ( fEfl != (fEflIn | X86_EFL_ZF)
1393 || g_pu128->s.Lo != uNewValue.s.Lo
1394 || g_pu128->s.Hi != uNewValue.s.Hi
1395 || uA.s.Lo != uOldValue.s.Lo
1396 || uA.s.Hi != uOldValue.s.Hi)
1397 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=%#018RX64'%016RX64 cmp=%#018RX64'%016RX64 new=%#018RX64'%016RX64\n"
1398 " -> efl=%#08x dst=%#018RX64'%016RX64 old=%#018RX64'%016RX64,\n"
1399 " wanted %#08x, %#018RX64'%016RX64, %#018RX64'%016RX64%s\n",
1400 iTest, fEflIn, uOldValue.s.Hi, uOldValue.s.Lo, uOldValue.s.Hi, uOldValue.s.Lo, uNewValue.s.Hi, uNewValue.s.Lo,
1401 fEfl, g_pu128->s.Hi, g_pu128->s.Lo, uA.s.Hi, uA.s.Lo,
1402 (fEflIn | X86_EFL_ZF), uNewValue.s.Hi, uNewValue.s.Lo, uOldValue.s.Hi, uOldValue.s.Lo,
1403 EFlagsDiff(fEfl, fEflIn | X86_EFL_ZF));
1404 RTTEST_CHECK(g_hTest, uB.s.Lo == uNewValue.s.Lo && uB.s.Hi == uNewValue.s.Hi);
1405
1406 /* negative */
1407 RTUINT128U const uExpect = RTUINT128_INIT(~uOldValue.s.Hi, ~uOldValue.s.Lo);
1408 *g_pu128 = uExpect;
1409 uA = uOldValue;
1410 uB = uNewValue;
1411 fEfl = fEflIn = RandEFlags();
1412 s_aFuncs[iFn].pfn(g_pu128, &uA, &uB, &fEfl);
1413 if ( fEfl != (fEflIn & ~X86_EFL_ZF)
1414 || g_pu128->s.Lo != uExpect.s.Lo
1415 || g_pu128->s.Hi != uExpect.s.Hi
1416 || uA.s.Lo != uExpect.s.Lo
1417 || uA.s.Hi != uExpect.s.Hi)
1418 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=%#018RX64'%016RX64 cmp=%#018RX64'%016RX64 new=%#018RX64'%016RX64\n"
1419 " -> efl=%#08x dst=%#018RX64'%016RX64 old=%#018RX64'%016RX64,\n"
1420 " wanted %#08x, %#018RX64'%016RX64, %#018RX64'%016RX64%s\n",
1421 iTest + 1, fEflIn, uExpect.s.Hi, uExpect.s.Lo, uOldValue.s.Hi, uOldValue.s.Lo, uNewValue.s.Hi, uNewValue.s.Lo,
1422 fEfl, g_pu128->s.Hi, g_pu128->s.Lo, uA.s.Hi, uA.s.Lo,
1423 (fEflIn & ~X86_EFL_ZF), uExpect.s.Hi, uExpect.s.Lo, uExpect.s.Hi, uExpect.s.Lo,
1424 EFlagsDiff(fEfl, fEflIn & ~X86_EFL_ZF));
1425 RTTEST_CHECK(g_hTest, uB.s.Lo == uNewValue.s.Lo && uB.s.Hi == uNewValue.s.Hi);
1426 }
1427 }
1428}
1429
1430
1431/*
1432 * Double shifts.
1433 *
1434 * Note! We use BINUxx_TEST_T with the shift value in the uMisc field.
1435 */
1436#ifdef TSTIEMAIMPL_WITH_GENERATOR
1437# define GEN_SHIFT_DBL(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
1438void ShiftDblU ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
1439{ \
1440 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
1441 { \
1442 if ( a_aSubTests[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE \
1443 && a_aSubTests[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour) \
1444 continue; \
1445 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
1446 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1447 { \
1448 a_TestType Test; \
1449 Test.fEflIn = RandEFlags(); \
1450 Test.fEflOut = Test.fEflIn; \
1451 Test.uDstIn = RandU ## a_cBits ## Dst(iTest); \
1452 Test.uDstOut = Test.uDstIn; \
1453 Test.uSrcIn = RandU ## a_cBits ## Src(iTest); \
1454 Test.uMisc = RandU8() & (a_cBits * 4 - 1); /* need to go way beyond the a_cBits limit */ \
1455 a_aSubTests[iFn].pfnNative(&Test.uDstOut, Test.uSrcIn, Test.uMisc, &Test.fEflOut); \
1456 RTStrmPrintf(pOut, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", " a_Fmt ", %2u }, /* #%u */\n", \
1457 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uSrcIn, Test.uMisc, iTest); \
1458 } \
1459 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
1460 } \
1461}
1462#else
1463# define GEN_SHIFT_DBL(a_cBits, a_Fmt, a_TestType, a_aSubTests)
1464#endif
1465
1466#define TEST_SHIFT_DBL(a_cBits, a_Type, a_Fmt, a_TestType, a_SubTestType, a_aSubTests) \
1467TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLSHIFTDBLU ## a_cBits); \
1468\
1469static a_SubTestType const a_aSubTests[] = \
1470{ \
1471 ENTRY_AMD(shld_u ## a_cBits, X86_EFL_OF | X86_EFL_CF), \
1472 ENTRY_INTEL(shld_u ## a_cBits, X86_EFL_OF | X86_EFL_CF), \
1473 ENTRY_AMD(shrd_u ## a_cBits, X86_EFL_OF | X86_EFL_CF), \
1474 ENTRY_INTEL(shrd_u ## a_cBits, X86_EFL_OF | X86_EFL_CF), \
1475}; \
1476\
1477GEN_SHIFT_DBL(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
1478\
1479static void ShiftDblU ## a_cBits ## Test(void) \
1480{ \
1481 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
1482 { \
1483 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
1484 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
1485 PFNIEMAIMPLSHIFTDBLU ## a_cBits pfn = a_aSubTests[iFn].pfn; \
1486 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
1487 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
1488 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
1489 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
1490 { \
1491 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1492 { \
1493 uint32_t fEfl = paTests[iTest].fEflIn; \
1494 a_Type uDst = paTests[iTest].uDstIn; \
1495 pfn(&uDst, paTests[iTest].uSrcIn, paTests[iTest].uMisc, &fEfl); \
1496 if ( uDst != paTests[iTest].uDstOut \
1497 || fEfl != paTests[iTest].fEflOut) \
1498 RTTestFailed(g_hTest, "#%03u%s: efl=%#08x dst=" a_Fmt " src=" a_Fmt " shift=%-2u -> efl=%#08x dst=" a_Fmt ", expected %#08x & " a_Fmt "%s%s\n", \
1499 iTest, iVar == 0 ? "" : "/n", paTests[iTest].fEflIn, \
1500 paTests[iTest].uDstIn, paTests[iTest].uSrcIn, (unsigned)paTests[iTest].uMisc, \
1501 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut, \
1502 EFlagsDiff(fEfl, paTests[iTest].fEflOut), uDst == paTests[iTest].uDstOut ? "" : " dst!"); \
1503 else \
1504 { \
1505 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
1506 *g_pfEfl = paTests[iTest].fEflIn; \
1507 pfn(g_pu ## a_cBits, paTests[iTest].uSrcIn, paTests[iTest].uMisc, g_pfEfl); \
1508 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDstOut); \
1509 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut); \
1510 } \
1511 } \
1512 pfn = a_aSubTests[iFn].pfnNative; \
1513 } \
1514 } \
1515}
1516TEST_SHIFT_DBL(16, uint16_t, "%#06RX16", BINU16_TEST_T, SHIFT_DBL_U16_T, g_aShiftDblU16)
1517TEST_SHIFT_DBL(32, uint32_t, "%#010RX32", BINU32_TEST_T, SHIFT_DBL_U32_T, g_aShiftDblU32)
1518TEST_SHIFT_DBL(64, uint64_t, "%#018RX64", BINU64_TEST_T, SHIFT_DBL_U64_T, g_aShiftDblU64)
1519
1520#ifdef TSTIEMAIMPL_WITH_GENERATOR
1521static void ShiftDblGenerate(PRTSTREAM pOut, uint32_t cTests)
1522{
1523 ShiftDblU16Generate(pOut, cTests);
1524 ShiftDblU32Generate(pOut, cTests);
1525 ShiftDblU64Generate(pOut, cTests);
1526}
1527#endif
1528
1529static void ShiftDblTest(void)
1530{
1531 ShiftDblU16Test();
1532 ShiftDblU32Test();
1533 ShiftDblU64Test();
1534}
1535
1536
1537/*
1538 * Unary operators.
1539 *
1540 * Note! We use BINUxx_TEST_T ignoreing uSrcIn and uMisc.
1541 */
1542#ifdef TSTIEMAIMPL_WITH_GENERATOR
1543# define GEN_UNARY(a_cBits, a_Type, a_Fmt, a_TestType, a_SubTestType) \
1544void UnaryU ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
1545{ \
1546 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aUnaryU ## a_cBits); iFn++) \
1547 { \
1548 GenerateArrayStart(pOut, g_aUnaryU ## a_cBits[iFn].pszName, #a_TestType); \
1549 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1550 { \
1551 a_TestType Test; \
1552 Test.fEflIn = RandEFlags(); \
1553 Test.fEflOut = Test.fEflIn; \
1554 Test.uDstIn = RandU ## a_cBits(); \
1555 Test.uDstOut = Test.uDstIn; \
1556 Test.uSrcIn = 0; \
1557 Test.uMisc = 0; \
1558 g_aUnaryU ## a_cBits[iFn].pfn(&Test.uDstOut, &Test.fEflOut); \
1559 RTStrmPrintf(pOut, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", 0, 0 }, /* #%u */\n", \
1560 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, iTest); \
1561 } \
1562 GenerateArrayEnd(pOut, g_aUnaryU ## a_cBits[iFn].pszName); \
1563 } \
1564}
1565#else
1566# define GEN_UNARY(a_cBits, a_Type, a_Fmt, a_TestType, a_SubTestType)
1567#endif
1568
1569#define TEST_UNARY(a_cBits, a_Type, a_Fmt, a_TestType, a_SubTestType) \
1570TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLUNARYU ## a_cBits); \
1571static a_SubTestType const g_aUnaryU ## a_cBits [] = \
1572{ \
1573 ENTRY(inc_u ## a_cBits), \
1574 ENTRY(inc_u ## a_cBits ## _locked), \
1575 ENTRY(dec_u ## a_cBits), \
1576 ENTRY(dec_u ## a_cBits ## _locked), \
1577 ENTRY(not_u ## a_cBits), \
1578 ENTRY(not_u ## a_cBits ## _locked), \
1579 ENTRY(neg_u ## a_cBits), \
1580 ENTRY(neg_u ## a_cBits ## _locked), \
1581}; \
1582\
1583GEN_UNARY(a_cBits, a_Type, a_Fmt, a_TestType, a_SubTestType) \
1584\
1585static void UnaryU ## a_cBits ## Test(void) \
1586{ \
1587 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aUnaryU ## a_cBits); iFn++) \
1588 { \
1589 RTTestSub(g_hTest, g_aUnaryU ## a_cBits[iFn].pszName); \
1590 a_TestType const * const paTests = g_aUnaryU ## a_cBits[iFn].paTests; \
1591 uint32_t const cTests = *g_aUnaryU ## a_cBits[iFn].pcTests; \
1592 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
1593 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1594 { \
1595 uint32_t fEfl = paTests[iTest].fEflIn; \
1596 a_Type uDst = paTests[iTest].uDstIn; \
1597 g_aUnaryU ## a_cBits[iFn].pfn(&uDst, &fEfl); \
1598 if ( uDst != paTests[iTest].uDstOut \
1599 || fEfl != paTests[iTest].fEflOut) \
1600 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=" a_Fmt " -> efl=%#08x dst=" a_Fmt ", expected %#08x & " a_Fmt "%s\n", \
1601 iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, \
1602 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut, \
1603 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
1604 else \
1605 { \
1606 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
1607 *g_pfEfl = paTests[iTest].fEflIn; \
1608 g_aUnaryU ## a_cBits[iFn].pfn(g_pu ## a_cBits, g_pfEfl); \
1609 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDstOut); \
1610 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut); \
1611 } \
1612 } \
1613 } \
1614}
1615TEST_UNARY(8, uint8_t, "%#04RX8", BINU8_TEST_T, INT_UNARY_U8_T)
1616TEST_UNARY(16, uint16_t, "%#06RX16", BINU16_TEST_T, INT_UNARY_U16_T)
1617TEST_UNARY(32, uint32_t, "%#010RX32", BINU32_TEST_T, INT_UNARY_U32_T)
1618TEST_UNARY(64, uint64_t, "%#018RX64", BINU64_TEST_T, INT_UNARY_U64_T)
1619
1620#ifdef TSTIEMAIMPL_WITH_GENERATOR
1621static void UnaryGenerate(PRTSTREAM pOut, uint32_t cTests)
1622{
1623 UnaryU8Generate(pOut, cTests);
1624 UnaryU16Generate(pOut, cTests);
1625 UnaryU32Generate(pOut, cTests);
1626 UnaryU64Generate(pOut, cTests);
1627}
1628#endif
1629
1630static void UnaryTest(void)
1631{
1632 UnaryU8Test();
1633 UnaryU16Test();
1634 UnaryU32Test();
1635 UnaryU64Test();
1636}
1637
1638
1639/*
1640 * Shifts.
1641 *
1642 * Note! We use BINUxx_TEST_T with the shift count in uMisc and uSrcIn unused.
1643 */
1644#ifdef TSTIEMAIMPL_WITH_GENERATOR
1645# define GEN_SHIFT(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
1646void ShiftU ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
1647{ \
1648 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
1649 { \
1650 if ( a_aSubTests[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE \
1651 && a_aSubTests[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour) \
1652 continue; \
1653 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
1654 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1655 { \
1656 a_TestType Test; \
1657 Test.fEflIn = RandEFlags(); \
1658 Test.fEflOut = Test.fEflIn; \
1659 Test.uDstIn = RandU ## a_cBits ## Dst(iTest); \
1660 Test.uDstOut = Test.uDstIn; \
1661 Test.uSrcIn = 0; \
1662 Test.uMisc = RandU8() & (a_cBits * 4 - 1); /* need to go way beyond the a_cBits limit */ \
1663 a_aSubTests[iFn].pfnNative(&Test.uDstOut, Test.uMisc, &Test.fEflOut); \
1664 RTStrmPrintf(pOut, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", 0, %-2u }, /* #%u */\n", \
1665 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uMisc, iTest); \
1666 \
1667 Test.fEflIn = (~Test.fEflIn & X86_EFL_LIVE_MASK) | X86_EFL_RA1_MASK; \
1668 Test.fEflOut = Test.fEflIn; \
1669 Test.uDstOut = Test.uDstIn; \
1670 a_aSubTests[iFn].pfnNative(&Test.uDstOut, Test.uMisc, &Test.fEflOut); \
1671 RTStrmPrintf(pOut, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", 0, %-2u }, /* #%u b */\n", \
1672 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uMisc, iTest); \
1673 } \
1674 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
1675 } \
1676}
1677#else
1678# define GEN_SHIFT(a_cBits, a_Fmt, a_TestType, a_aSubTests)
1679#endif
1680
1681#define TEST_SHIFT(a_cBits, a_Type, a_Fmt, a_TestType, a_SubTestType, a_aSubTests) \
1682TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLSHIFTU ## a_cBits); \
1683static a_SubTestType const a_aSubTests[] = \
1684{ \
1685 ENTRY_AMD( rol_u ## a_cBits, X86_EFL_OF), \
1686 ENTRY_INTEL(rol_u ## a_cBits, X86_EFL_OF), \
1687 ENTRY_AMD( ror_u ## a_cBits, X86_EFL_OF), \
1688 ENTRY_INTEL(ror_u ## a_cBits, X86_EFL_OF), \
1689 ENTRY_AMD( rcl_u ## a_cBits, X86_EFL_OF), \
1690 ENTRY_INTEL(rcl_u ## a_cBits, X86_EFL_OF), \
1691 ENTRY_AMD( rcr_u ## a_cBits, X86_EFL_OF), \
1692 ENTRY_INTEL(rcr_u ## a_cBits, X86_EFL_OF), \
1693 ENTRY_AMD( shl_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
1694 ENTRY_INTEL(shl_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
1695 ENTRY_AMD( shr_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
1696 ENTRY_INTEL(shr_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
1697 ENTRY_AMD( sar_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
1698 ENTRY_INTEL(sar_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
1699}; \
1700\
1701GEN_SHIFT(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
1702\
1703static void ShiftU ## a_cBits ## Test(void) \
1704{ \
1705 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
1706 { \
1707 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
1708 PFNIEMAIMPLSHIFTU ## a_cBits pfn = a_aSubTests[iFn].pfn; \
1709 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
1710 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
1711 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
1712 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
1713 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
1714 { \
1715 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1716 { \
1717 uint32_t fEfl = paTests[iTest].fEflIn; \
1718 a_Type uDst = paTests[iTest].uDstIn; \
1719 pfn(&uDst, paTests[iTest].uMisc, &fEfl); \
1720 if ( uDst != paTests[iTest].uDstOut \
1721 || fEfl != paTests[iTest].fEflOut ) \
1722 RTTestFailed(g_hTest, "#%u%s: efl=%#08x dst=" a_Fmt " shift=%2u -> efl=%#08x dst=" a_Fmt ", expected %#08x & " a_Fmt "%s\n", \
1723 iTest, iVar == 0 ? "" : "/n", \
1724 paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uMisc, \
1725 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut, \
1726 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
1727 else \
1728 { \
1729 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
1730 *g_pfEfl = paTests[iTest].fEflIn; \
1731 pfn(g_pu ## a_cBits, paTests[iTest].uMisc, g_pfEfl); \
1732 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDstOut); \
1733 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut); \
1734 } \
1735 } \
1736 pfn = a_aSubTests[iFn].pfnNative; \
1737 } \
1738 } \
1739}
1740TEST_SHIFT(8, uint8_t, "%#04RX8", BINU8_TEST_T, INT_BINARY_U8_T, g_aShiftU8)
1741TEST_SHIFT(16, uint16_t, "%#06RX16", BINU16_TEST_T, INT_BINARY_U16_T, g_aShiftU16)
1742TEST_SHIFT(32, uint32_t, "%#010RX32", BINU32_TEST_T, INT_BINARY_U32_T, g_aShiftU32)
1743TEST_SHIFT(64, uint64_t, "%#018RX64", BINU64_TEST_T, INT_BINARY_U64_T, g_aShiftU64)
1744
1745#ifdef TSTIEMAIMPL_WITH_GENERATOR
1746static void ShiftGenerate(PRTSTREAM pOut, uint32_t cTests)
1747{
1748 ShiftU8Generate(pOut, cTests);
1749 ShiftU16Generate(pOut, cTests);
1750 ShiftU32Generate(pOut, cTests);
1751 ShiftU64Generate(pOut, cTests);
1752}
1753#endif
1754
1755static void ShiftTest(void)
1756{
1757 ShiftU8Test();
1758 ShiftU16Test();
1759 ShiftU32Test();
1760 ShiftU64Test();
1761}
1762
1763
1764/*
1765 * Multiplication and division.
1766 *
1767 * Note! The 8-bit functions has a different format, so we need to duplicate things.
1768 * Note! Currently ignoring undefined bits.
1769 */
1770
1771/* U8 */
1772TYPEDEF_SUBTEST_TYPE(INT_MULDIV_U8_T, MULDIVU8_TEST_T, PFNIEMAIMPLMULDIVU8);
1773static INT_MULDIV_U8_T const g_aMulDivU8[] =
1774{
1775 ENTRY_AMD_EX(mul_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF,
1776 X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF),
1777 ENTRY_INTEL_EX(mul_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0),
1778 ENTRY_AMD_EX(imul_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF,
1779 X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF),
1780 ENTRY_INTEL_EX(imul_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0),
1781 ENTRY_AMD_EX(div_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0),
1782 ENTRY_INTEL_EX(div_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0),
1783 ENTRY_AMD_EX(idiv_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0),
1784 ENTRY_INTEL_EX(idiv_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0),
1785};
1786
1787#ifdef TSTIEMAIMPL_WITH_GENERATOR
1788static void MulDivU8Generate(PRTSTREAM pOut, uint32_t cTests)
1789{
1790 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aMulDivU8); iFn++)
1791 {
1792 if ( g_aMulDivU8[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE
1793 && g_aMulDivU8[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour)
1794 continue;
1795 GenerateArrayStart(pOut, g_aMulDivU8[iFn].pszName, "MULDIVU8_TEST_T"); \
1796 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
1797 {
1798 MULDIVU8_TEST_T Test;
1799 Test.fEflIn = RandEFlags();
1800 Test.fEflOut = Test.fEflIn;
1801 Test.uDstIn = RandU16Dst(iTest);
1802 Test.uDstOut = Test.uDstIn;
1803 Test.uSrcIn = RandU8Src(iTest);
1804 Test.rc = g_aMulDivU8[iFn].pfnNative(&Test.uDstOut, Test.uSrcIn, &Test.fEflOut);
1805 RTStrmPrintf(pOut, " { %#08x, %#08x, %#06RX16, %#06RX16, %#04RX8, %d }, /* #%u */\n",
1806 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uSrcIn, Test.rc, iTest);
1807 }
1808 GenerateArrayEnd(pOut, g_aMulDivU8[iFn].pszName);
1809 }
1810}
1811#endif
1812
1813static void MulDivU8Test(void)
1814{
1815 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aMulDivU8); iFn++)
1816 {
1817 RTTestSub(g_hTest, g_aMulDivU8[iFn].pszName);
1818 MULDIVU8_TEST_T const * const paTests = g_aMulDivU8[iFn].paTests;
1819 uint32_t const cTests = *g_aMulDivU8[iFn].pcTests;
1820 uint32_t const fEflIgn = g_aMulDivU8[iFn].uExtra;
1821 PFNIEMAIMPLMULDIVU8 pfn = g_aMulDivU8[iFn].pfn;
1822 uint32_t const cVars = 1 + (g_aMulDivU8[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && g_aMulDivU8[iFn].pfnNative);
1823 if (!cTests) RTTestSkipped(g_hTest, "no tests");
1824 for (uint32_t iVar = 0; iVar < cVars; iVar++)
1825 {
1826 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
1827 {
1828 uint32_t fEfl = paTests[iTest].fEflIn;
1829 uint16_t uDst = paTests[iTest].uDstIn;
1830 int rc = g_aMulDivU8[iFn].pfn(&uDst, paTests[iTest].uSrcIn, &fEfl);
1831 if ( uDst != paTests[iTest].uDstOut
1832 || (fEfl | fEflIgn) != (paTests[iTest].fEflOut | fEflIgn)
1833 || rc != paTests[iTest].rc)
1834 RTTestFailed(g_hTest, "#%02u%s: efl=%#08x dst=%#06RX16 src=%#04RX8\n"
1835 " %s-> efl=%#08x dst=%#06RX16 rc=%d\n"
1836 "%sexpected %#08x %#06RX16 %d%s\n",
1837 iTest, iVar ? "/n" : "", paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn,
1838 iVar ? " " : "", fEfl, uDst, rc,
1839 iVar ? " " : "", paTests[iTest].fEflOut, paTests[iTest].uDstOut, paTests[iTest].rc,
1840 EFlagsDiff(fEfl | fEflIgn, paTests[iTest].fEflOut | fEflIgn));
1841 else
1842 {
1843 *g_pu16 = paTests[iTest].uDstIn;
1844 *g_pfEfl = paTests[iTest].fEflIn;
1845 rc = g_aMulDivU8[iFn].pfn(g_pu16, paTests[iTest].uSrcIn, g_pfEfl);
1846 RTTEST_CHECK(g_hTest, *g_pu16 == paTests[iTest].uDstOut);
1847 RTTEST_CHECK(g_hTest, (*g_pfEfl | fEflIgn) == (paTests[iTest].fEflOut | fEflIgn));
1848 RTTEST_CHECK(g_hTest, rc == paTests[iTest].rc);
1849 }
1850 }
1851 pfn = g_aMulDivU8[iFn].pfnNative;
1852 }
1853 }
1854}
1855
1856#ifdef TSTIEMAIMPL_WITH_GENERATOR
1857# define GEN_MULDIV(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
1858void MulDivU ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
1859{ \
1860 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
1861 { \
1862 if ( a_aSubTests[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE \
1863 && a_aSubTests[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour) \
1864 continue; \
1865 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
1866 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1867 { \
1868 a_TestType Test; \
1869 Test.fEflIn = RandEFlags(); \
1870 Test.fEflOut = Test.fEflIn; \
1871 Test.uDst1In = RandU ## a_cBits ## Dst(iTest); \
1872 Test.uDst1Out = Test.uDst1In; \
1873 Test.uDst2In = RandU ## a_cBits ## Dst(iTest); \
1874 Test.uDst2Out = Test.uDst2In; \
1875 Test.uSrcIn = RandU ## a_cBits ## Src(iTest); \
1876 Test.rc = a_aSubTests[iFn].pfnNative(&Test.uDst1Out, &Test.uDst2Out, Test.uSrcIn, &Test.fEflOut); \
1877 RTStrmPrintf(pOut, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", " a_Fmt ", " a_Fmt ", " a_Fmt ", %d }, /* #%u */\n", \
1878 Test.fEflIn, Test.fEflOut, Test.uDst1In, Test.uDst1Out, Test.uDst2In, Test.uDst2Out, Test.uSrcIn, \
1879 Test.rc, iTest); \
1880 } \
1881 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
1882 } \
1883}
1884#else
1885# define GEN_MULDIV(a_cBits, a_Fmt, a_TestType, a_aSubTests)
1886#endif
1887
1888#define TEST_MULDIV(a_cBits, a_Type, a_Fmt, a_TestType, a_SubTestType, a_aSubTests) \
1889TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLMULDIVU ## a_cBits); \
1890static a_SubTestType const a_aSubTests [] = \
1891{ \
1892 ENTRY_AMD_EX(mul_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0), \
1893 ENTRY_INTEL_EX(mul_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0), \
1894 ENTRY_AMD_EX(imul_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0), \
1895 ENTRY_INTEL_EX(imul_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0), \
1896 ENTRY_AMD_EX(div_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0), \
1897 ENTRY_INTEL_EX(div_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0), \
1898 ENTRY_AMD_EX(idiv_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0), \
1899 ENTRY_INTEL_EX(idiv_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0), \
1900}; \
1901\
1902GEN_MULDIV(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
1903\
1904static void MulDivU ## a_cBits ## Test(void) \
1905{ \
1906 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
1907 { \
1908 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
1909 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
1910 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
1911 uint32_t const fEflIgn = a_aSubTests[iFn].uExtra; \
1912 PFNIEMAIMPLMULDIVU ## a_cBits pfn = a_aSubTests[iFn].pfn; \
1913 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
1914 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
1915 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
1916 { \
1917 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1918 { \
1919 uint32_t fEfl = paTests[iTest].fEflIn; \
1920 a_Type uDst1 = paTests[iTest].uDst1In; \
1921 a_Type uDst2 = paTests[iTest].uDst2In; \
1922 int rc = pfn(&uDst1, &uDst2, paTests[iTest].uSrcIn, &fEfl); \
1923 if ( uDst1 != paTests[iTest].uDst1Out \
1924 || uDst2 != paTests[iTest].uDst2Out \
1925 || (fEfl | fEflIgn) != (paTests[iTest].fEflOut | fEflIgn)\
1926 || rc != paTests[iTest].rc) \
1927 RTTestFailed(g_hTest, "#%02u%s: efl=%#08x dst1=" a_Fmt " dst2=" a_Fmt " src=" a_Fmt "\n" \
1928 " -> efl=%#08x dst1=" a_Fmt " dst2=" a_Fmt " rc=%d\n" \
1929 "expected %#08x " a_Fmt " " a_Fmt " %d%s -%s%s%s\n", \
1930 iTest, iVar == 0 ? "" : "/n", \
1931 paTests[iTest].fEflIn, paTests[iTest].uDst1In, paTests[iTest].uDst2In, paTests[iTest].uSrcIn, \
1932 fEfl, uDst1, uDst2, rc, \
1933 paTests[iTest].fEflOut, paTests[iTest].uDst1Out, paTests[iTest].uDst2Out, paTests[iTest].rc, \
1934 EFlagsDiff(fEfl | fEflIgn, paTests[iTest].fEflOut | fEflIgn), \
1935 uDst1 != paTests[iTest].uDst1Out ? " dst1" : "", uDst2 != paTests[iTest].uDst2Out ? " dst2" : "", \
1936 (fEfl | fEflIgn) != (paTests[iTest].fEflOut | fEflIgn) ? " eflags" : ""); \
1937 else \
1938 { \
1939 *g_pu ## a_cBits = paTests[iTest].uDst1In; \
1940 *g_pu ## a_cBits ## Two = paTests[iTest].uDst2In; \
1941 *g_pfEfl = paTests[iTest].fEflIn; \
1942 rc = pfn(g_pu ## a_cBits, g_pu ## a_cBits ## Two, paTests[iTest].uSrcIn, g_pfEfl); \
1943 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDst1Out); \
1944 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits ## Two == paTests[iTest].uDst2Out); \
1945 RTTEST_CHECK(g_hTest, (*g_pfEfl | fEflIgn) == (paTests[iTest].fEflOut | fEflIgn)); \
1946 RTTEST_CHECK(g_hTest, rc == paTests[iTest].rc); \
1947 } \
1948 } \
1949 pfn = a_aSubTests[iFn].pfnNative; \
1950 } \
1951 } \
1952}
1953TEST_MULDIV(16, uint16_t, "%#06RX16", MULDIVU16_TEST_T, INT_MULDIV_U16_T, g_aMulDivU16)
1954TEST_MULDIV(32, uint32_t, "%#010RX32", MULDIVU32_TEST_T, INT_MULDIV_U32_T, g_aMulDivU32)
1955TEST_MULDIV(64, uint64_t, "%#018RX64", MULDIVU64_TEST_T, INT_MULDIV_U64_T, g_aMulDivU64)
1956
1957#ifdef TSTIEMAIMPL_WITH_GENERATOR
1958static void MulDivGenerate(PRTSTREAM pOut, uint32_t cTests)
1959{
1960 MulDivU8Generate(pOut, cTests);
1961 MulDivU16Generate(pOut, cTests);
1962 MulDivU32Generate(pOut, cTests);
1963 MulDivU64Generate(pOut, cTests);
1964}
1965#endif
1966
1967static void MulDivTest(void)
1968{
1969 MulDivU8Test();
1970 MulDivU16Test();
1971 MulDivU32Test();
1972 MulDivU64Test();
1973}
1974
1975
1976/*
1977 * BSWAP
1978 */
1979static void BswapTest(void)
1980{
1981 RTTestSub(g_hTest, "bswap_u16");
1982 *g_pu32 = UINT32_C(0x12345678);
1983 iemAImpl_bswap_u16(g_pu32);
1984#if 0
1985 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0x12347856), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
1986#else
1987 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0x12340000), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
1988#endif
1989 *g_pu32 = UINT32_C(0xffff1122);
1990 iemAImpl_bswap_u16(g_pu32);
1991#if 0
1992 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0xffff2211), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
1993#else
1994 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0xffff0000), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
1995#endif
1996
1997 RTTestSub(g_hTest, "bswap_u32");
1998 *g_pu32 = UINT32_C(0x12345678);
1999 iemAImpl_bswap_u32(g_pu32);
2000 RTTEST_CHECK(g_hTest, *g_pu32 == UINT32_C(0x78563412));
2001
2002 RTTestSub(g_hTest, "bswap_u64");
2003 *g_pu64 = UINT64_C(0x0123456789abcdef);
2004 iemAImpl_bswap_u64(g_pu64);
2005 RTTEST_CHECK(g_hTest, *g_pu64 == UINT64_C(0xefcdab8967452301));
2006}
2007
2008
2009
2010/*********************************************************************************************************************************
2011* Floating point (x87 style) *
2012*********************************************************************************************************************************/
2013
2014/*
2015 * FPU constant loading.
2016 */
2017TYPEDEF_SUBTEST_TYPE(FPU_LD_CONST_T, FPU_LD_CONST_TEST_T, PFNIEMAIMPLFPUR80LDCONST);
2018
2019static const FPU_LD_CONST_T g_aFpuLdConst[] =
2020{
2021 ENTRY(fld1),
2022 ENTRY(fldl2t),
2023 ENTRY(fldl2e),
2024 ENTRY(fldpi),
2025 ENTRY(fldlg2),
2026 ENTRY(fldln2),
2027 ENTRY(fldz),
2028};
2029
2030#ifdef TSTIEMAIMPL_WITH_GENERATOR
2031static void FpuLdConstGenerate(PRTSTREAM pOut, uint32_t cTests)
2032{
2033 X86FXSTATE State;
2034 RT_ZERO(State);
2035 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuLdConst); iFn++)
2036 {
2037 GenerateArrayStart(pOut, g_aFpuLdConst[iFn].pszName, "FPU_LD_CONST_TEST_T");
2038 for (uint32_t iTest = 0; iTest < cTests; iTest += 4)
2039 {
2040 State.FCW = RandFcw();
2041 State.FSW = RandFsw();
2042
2043 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
2044 {
2045 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 };
2046 State.FCW = (State.FCW & ~X86_FCW_RC_MASK) | (iRounding << X86_FCW_RC_SHIFT);
2047 g_aFpuLdConst[iFn].pfn(&State, &Res);
2048 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s }, /* #%u */\n",
2049 State.FCW, State.FSW, Res.FSW, GenFormatR80(&Res.r80Result), iTest + iRounding);
2050 }
2051 }
2052 GenerateArrayEnd(pOut, g_aFpuLdConst[iFn].pszName);
2053 }
2054}
2055#endif
2056
2057static void FpuLoadConstTest(void)
2058{
2059 /*
2060 * Inputs:
2061 * - FSW: C0, C1, C2, C3
2062 * - FCW: Exception masks, Precision control, Rounding control.
2063 *
2064 * C1 set to 1 on stack overflow, zero otherwise. C0, C2, and C3 are "undefined".
2065 */
2066 X86FXSTATE State;
2067 RT_ZERO(State);
2068 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuLdConst); iFn++)
2069 {
2070 RTTestSub(g_hTest, g_aFpuLdConst[iFn].pszName);
2071
2072 uint32_t const cTests = *g_aFpuLdConst[iFn].pcTests;
2073 FPU_LD_CONST_TEST_T const *paTests = g_aFpuLdConst[iFn].paTests;
2074 PFNIEMAIMPLFPUR80LDCONST pfn = g_aFpuLdConst[iFn].pfn;
2075 uint32_t const cVars = 1 + (g_aFpuLdConst[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && g_aFpuLdConst[iFn].pfnNative);
2076 if (!cTests) RTTestSkipped(g_hTest, "no tests");
2077 for (uint32_t iVar = 0; iVar < cVars; iVar++)
2078 {
2079 for (uint32_t iTest = 0; iTest < cTests; iTest++)
2080 {
2081 State.FCW = paTests[iTest].fFcw;
2082 State.FSW = paTests[iTest].fFswIn;
2083 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 };
2084 pfn(&State, &Res);
2085 if ( Res.FSW != paTests[iTest].fFswOut
2086 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult))
2087 RTTestFailed(g_hTest, "#%u%s: fcw=%#06x fsw=%#06x -> fsw=%#06x %s, expected %#06x %s%s%s (%s)\n",
2088 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
2089 Res.FSW, FormatR80(&Res.r80Result),
2090 paTests[iTest].fFswOut, FormatR80(&paTests[iTest].rdResult),
2091 FswDiff(Res.FSW, paTests[iTest].fFswOut),
2092 !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult) ? " - val" : "",
2093 FormatFcw(paTests[iTest].fFcw) );
2094 }
2095 pfn = g_aFpuLdConst[iFn].pfnNative;
2096 }
2097 }
2098}
2099
2100
2101/*
2102 * Load floating point values from memory.
2103 */
2104#ifdef TSTIEMAIMPL_WITH_GENERATOR
2105# define GEN_FPU_LOAD(a_cBits, a_rdTypeIn, a_aSubTests, a_TestType) \
2106static void FpuLdR ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
2107{ \
2108 X86FXSTATE State; \
2109 RT_ZERO(State); \
2110 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2111 { \
2112 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
2113 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
2114 { \
2115 State.FCW = RandFcw(); \
2116 State.FSW = RandFsw(); \
2117 a_rdTypeIn InVal = RandR ## a_cBits ## Src(iTest); \
2118 \
2119 for (uint16_t iRounding = 0; iRounding < 4; iRounding++) \
2120 { \
2121 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 }; \
2122 State.FCW = (State.FCW & ~X86_FCW_RC_MASK) | (iRounding << X86_FCW_RC_SHIFT); \
2123 a_aSubTests[iFn].pfn(&State, &Res, &InVal); \
2124 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u */\n", \
2125 State.FCW, State.FSW, Res.FSW, GenFormatR80(&Res.r80Result), \
2126 GenFormatR ## a_cBits(&InVal), iTest, iRounding); \
2127 } \
2128 } \
2129 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
2130 } \
2131}
2132#else
2133# define GEN_FPU_LOAD(a_cBits, a_rdTypeIn, a_aSubTests, a_TestType)
2134#endif
2135
2136#define TEST_FPU_LOAD(a_cBits, a_rdTypeIn, a_SubTestType, a_aSubTests, a_TestType) \
2137typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLFPULDR80FROM ## a_cBits,(PCX86FXSTATE, PIEMFPURESULT, PC ## a_rdTypeIn)); \
2138typedef FNIEMAIMPLFPULDR80FROM ## a_cBits *PFNIEMAIMPLFPULDR80FROM ## a_cBits; \
2139TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLFPULDR80FROM ## a_cBits); \
2140\
2141static const a_SubTestType a_aSubTests[] = \
2142{ \
2143 ENTRY(RT_CONCAT(fld_r80_from_r,a_cBits)) \
2144}; \
2145GEN_FPU_LOAD(a_cBits, a_rdTypeIn, a_aSubTests, a_TestType) \
2146\
2147static void FpuLdR ## a_cBits ## Test(void) \
2148{ \
2149 X86FXSTATE State; \
2150 RT_ZERO(State); \
2151 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2152 { \
2153 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
2154 \
2155 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
2156 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
2157 PFNIEMAIMPLFPULDR80FROM ## a_cBits pfn = a_aSubTests[iFn].pfn; \
2158 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
2159 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
2160 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
2161 { \
2162 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
2163 { \
2164 a_rdTypeIn const InVal = paTests[iTest].InVal; \
2165 State.FCW = paTests[iTest].fFcw; \
2166 State.FSW = paTests[iTest].fFswIn; \
2167 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 }; \
2168 pfn(&State, &Res, &InVal); \
2169 if ( Res.FSW != paTests[iTest].fFswOut \
2170 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult)) \
2171 RTTestFailed(g_hTest, "#%03u%s: fcw=%#06x fsw=%#06x in=%s\n" \
2172 "%s -> fsw=%#06x %s\n" \
2173 "%s expected %#06x %s%s%s (%s)\n", \
2174 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, \
2175 FormatR ## a_cBits(&paTests[iTest].InVal), \
2176 iVar ? " " : "", Res.FSW, FormatR80(&Res.r80Result), \
2177 iVar ? " " : "", paTests[iTest].fFswOut, FormatR80(&paTests[iTest].rdResult), \
2178 FswDiff(Res.FSW, paTests[iTest].fFswOut), \
2179 !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult) ? " - val" : "", \
2180 FormatFcw(paTests[iTest].fFcw) ); \
2181 } \
2182 pfn = a_aSubTests[iFn].pfnNative; \
2183 } \
2184 } \
2185}
2186
2187TEST_FPU_LOAD(80, RTFLOAT80U, FPU_LD_R80_T, g_aFpuLdR80, FPU_R80_IN_TEST_T)
2188TEST_FPU_LOAD(64, RTFLOAT64U, FPU_LD_R64_T, g_aFpuLdR64, FPU_R64_IN_TEST_T)
2189TEST_FPU_LOAD(32, RTFLOAT32U, FPU_LD_R32_T, g_aFpuLdR32, FPU_R32_IN_TEST_T)
2190
2191#ifdef TSTIEMAIMPL_WITH_GENERATOR
2192static void FpuLdMemGenerate(PRTSTREAM pOut, uint32_t cTests)
2193{
2194 FpuLdR80Generate(pOut, cTests);
2195 FpuLdR64Generate(pOut, cTests);
2196 FpuLdR32Generate(pOut, cTests);
2197}
2198#endif
2199
2200static void FpuLdMemTest(void)
2201{
2202 FpuLdR80Test();
2203 FpuLdR64Test();
2204 FpuLdR32Test();
2205}
2206
2207
2208/*
2209 * Load integer values from memory.
2210 */
2211#ifdef TSTIEMAIMPL_WITH_GENERATOR
2212# define GEN_FPU_LOAD_INT(a_cBits, a_iTypeIn, a_szFmtIn, a_aSubTests, a_TestType) \
2213static void FpuLdI ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
2214{ \
2215 X86FXSTATE State; \
2216 RT_ZERO(State); \
2217 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2218 { \
2219 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
2220 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
2221 { \
2222 State.FCW = RandFcw(); \
2223 State.FSW = RandFsw(); \
2224 a_iTypeIn InVal = (a_iTypeIn)RandU ## a_cBits ## Src(iTest); \
2225 \
2226 for (uint16_t iRounding = 0; iRounding < 4; iRounding++) \
2227 { \
2228 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 }; \
2229 State.FCW = (State.FCW & ~X86_FCW_RC_MASK) | (iRounding << X86_FCW_RC_SHIFT); \
2230 a_aSubTests[iFn].pfn(&State, &Res, &InVal); \
2231 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, " a_szFmtIn " }, /* #%u/%u */\n", \
2232 State.FCW, State.FSW, Res.FSW, GenFormatR80(&Res.r80Result), InVal, iTest, iRounding); \
2233 } \
2234 } \
2235 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
2236 } \
2237}
2238#else
2239# define GEN_FPU_LOAD_INT(a_cBits, a_iTypeIn, a_szFmtIn, a_aSubTests, a_TestType)
2240#endif
2241
2242#define TEST_FPU_LOAD_INT(a_cBits, a_iTypeIn, a_szFmtIn, a_SubTestType, a_aSubTests, a_TestType) \
2243typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLFPULDR80FROMI ## a_cBits,(PCX86FXSTATE, PIEMFPURESULT, a_iTypeIn const *)); \
2244typedef FNIEMAIMPLFPULDR80FROMI ## a_cBits *PFNIEMAIMPLFPULDR80FROMI ## a_cBits; \
2245TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLFPULDR80FROMI ## a_cBits); \
2246\
2247static const a_SubTestType a_aSubTests[] = \
2248{ \
2249 ENTRY(RT_CONCAT(fild_r80_from_i,a_cBits)) \
2250}; \
2251GEN_FPU_LOAD_INT(a_cBits, a_iTypeIn, a_szFmtIn, a_aSubTests, a_TestType) \
2252\
2253static void FpuLdI ## a_cBits ## Test(void) \
2254{ \
2255 X86FXSTATE State; \
2256 RT_ZERO(State); \
2257 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2258 { \
2259 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
2260 \
2261 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
2262 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
2263 PFNIEMAIMPLFPULDR80FROMI ## a_cBits pfn = a_aSubTests[iFn].pfn; \
2264 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
2265 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
2266 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
2267 { \
2268 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
2269 { \
2270 a_iTypeIn const iInVal = paTests[iTest].iInVal; \
2271 State.FCW = paTests[iTest].fFcw; \
2272 State.FSW = paTests[iTest].fFswIn; \
2273 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 }; \
2274 pfn(&State, &Res, &iInVal); \
2275 if ( Res.FSW != paTests[iTest].fFswOut \
2276 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult)) \
2277 RTTestFailed(g_hTest, "#%03u%s: fcw=%#06x fsw=%#06x in=" a_szFmtIn "\n" \
2278 "%s -> fsw=%#06x %s\n" \
2279 "%s expected %#06x %s%s%s (%s)\n", \
2280 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, paTests[iTest].iInVal, \
2281 iVar ? " " : "", Res.FSW, FormatR80(&Res.r80Result), \
2282 iVar ? " " : "", paTests[iTest].fFswOut, FormatR80(&paTests[iTest].rdResult), \
2283 FswDiff(Res.FSW, paTests[iTest].fFswOut), \
2284 !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult) ? " - val" : "", \
2285 FormatFcw(paTests[iTest].fFcw) ); \
2286 } \
2287 pfn = a_aSubTests[iFn].pfnNative; \
2288 } \
2289 } \
2290}
2291
2292TEST_FPU_LOAD_INT(64, int64_t, "%RI64", FPU_LD_I64_T, g_aFpuLdU64, FPU_I64_IN_TEST_T)
2293TEST_FPU_LOAD_INT(32, int32_t, "%RI32", FPU_LD_I32_T, g_aFpuLdU32, FPU_I32_IN_TEST_T)
2294TEST_FPU_LOAD_INT(16, int16_t, "%RI16", FPU_LD_I16_T, g_aFpuLdU16, FPU_I16_IN_TEST_T)
2295
2296#ifdef TSTIEMAIMPL_WITH_GENERATOR
2297static void FpuLdIntGenerate(PRTSTREAM pOut, uint32_t cTests)
2298{
2299 FpuLdI64Generate(pOut, cTests);
2300 FpuLdI32Generate(pOut, cTests);
2301 FpuLdI16Generate(pOut, cTests);
2302}
2303#endif
2304
2305static void FpuLdIntTest(void)
2306{
2307 FpuLdI64Test();
2308 FpuLdI32Test();
2309 FpuLdI16Test();
2310}
2311
2312
2313/*
2314 * Load binary coded decimal values from memory.
2315 */
2316typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLFPULDR80FROMD80,(PCX86FXSTATE, PIEMFPURESULT, PCRTPBCD80U));
2317typedef FNIEMAIMPLFPULDR80FROMD80 *PFNIEMAIMPLFPULDR80FROMD80;
2318TYPEDEF_SUBTEST_TYPE(FPU_LD_D80_T, FPU_D80_IN_TEST_T, PFNIEMAIMPLFPULDR80FROMD80);
2319
2320static const FPU_LD_D80_T g_aFpuLdD80[] =
2321{
2322 ENTRY(fld_r80_from_d80)
2323};
2324
2325#ifdef TSTIEMAIMPL_WITH_GENERATOR
2326static void FpuLdD80Generate(PRTSTREAM pOut, uint32_t cTests)
2327{
2328 X86FXSTATE State;
2329 RT_ZERO(State);
2330 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuLdD80); iFn++)
2331 {
2332 GenerateArrayStart(pOut, g_aFpuLdD80[iFn].pszName, "FPU_D80_IN_TEST_T");
2333 for (uint32_t iTest = 0; iTest < cTests; iTest++)
2334 {
2335 State.FCW = RandFcw();
2336 State.FSW = RandFsw();
2337 RTPBCD80U InVal = RandD80Src(iTest);
2338
2339 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
2340 {
2341 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 };
2342 State.FCW = (State.FCW & ~X86_FCW_RC_MASK) | (iRounding << X86_FCW_RC_SHIFT);
2343 g_aFpuLdD80[iFn].pfn(&State, &Res, &InVal);
2344 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u */\n",
2345 State.FCW, State.FSW, Res.FSW, GenFormatR80(&Res.r80Result), GenFormatD80(&InVal),
2346 iTest, iRounding);
2347 }
2348 }
2349 GenerateArrayEnd(pOut, g_aFpuLdD80[iFn].pszName);
2350 }
2351}
2352#endif
2353
2354static void FpuLdD80Test(void)
2355{
2356 X86FXSTATE State;
2357 RT_ZERO(State);
2358 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuLdD80); iFn++)
2359 {
2360 RTTestSub(g_hTest, g_aFpuLdD80[iFn].pszName);
2361
2362 uint32_t const cTests = *g_aFpuLdD80[iFn].pcTests;
2363 FPU_D80_IN_TEST_T const * const paTests = g_aFpuLdD80[iFn].paTests;
2364 PFNIEMAIMPLFPULDR80FROMD80 pfn = g_aFpuLdD80[iFn].pfn;
2365 uint32_t const cVars = 1 + (g_aFpuLdD80[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && g_aFpuLdD80[iFn].pfnNative);
2366 if (!cTests) RTTestSkipped(g_hTest, "no tests");
2367 for (uint32_t iVar = 0; iVar < cVars; iVar++)
2368 {
2369 for (uint32_t iTest = 0; iTest < cTests; iTest++)
2370 {
2371 RTPBCD80U const InVal = paTests[iTest].InVal;
2372 State.FCW = paTests[iTest].fFcw;
2373 State.FSW = paTests[iTest].fFswIn;
2374 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 };
2375 pfn(&State, &Res, &InVal);
2376 if ( Res.FSW != paTests[iTest].fFswOut
2377 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult))
2378 RTTestFailed(g_hTest, "#%03u%s: fcw=%#06x fsw=%#06x in=%s\n"
2379 "%s -> fsw=%#06x %s\n"
2380 "%s expected %#06x %s%s%s (%s)\n",
2381 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
2382 FormatD80(&paTests[iTest].InVal),
2383 iVar ? " " : "", Res.FSW, FormatR80(&Res.r80Result),
2384 iVar ? " " : "", paTests[iTest].fFswOut, FormatR80(&paTests[iTest].rdResult),
2385 FswDiff(Res.FSW, paTests[iTest].fFswOut),
2386 !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult) ? " - val" : "",
2387 FormatFcw(paTests[iTest].fFcw) );
2388 }
2389 pfn = g_aFpuLdD80[iFn].pfnNative;
2390 }
2391 }
2392}
2393
2394
2395/*
2396 * Store values floating point values to memory.
2397 */
2398#ifdef TSTIEMAIMPL_WITH_GENERATOR
2399static const RTFLOAT80U g_aFpuStR32Specials[] =
2400{
2401 RTFLOAT80U_INIT_C(0, 0xffffff8000000000, RTFLOAT80U_EXP_BIAS), /* near rounding with carry */
2402 RTFLOAT80U_INIT_C(1, 0xffffff8000000000, RTFLOAT80U_EXP_BIAS), /* near rounding with carry */
2403 RTFLOAT80U_INIT_C(0, 0xfffffe8000000000, RTFLOAT80U_EXP_BIAS), /* near rounding */
2404 RTFLOAT80U_INIT_C(1, 0xfffffe8000000000, RTFLOAT80U_EXP_BIAS), /* near rounding */
2405};
2406static const RTFLOAT80U g_aFpuStR64Specials[] =
2407{
2408 RTFLOAT80U_INIT_C(0, 0xfffffffffffffc00, RTFLOAT80U_EXP_BIAS), /* near rounding with carry */
2409 RTFLOAT80U_INIT_C(1, 0xfffffffffffffc00, RTFLOAT80U_EXP_BIAS), /* near rounding with carry */
2410 RTFLOAT80U_INIT_C(0, 0xfffffffffffff400, RTFLOAT80U_EXP_BIAS), /* near rounding */
2411 RTFLOAT80U_INIT_C(1, 0xfffffffffffff400, RTFLOAT80U_EXP_BIAS), /* near rounding */
2412 RTFLOAT80U_INIT_C(0, 0xd0b9e6fdda887400, 687 + RTFLOAT80U_EXP_BIAS), /* random example for this */
2413};
2414static const RTFLOAT80U g_aFpuStR80Specials[] =
2415{
2416 RTFLOAT80U_INIT_C(0, 0x8000000000000000, RTFLOAT80U_EXP_BIAS), /* placeholder */
2417};
2418# define GEN_FPU_STORE(a_cBits, a_rdType, a_aSubTests, a_TestType) \
2419static void FpuStR ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
2420{ \
2421 uint32_t const cTotalTests = cTests + RT_ELEMENTS(g_aFpuStR ## a_cBits ## Specials); \
2422 X86FXSTATE State; \
2423 RT_ZERO(State); \
2424 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2425 { \
2426 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
2427 for (uint32_t iTest = 0; iTest < cTotalTests; iTest++) \
2428 { \
2429 uint16_t const fFcw = RandFcw(); \
2430 State.FSW = RandFsw(); \
2431 RTFLOAT80U const InVal = iTest < cTests ? RandR80Src(iTest) : g_aFpuStR ## a_cBits ## Specials[iTest - cTests]; \
2432 \
2433 for (uint16_t iRounding = 0; iRounding < 4; iRounding++) \
2434 { \
2435 /* PC doesn't influence these, so leave as is. */ \
2436 AssertCompile(X86_FCW_OM_BIT + 1 == X86_FCW_UM_BIT && X86_FCW_UM_BIT + 1 == X86_FCW_PM_BIT); \
2437 for (uint16_t iMask = 0; iMask < 16; iMask += 2 /*1*/) \
2438 { \
2439 uint16_t uFswOut = 0; \
2440 a_rdType OutVal; \
2441 RT_ZERO(OutVal); \
2442 memset(&OutVal, 0xfe, sizeof(OutVal)); \
2443 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_OM | X86_FCW_UM | X86_FCW_PM)) \
2444 | (iRounding << X86_FCW_RC_SHIFT); \
2445 /*if (iMask & 1) State.FCW ^= X86_FCW_MASK_ALL;*/ \
2446 State.FCW |= (iMask >> 1) << X86_FCW_OM_BIT; \
2447 a_aSubTests[iFn].pfn(&State, &uFswOut, &OutVal, &InVal); \
2448 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u/%u */\n", \
2449 State.FCW, State.FSW, uFswOut, GenFormatR80(&InVal), \
2450 GenFormatR ## a_cBits(&OutVal), iTest, iRounding, iMask); \
2451 } \
2452 } \
2453 } \
2454 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
2455 } \
2456}
2457#else
2458# define GEN_FPU_STORE(a_cBits, a_rdType, a_aSubTests, a_TestType)
2459#endif
2460
2461#define TEST_FPU_STORE(a_cBits, a_rdType, a_SubTestType, a_aSubTests, a_TestType) \
2462typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLFPUSTR80TOR ## a_cBits,(PCX86FXSTATE, uint16_t *, \
2463 PRTFLOAT ## a_cBits ## U, PCRTFLOAT80U)); \
2464typedef FNIEMAIMPLFPUSTR80TOR ## a_cBits *PFNIEMAIMPLFPUSTR80TOR ## a_cBits; \
2465TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLFPUSTR80TOR ## a_cBits); \
2466\
2467static const a_SubTestType a_aSubTests[] = \
2468{ \
2469 ENTRY(RT_CONCAT(fst_r80_to_r,a_cBits)) \
2470}; \
2471GEN_FPU_STORE(a_cBits, a_rdType, a_aSubTests, a_TestType) \
2472\
2473static void FpuStR ## a_cBits ## Test(void) \
2474{ \
2475 X86FXSTATE State; \
2476 RT_ZERO(State); \
2477 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2478 { \
2479 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
2480 \
2481 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
2482 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
2483 PFNIEMAIMPLFPUSTR80TOR ## a_cBits pfn = a_aSubTests[iFn].pfn; \
2484 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
2485 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
2486 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
2487 { \
2488 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
2489 { \
2490 RTFLOAT80U const InVal = paTests[iTest].InVal; \
2491 uint16_t uFswOut = 0; \
2492 a_rdType OutVal; \
2493 RT_ZERO(OutVal); \
2494 memset(&OutVal, 0xfe, sizeof(OutVal)); \
2495 State.FCW = paTests[iTest].fFcw; \
2496 State.FSW = paTests[iTest].fFswIn; \
2497 pfn(&State, &uFswOut, &OutVal, &InVal); \
2498 if ( uFswOut != paTests[iTest].fFswOut \
2499 || !RTFLOAT ## a_cBits ## U_ARE_IDENTICAL(&OutVal, &paTests[iTest].OutVal)) \
2500 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in=%s\n" \
2501 "%s -> fsw=%#06x %s\n" \
2502 "%s expected %#06x %s%s%s (%s)\n", \
2503 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, \
2504 FormatR80(&paTests[iTest].InVal), \
2505 iVar ? " " : "", uFswOut, FormatR ## a_cBits(&OutVal), \
2506 iVar ? " " : "", paTests[iTest].fFswOut, FormatR ## a_cBits(&paTests[iTest].OutVal), \
2507 FswDiff(uFswOut, paTests[iTest].fFswOut), \
2508 !RTFLOAT ## a_cBits ## U_ARE_IDENTICAL(&OutVal, &paTests[iTest].OutVal) ? " - val" : "", \
2509 FormatFcw(paTests[iTest].fFcw) ); \
2510 } \
2511 pfn = a_aSubTests[iFn].pfnNative; \
2512 } \
2513 } \
2514}
2515
2516TEST_FPU_STORE(80, RTFLOAT80U, FPU_ST_R80_T, g_aFpuStR80, FPU_ST_R80_TEST_T)
2517TEST_FPU_STORE(64, RTFLOAT64U, FPU_ST_R64_T, g_aFpuStR64, FPU_ST_R64_TEST_T)
2518TEST_FPU_STORE(32, RTFLOAT32U, FPU_ST_R32_T, g_aFpuStR32, FPU_ST_R32_TEST_T)
2519
2520#ifdef TSTIEMAIMPL_WITH_GENERATOR
2521static void FpuStMemGenerate(PRTSTREAM pOut, uint32_t cTests)
2522{
2523 FpuStR80Generate(pOut, cTests);
2524 FpuStR64Generate(pOut, cTests);
2525 FpuStR32Generate(pOut, cTests);
2526}
2527#endif
2528
2529static void FpuStMemTest(void)
2530{
2531 FpuStR80Test();
2532 FpuStR64Test();
2533 FpuStR32Test();
2534}
2535
2536
2537/*
2538 * Store integer values to memory or register.
2539 */
2540#ifdef TSTIEMAIMPL_WITH_GENERATOR
2541static const RTFLOAT80U g_aFpuStI16Specials[] = /* 16-bit variant borrows properties from the 32-bit one, thus all this stuff. */
2542{
2543 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 13 + RTFLOAT80U_EXP_BIAS),
2544 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 13 + RTFLOAT80U_EXP_BIAS),
2545 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 14 + RTFLOAT80U_EXP_BIAS),
2546 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 14 + RTFLOAT80U_EXP_BIAS),
2547 RTFLOAT80U_INIT_C(0, 0x8000080000000000, 14 + RTFLOAT80U_EXP_BIAS),
2548 RTFLOAT80U_INIT_C(1, 0x8000080000000000, 14 + RTFLOAT80U_EXP_BIAS),
2549 RTFLOAT80U_INIT_C(0, 0x8000100000000000, 14 + RTFLOAT80U_EXP_BIAS),
2550 RTFLOAT80U_INIT_C(1, 0x8000100000000000, 14 + RTFLOAT80U_EXP_BIAS),
2551 RTFLOAT80U_INIT_C(0, 0x8000200000000000, 14 + RTFLOAT80U_EXP_BIAS),
2552 RTFLOAT80U_INIT_C(1, 0x8000200000000000, 14 + RTFLOAT80U_EXP_BIAS),
2553 RTFLOAT80U_INIT_C(0, 0x8000400000000000, 14 + RTFLOAT80U_EXP_BIAS),
2554 RTFLOAT80U_INIT_C(1, 0x8000400000000000, 14 + RTFLOAT80U_EXP_BIAS),
2555 RTFLOAT80U_INIT_C(0, 0x8000800000000000, 14 + RTFLOAT80U_EXP_BIAS),
2556 RTFLOAT80U_INIT_C(1, 0x8000800000000000, 14 + RTFLOAT80U_EXP_BIAS),
2557 RTFLOAT80U_INIT_C(1, 0x8000ffffffffffff, 14 + RTFLOAT80U_EXP_BIAS),
2558 RTFLOAT80U_INIT_C(0, 0x8001000000000000, 14 + RTFLOAT80U_EXP_BIAS),
2559 RTFLOAT80U_INIT_C(1, 0x8001000000000000, 14 + RTFLOAT80U_EXP_BIAS),
2560 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 14 + RTFLOAT80U_EXP_BIAS),
2561 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 14 + RTFLOAT80U_EXP_BIAS),
2562 RTFLOAT80U_INIT_C(0, 0xffff800000000000, 14 + RTFLOAT80U_EXP_BIAS),
2563 RTFLOAT80U_INIT_C(0, 0xffff000000000000, 14 + RTFLOAT80U_EXP_BIAS), /* overflow to min/nan */
2564 RTFLOAT80U_INIT_C(0, 0xfffe000000000000, 14 + RTFLOAT80U_EXP_BIAS),
2565 RTFLOAT80U_INIT_C(1, 0xffff800000000000, 14 + RTFLOAT80U_EXP_BIAS),
2566 RTFLOAT80U_INIT_C(1, 0xffff000000000000, 14 + RTFLOAT80U_EXP_BIAS), /* min */
2567 RTFLOAT80U_INIT_C(1, 0xfffe000000000000, 14 + RTFLOAT80U_EXP_BIAS),
2568 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 15 + RTFLOAT80U_EXP_BIAS),
2569 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 15 + RTFLOAT80U_EXP_BIAS),
2570 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 16 + RTFLOAT80U_EXP_BIAS),
2571 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 17 + RTFLOAT80U_EXP_BIAS),
2572 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 20 + RTFLOAT80U_EXP_BIAS),
2573 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 24 + RTFLOAT80U_EXP_BIAS),
2574 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 28 + RTFLOAT80U_EXP_BIAS),
2575 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 30 + RTFLOAT80U_EXP_BIAS),
2576 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 30 + RTFLOAT80U_EXP_BIAS),
2577 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 30 + RTFLOAT80U_EXP_BIAS),
2578 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 30 + RTFLOAT80U_EXP_BIAS),
2579 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 31 + RTFLOAT80U_EXP_BIAS),
2580 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 31 + RTFLOAT80U_EXP_BIAS),
2581 RTFLOAT80U_INIT_C(0, 0x8000000000000001, 31 + RTFLOAT80U_EXP_BIAS),
2582 RTFLOAT80U_INIT_C(1, 0x8000000000000001, 31 + RTFLOAT80U_EXP_BIAS),
2583 RTFLOAT80U_INIT_C(0, 0x8000ffffffffffff, 31 + RTFLOAT80U_EXP_BIAS),
2584 RTFLOAT80U_INIT_C(1, 0x8000ffffffffffff, 31 + RTFLOAT80U_EXP_BIAS),
2585 RTFLOAT80U_INIT_C(0, 0x8001000000000000, 31 + RTFLOAT80U_EXP_BIAS),
2586 RTFLOAT80U_INIT_C(1, 0x8001000000000000, 31 + RTFLOAT80U_EXP_BIAS),
2587 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 31 + RTFLOAT80U_EXP_BIAS),
2588 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 31 + RTFLOAT80U_EXP_BIAS),
2589 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 32 + RTFLOAT80U_EXP_BIAS),
2590};
2591static const RTFLOAT80U g_aFpuStI32Specials[] =
2592{
2593 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 30 + RTFLOAT80U_EXP_BIAS),
2594 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 30 + RTFLOAT80U_EXP_BIAS),
2595 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 30 + RTFLOAT80U_EXP_BIAS), /* overflow to min/nan */
2596 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 30 + RTFLOAT80U_EXP_BIAS), /* min */
2597 RTFLOAT80U_INIT_C(0, 0xffffffff80000000, 30 + RTFLOAT80U_EXP_BIAS), /* overflow to min/nan */
2598 RTFLOAT80U_INIT_C(1, 0xffffffff80000000, 30 + RTFLOAT80U_EXP_BIAS), /* min */
2599 RTFLOAT80U_INIT_C(0, 0xffffffff00000000, 30 + RTFLOAT80U_EXP_BIAS), /* overflow to min/nan */
2600 RTFLOAT80U_INIT_C(1, 0xffffffff00000000, 30 + RTFLOAT80U_EXP_BIAS), /* min */
2601 RTFLOAT80U_INIT_C(0, 0xfffffffe00000000, 30 + RTFLOAT80U_EXP_BIAS),
2602 RTFLOAT80U_INIT_C(1, 0xfffffffe00000000, 30 + RTFLOAT80U_EXP_BIAS),
2603 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 31 + RTFLOAT80U_EXP_BIAS),
2604 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 31 + RTFLOAT80U_EXP_BIAS),
2605 RTFLOAT80U_INIT_C(0, 0x8000000000000001, 31 + RTFLOAT80U_EXP_BIAS),
2606 RTFLOAT80U_INIT_C(1, 0x8000000000000001, 31 + RTFLOAT80U_EXP_BIAS),
2607 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 31 + RTFLOAT80U_EXP_BIAS),
2608 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 31 + RTFLOAT80U_EXP_BIAS),
2609};
2610static const RTFLOAT80U g_aFpuStI64Specials[] =
2611{
2612 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 61 + RTFLOAT80U_EXP_BIAS),
2613 RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, 61 + RTFLOAT80U_EXP_BIAS),
2614 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 62 + RTFLOAT80U_EXP_BIAS),
2615 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 62 + RTFLOAT80U_EXP_BIAS),
2616 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 62 + RTFLOAT80U_EXP_BIAS),
2617 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 62 + RTFLOAT80U_EXP_BIAS),
2618 RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, 62 + RTFLOAT80U_EXP_BIAS), /* overflow to min/nan */
2619 RTFLOAT80U_INIT_C(1, 0xffffffffffffffff, 62 + RTFLOAT80U_EXP_BIAS), /* min */
2620 RTFLOAT80U_INIT_C(0, 0xfffffffffffffffe, 62 + RTFLOAT80U_EXP_BIAS),
2621 RTFLOAT80U_INIT_C(1, 0xfffffffffffffffe, 62 + RTFLOAT80U_EXP_BIAS),
2622 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 63 + RTFLOAT80U_EXP_BIAS),
2623 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 63 + RTFLOAT80U_EXP_BIAS),
2624 RTFLOAT80U_INIT_C(0, 0x8000000000000001, 63 + RTFLOAT80U_EXP_BIAS),
2625 RTFLOAT80U_INIT_C(1, 0x8000000000000001, 63 + RTFLOAT80U_EXP_BIAS),
2626 RTFLOAT80U_INIT_C(0, 0x8000000000000002, 63 + RTFLOAT80U_EXP_BIAS),
2627 RTFLOAT80U_INIT_C(1, 0x8000000000000002, 63 + RTFLOAT80U_EXP_BIAS),
2628 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 63 + RTFLOAT80U_EXP_BIAS),
2629};
2630
2631# define GEN_FPU_STORE_INT(a_cBits, a_iType, a_szFmt, a_aSubTests, a_TestType) \
2632static void FpuStI ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
2633{ \
2634 X86FXSTATE State; \
2635 RT_ZERO(State); \
2636 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2637 { \
2638 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
2639 uint32_t const cTotalTests = cTests + RT_ELEMENTS(g_aFpuStI ## a_cBits ## Specials); \
2640 for (uint32_t iTest = 0; iTest < cTotalTests; iTest++) \
2641 { \
2642 uint16_t const fFcw = RandFcw(); \
2643 State.FSW = RandFsw(); \
2644 RTFLOAT80U const InVal = iTest < cTests ? RandR80Ex(a_cBits, true) \
2645 : g_aFpuStI ## a_cBits ## Specials[iTest - cTests]; \
2646 \
2647 for (uint16_t iRounding = 0; iRounding < 4; iRounding++) \
2648 { \
2649 /* PC doesn't influence these, so leave as is. */ \
2650 AssertCompile(X86_FCW_OM_BIT + 1 == X86_FCW_UM_BIT && X86_FCW_UM_BIT + 1 == X86_FCW_PM_BIT); \
2651 for (uint16_t iMask = 0; iMask < 16; iMask += 2 /*1*/) \
2652 { \
2653 uint16_t uFswOut = 0; \
2654 a_iType iOutVal = ~(a_iType)2; \
2655 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_OM | X86_FCW_UM | X86_FCW_PM)) \
2656 | (iRounding << X86_FCW_RC_SHIFT); \
2657 /*if (iMask & 1) State.FCW ^= X86_FCW_MASK_ALL;*/ \
2658 State.FCW |= (iMask >> 1) << X86_FCW_OM_BIT; \
2659 a_aSubTests[iFn].pfn(&State, &uFswOut, &iOutVal, &InVal); \
2660 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u/%u */\n", \
2661 State.FCW, State.FSW, uFswOut, GenFormatR80(&InVal), \
2662 GenFormatI ## a_cBits(iOutVal), iTest, iRounding, iMask); \
2663 } \
2664 } \
2665 } \
2666 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
2667 } \
2668}
2669#else
2670# define GEN_FPU_STORE_INT(a_cBits, a_iType, a_szFmt, a_aSubTests, a_TestType)
2671#endif
2672
2673#define TEST_FPU_STORE_INT(a_cBits, a_iType, a_szFmt, a_SubTestType, a_aSubTests, a_TestType) \
2674typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLFPUSTR80TOI ## a_cBits,(PCX86FXSTATE, uint16_t *, a_iType *, PCRTFLOAT80U)); \
2675typedef FNIEMAIMPLFPUSTR80TOI ## a_cBits *PFNIEMAIMPLFPUSTR80TOI ## a_cBits; \
2676TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLFPUSTR80TOI ## a_cBits); \
2677\
2678static const a_SubTestType a_aSubTests[] = \
2679{ \
2680 ENTRY(RT_CONCAT(fist_r80_to_i,a_cBits)), \
2681 ENTRY(RT_CONCAT(fistt_r80_to_i,a_cBits)) \
2682}; \
2683GEN_FPU_STORE_INT(a_cBits, a_iType, a_szFmt, a_aSubTests, a_TestType) \
2684\
2685static void FpuStI ## a_cBits ## Test(void) \
2686{ \
2687 X86FXSTATE State; \
2688 RT_ZERO(State); \
2689 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2690 { \
2691 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
2692 \
2693 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
2694 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
2695 PFNIEMAIMPLFPUSTR80TOI ## a_cBits pfn = a_aSubTests[iFn].pfn; \
2696 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
2697 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
2698 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
2699 { \
2700 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
2701 { \
2702 RTFLOAT80U const InVal = paTests[iTest].InVal; \
2703 uint16_t uFswOut = 0; \
2704 a_iType iOutVal = ~(a_iType)2; \
2705 State.FCW = paTests[iTest].fFcw; \
2706 State.FSW = paTests[iTest].fFswIn; \
2707 pfn(&State, &uFswOut, &iOutVal, &InVal); \
2708 if ( uFswOut != paTests[iTest].fFswOut \
2709 || iOutVal != paTests[iTest].iOutVal) \
2710 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in=%s\n" \
2711 "%s -> fsw=%#06x " a_szFmt "\n" \
2712 "%s expected %#06x " a_szFmt "%s%s (%s)\n", \
2713 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, \
2714 FormatR80(&paTests[iTest].InVal), \
2715 iVar ? " " : "", uFswOut, iOutVal, \
2716 iVar ? " " : "", paTests[iTest].fFswOut, paTests[iTest].iOutVal, \
2717 FswDiff(uFswOut, paTests[iTest].fFswOut), \
2718 iOutVal != paTests[iTest].iOutVal ? " - val" : "", FormatFcw(paTests[iTest].fFcw) ); \
2719 } \
2720 pfn = a_aSubTests[iFn].pfnNative; \
2721 } \
2722 } \
2723}
2724
2725TEST_FPU_STORE_INT(64, int64_t, "%RI64", FPU_ST_I64_T, g_aFpuStI64, FPU_ST_I64_TEST_T)
2726TEST_FPU_STORE_INT(32, int32_t, "%RI32", FPU_ST_I32_T, g_aFpuStI32, FPU_ST_I32_TEST_T)
2727TEST_FPU_STORE_INT(16, int16_t, "%RI16", FPU_ST_I16_T, g_aFpuStI16, FPU_ST_I16_TEST_T)
2728
2729#ifdef TSTIEMAIMPL_WITH_GENERATOR
2730static void FpuStIntGenerate(PRTSTREAM pOut, uint32_t cTests)
2731{
2732 FpuStI64Generate(pOut, cTests);
2733 FpuStI32Generate(pOut, cTests);
2734 FpuStI16Generate(pOut, cTests);
2735}
2736#endif
2737
2738static void FpuStIntTest(void)
2739{
2740 FpuStI64Test();
2741 FpuStI32Test();
2742 FpuStI16Test();
2743}
2744
2745
2746/*
2747 * Store as packed BCD value (memory).
2748 */
2749typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLFPUSTR80TOD80,(PCX86FXSTATE, uint16_t *, PRTPBCD80U, PCRTFLOAT80U));
2750typedef FNIEMAIMPLFPUSTR80TOD80 *PFNIEMAIMPLFPUSTR80TOD80;
2751TYPEDEF_SUBTEST_TYPE(FPU_ST_D80_T, FPU_ST_D80_TEST_T, PFNIEMAIMPLFPUSTR80TOD80);
2752
2753static const FPU_ST_D80_T g_aFpuStD80[] =
2754{
2755 ENTRY(fst_r80_to_d80),
2756};
2757
2758#ifdef TSTIEMAIMPL_WITH_GENERATOR
2759static void FpuStD80Generate(PRTSTREAM pOut, uint32_t cTests)
2760{
2761 static RTFLOAT80U const s_aSpecials[] =
2762 {
2763 RTFLOAT80U_INIT_C(0, 0xde0b6b3a763fffe0, RTFLOAT80U_EXP_BIAS + 59), /* 1 below max */
2764 RTFLOAT80U_INIT_C(1, 0xde0b6b3a763fffe0, RTFLOAT80U_EXP_BIAS + 59), /* 1 above min */
2765 RTFLOAT80U_INIT_C(0, 0xde0b6b3a763ffff0, RTFLOAT80U_EXP_BIAS + 59), /* exact max */
2766 RTFLOAT80U_INIT_C(1, 0xde0b6b3a763ffff0, RTFLOAT80U_EXP_BIAS + 59), /* exact min */
2767 RTFLOAT80U_INIT_C(0, 0xde0b6b3a763fffff, RTFLOAT80U_EXP_BIAS + 59), /* max & all rounded off bits set */
2768 RTFLOAT80U_INIT_C(1, 0xde0b6b3a763fffff, RTFLOAT80U_EXP_BIAS + 59), /* min & all rounded off bits set */
2769 RTFLOAT80U_INIT_C(0, 0xde0b6b3a763ffff8, RTFLOAT80U_EXP_BIAS + 59), /* max & some rounded off bits set */
2770 RTFLOAT80U_INIT_C(1, 0xde0b6b3a763ffff8, RTFLOAT80U_EXP_BIAS + 59), /* min & some rounded off bits set */
2771 RTFLOAT80U_INIT_C(0, 0xde0b6b3a763ffff1, RTFLOAT80U_EXP_BIAS + 59), /* max & some other rounded off bits set */
2772 RTFLOAT80U_INIT_C(1, 0xde0b6b3a763ffff1, RTFLOAT80U_EXP_BIAS + 59), /* min & some other rounded off bits set */
2773 RTFLOAT80U_INIT_C(0, 0xde0b6b3a76400000, RTFLOAT80U_EXP_BIAS + 59), /* 1 above max */
2774 RTFLOAT80U_INIT_C(1, 0xde0b6b3a76400000, RTFLOAT80U_EXP_BIAS + 59), /* 1 below min */
2775 };
2776
2777 X86FXSTATE State;
2778 RT_ZERO(State);
2779 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuStD80); iFn++)
2780 {
2781 GenerateArrayStart(pOut, g_aFpuStD80[iFn].pszName, "FPU_ST_D80_TEST_T");
2782 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
2783 {
2784 uint16_t const fFcw = RandFcw();
2785 State.FSW = RandFsw();
2786 RTFLOAT80U const InVal = iTest < cTests ? RandR80Ex(59, true) : s_aSpecials[iTest - cTests];
2787
2788 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
2789 {
2790 /* PC doesn't influence these, so leave as is. */
2791 AssertCompile(X86_FCW_OM_BIT + 1 == X86_FCW_UM_BIT && X86_FCW_UM_BIT + 1 == X86_FCW_PM_BIT);
2792 for (uint16_t iMask = 0; iMask < 16; iMask += 2 /*1*/)
2793 {
2794 uint16_t uFswOut = 0;
2795 RTPBCD80U OutVal = RTPBCD80U_INIT_ZERO(0);
2796 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_OM | X86_FCW_UM | X86_FCW_PM))
2797 | (iRounding << X86_FCW_RC_SHIFT);
2798 /*if (iMask & 1) State.FCW ^= X86_FCW_MASK_ALL;*/
2799 State.FCW |= (iMask >> 1) << X86_FCW_OM_BIT;
2800 g_aFpuStD80[iFn].pfn(&State, &uFswOut, &OutVal, &InVal);
2801 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u/%u */\n",
2802 State.FCW, State.FSW, uFswOut, GenFormatR80(&InVal),
2803 GenFormatD80(&OutVal), iTest, iRounding, iMask);
2804 }
2805 }
2806 }
2807 GenerateArrayEnd(pOut, g_aFpuStD80[iFn].pszName);
2808 }
2809}
2810#endif
2811
2812
2813static void FpuStD80Test(void)
2814{
2815 X86FXSTATE State;
2816 RT_ZERO(State);
2817 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuStD80); iFn++)
2818 {
2819 RTTestSub(g_hTest, g_aFpuStD80[iFn].pszName);
2820
2821 uint32_t const cTests = *g_aFpuStD80[iFn].pcTests;
2822 FPU_ST_D80_TEST_T const * const paTests = g_aFpuStD80[iFn].paTests;
2823 PFNIEMAIMPLFPUSTR80TOD80 pfn = g_aFpuStD80[iFn].pfn;
2824 uint32_t const cVars = 1 + (g_aFpuStD80[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && g_aFpuStD80[iFn].pfnNative);
2825 if (!cTests) RTTestSkipped(g_hTest, "no tests");
2826 for (uint32_t iVar = 0; iVar < cVars; iVar++)
2827 {
2828 for (uint32_t iTest = 0; iTest < cTests; iTest++)
2829 {
2830 RTFLOAT80U const InVal = paTests[iTest].InVal;
2831 uint16_t uFswOut = 0;
2832 RTPBCD80U OutVal = RTPBCD80U_INIT_ZERO(0);
2833 State.FCW = paTests[iTest].fFcw;
2834 State.FSW = paTests[iTest].fFswIn;
2835 pfn(&State, &uFswOut, &OutVal, &InVal);
2836 if ( uFswOut != paTests[iTest].fFswOut
2837 || !RTPBCD80U_ARE_IDENTICAL(&OutVal, &paTests[iTest].OutVal))
2838 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in=%s\n"
2839 "%s -> fsw=%#06x %s\n"
2840 "%s expected %#06x %s%s%s (%s)\n",
2841 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
2842 FormatR80(&paTests[iTest].InVal),
2843 iVar ? " " : "", uFswOut, FormatD80(&OutVal),
2844 iVar ? " " : "", paTests[iTest].fFswOut, FormatD80(&paTests[iTest].OutVal),
2845 FswDiff(uFswOut, paTests[iTest].fFswOut),
2846 RTPBCD80U_ARE_IDENTICAL(&OutVal, &paTests[iTest].OutVal) ? " - val" : "",
2847 FormatFcw(paTests[iTest].fFcw) );
2848 }
2849 pfn = g_aFpuStD80[iFn].pfnNative;
2850 }
2851 }
2852}
2853
2854
2855
2856/*********************************************************************************************************************************
2857* x87 FPU Binary Operations *
2858*********************************************************************************************************************************/
2859
2860/*
2861 * Binary FPU operations on two 80-bit floating point values.
2862 */
2863TYPEDEF_SUBTEST_TYPE(FPU_BINARY_R80_T, FPU_BINARY_R80_TEST_T, PFNIEMAIMPLFPUR80);
2864
2865static const FPU_BINARY_R80_T g_aFpuBinaryR80[] =
2866{
2867 ENTRY(fadd_r80_by_r80),
2868 ENTRY(fsub_r80_by_r80),
2869 ENTRY(fsubr_r80_by_r80),
2870 ENTRY(fmul_r80_by_r80),
2871 ENTRY(fdiv_r80_by_r80),
2872 ENTRY(fdivr_r80_by_r80),
2873 ENTRY(fprem_r80_by_r80),
2874 ENTRY(fprem1_r80_by_r80),
2875 ENTRY(fscale_r80_by_r80),
2876 ENTRY(fpatan_r80_by_r80),
2877 ENTRY(fyl2x_r80_by_r80),
2878 ENTRY(fyl2xp1_r80_by_r80),
2879};
2880
2881#ifdef TSTIEMAIMPL_WITH_GENERATOR
2882static void FpuBinaryR80Generate(PRTSTREAM pOut, uint32_t cTests)
2883{
2884 static struct { RTFLOAT80U Val1, Val2; } const s_aSpecials[] =
2885 {
2886 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
2887 RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS) }, /* whatever */
2888 };
2889
2890 X86FXSTATE State;
2891 RT_ZERO(State);
2892 uint32_t cMinNormalPairs = cTests / 4;
2893 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuBinaryR80); iFn++)
2894 {
2895 GenerateArrayStart(pOut, g_aFpuBinaryR80[iFn].pszName, "FPU_BINARY_R80_TEST_T");
2896 uint32_t cNormalInputPairs = 0;
2897 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
2898 {
2899 RTFLOAT80U const InVal1 = iTest < cTests ? RandR80Ex() : s_aSpecials[iTest - cTests].Val1;
2900 RTFLOAT80U const InVal2 = iTest < cTests ? RandR80Ex() : s_aSpecials[iTest - cTests].Val2;
2901 if (RTFLOAT80U_IS_NORMAL(&InVal1) && RTFLOAT80U_IS_NORMAL(&InVal2))
2902 cNormalInputPairs++;
2903 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
2904 {
2905 iTest -= 1;
2906 continue;
2907 }
2908
2909 uint16_t const fFcw = RandFcw();
2910 State.FSW = RandFsw();
2911
2912 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
2913 {
2914 for (uint16_t iPrecision = 0; iPrecision < 4; iPrecision++)
2915 {
2916 for (uint16_t iMask = 0; iMask <= X86_FCW_MASK_ALL; iMask += X86_FCW_MASK_ALL)
2917 {
2918 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_PC_MASK | X86_FCW_MASK_ALL))
2919 | (iRounding << X86_FCW_RC_SHIFT)
2920 | (iPrecision << X86_FCW_PC_SHIFT)
2921 | iMask;
2922 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 };
2923 g_aFpuBinaryR80[iFn].pfn(&State, &Res, &InVal1, &InVal2);
2924 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/%c */\n",
2925 State.FCW, State.FSW, Res.FSW, GenFormatR80(&InVal1), GenFormatR80(&InVal2),
2926 GenFormatR80(&Res.r80Result), iTest, iRounding, iPrecision, iMask ? 'c' : 'u');
2927 }
2928 }
2929 }
2930 }
2931 GenerateArrayEnd(pOut, g_aFpuBinaryR80[iFn].pszName);
2932 }
2933}
2934#endif
2935
2936
2937static void FpuBinaryR80Test(void)
2938{
2939 X86FXSTATE State;
2940 RT_ZERO(State);
2941 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuBinaryR80); iFn++)
2942 {
2943 RTTestSub(g_hTest, g_aFpuBinaryR80[iFn].pszName);
2944
2945 uint32_t const cTests = *g_aFpuBinaryR80[iFn].pcTests;
2946 FPU_BINARY_R80_TEST_T const * const paTests = g_aFpuBinaryR80[iFn].paTests;
2947 PFNIEMAIMPLFPUR80 pfn = g_aFpuBinaryR80[iFn].pfn;
2948 uint32_t const cVars = 1 + (g_aFpuBinaryR80[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && g_aFpuBinaryR80[iFn].pfnNative);
2949 if (!cTests) RTTestSkipped(g_hTest, "no tests");
2950 for (uint32_t iVar = 0; iVar < cVars; iVar++)
2951 {
2952 for (uint32_t iTest = 0; iTest < cTests; iTest++)
2953 {
2954 RTFLOAT80U const InVal1 = paTests[iTest].InVal1;
2955 RTFLOAT80U const InVal2 = paTests[iTest].InVal2;
2956 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 };
2957 State.FCW = paTests[iTest].fFcw;
2958 State.FSW = paTests[iTest].fFswIn;
2959 pfn(&State, &Res, &InVal1, &InVal2);
2960 if ( Res.FSW != paTests[iTest].fFswOut
2961 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].OutVal))
2962 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in1=%s in2=%s\n"
2963 "%s -> fsw=%#06x %s\n"
2964 "%s expected %#06x %s%s%s (%s)\n",
2965 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
2966 FormatR80(&paTests[iTest].InVal1), FormatR80(&paTests[iTest].InVal2),
2967 iVar ? " " : "", Res.FSW, FormatR80(&Res.r80Result),
2968 iVar ? " " : "", paTests[iTest].fFswOut, FormatR80(&paTests[iTest].OutVal),
2969 FswDiff(Res.FSW, paTests[iTest].fFswOut),
2970 RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].OutVal) ? " - val" : "",
2971 FormatFcw(paTests[iTest].fFcw) );
2972 }
2973 pfn = g_aFpuBinaryR80[iFn].pfnNative;
2974 }
2975 }
2976}
2977
2978
2979/*
2980 * Binary FPU operations on one 80-bit floating point value and one 64-bit or 32-bit one.
2981 */
2982#ifdef TSTIEMAIMPL_WITH_GENERATOR
2983static struct { RTFLOAT80U Val1; RTFLOAT64U Val2; } const s_aFpuBinaryR64Specials[] =
2984{
2985 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
2986 RTFLOAT64U_INIT_C(0, 0xfeeeeddddcccc, RTFLOAT64U_EXP_BIAS) }, /* whatever */
2987};
2988static struct { RTFLOAT80U Val1; RTFLOAT32U Val2; } const s_aFpuBinaryR32Specials[] =
2989{
2990 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
2991 RTFLOAT32U_INIT_C(0, 0x7fffee, RTFLOAT32U_EXP_BIAS) }, /* whatever */
2992};
2993
2994# define GEN_FPU_BINARY_SMALL(a_cBits, a_rdType, a_aSubTests, a_TestType) \
2995static void FpuBinaryR ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
2996{ \
2997 X86FXSTATE State; \
2998 RT_ZERO(State); \
2999 uint32_t cMinNormalPairs = cTests / 4; \
3000 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
3001 { \
3002 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
3003 uint32_t cNormalInputPairs = 0; \
3004 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aFpuBinaryR ## a_cBits ## Specials); iTest += 1) \
3005 { \
3006 RTFLOAT80U const InVal1 = iTest < cTests ? RandR80Ex() \
3007 : s_aFpuBinaryR ## a_cBits ## Specials[iTest - cTests].Val1; \
3008 a_rdType const InVal2 = iTest < cTests ? RandR ## a_cBits ## Src(a_cBits) \
3009 : s_aFpuBinaryR ## a_cBits ## Specials[iTest - cTests].Val2; \
3010 if (RTFLOAT80U_IS_NORMAL(&InVal1) && a_rdType ## _IS_NORMAL(&InVal2)) \
3011 cNormalInputPairs++; \
3012 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests) \
3013 { \
3014 iTest -= 1; \
3015 continue; \
3016 } \
3017 \
3018 uint16_t const fFcw = RandFcw(); \
3019 State.FSW = RandFsw(); \
3020 \
3021 for (uint16_t iRounding = 0; iRounding < 4; iRounding++) \
3022 { \
3023 for (uint16_t iPrecision = 0; iPrecision < 4; iPrecision++) \
3024 { \
3025 for (uint16_t iMask = 0; iMask <= X86_FCW_MASK_ALL; iMask += X86_FCW_MASK_ALL) \
3026 { \
3027 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_PC_MASK | X86_FCW_MASK_ALL)) \
3028 | (iRounding << X86_FCW_RC_SHIFT) \
3029 | (iPrecision << X86_FCW_PC_SHIFT) \
3030 | iMask; \
3031 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 }; \
3032 a_aSubTests[iFn].pfn(&State, &Res, &InVal1, &InVal2); \
3033 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/%c */\n", \
3034 State.FCW, State.FSW, Res.FSW, GenFormatR80(&InVal1), GenFormatR ## a_cBits(&InVal2), \
3035 GenFormatR80(&Res.r80Result), iTest, iRounding, iPrecision, iMask ? 'c' : 'u'); \
3036 } \
3037 } \
3038 } \
3039 } \
3040 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
3041 } \
3042}
3043#else
3044# define GEN_FPU_BINARY_SMALL(a_cBits, a_rdType, a_aSubTests, a_TestType)
3045#endif
3046
3047#define TEST_FPU_BINARY_SMALL(a_cBits, a_rdType, a_SubTestType, a_aSubTests, a_TestType) \
3048TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLFPUR ## a_cBits); \
3049\
3050static const a_SubTestType a_aSubTests[] = \
3051{ \
3052 ENTRY(RT_CONCAT(fadd_r80_by_r, a_cBits)), \
3053 ENTRY(RT_CONCAT(fmul_r80_by_r, a_cBits)), \
3054 ENTRY(RT_CONCAT(fsub_r80_by_r, a_cBits)), \
3055 ENTRY(RT_CONCAT(fsubr_r80_by_r, a_cBits)), \
3056 ENTRY(RT_CONCAT(fdiv_r80_by_r, a_cBits)), \
3057 ENTRY(RT_CONCAT(fdivr_r80_by_r, a_cBits)), \
3058}; \
3059\
3060GEN_FPU_BINARY_SMALL(a_cBits, a_rdType, a_aSubTests, a_TestType) \
3061\
3062static void FpuBinaryR ## a_cBits ##Test(void) \
3063{ \
3064 X86FXSTATE State; \
3065 RT_ZERO(State); \
3066 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
3067 { \
3068 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
3069 \
3070 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
3071 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
3072 PFNIEMAIMPLFPUR ## a_cBits pfn = a_aSubTests[iFn].pfn; \
3073 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
3074 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
3075 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
3076 { \
3077 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
3078 { \
3079 RTFLOAT80U const InVal1 = paTests[iTest].InVal1; \
3080 a_rdType const InVal2 = paTests[iTest].InVal2; \
3081 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 }; \
3082 State.FCW = paTests[iTest].fFcw; \
3083 State.FSW = paTests[iTest].fFswIn; \
3084 pfn(&State, &Res, &InVal1, &InVal2); \
3085 if ( Res.FSW != paTests[iTest].fFswOut \
3086 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].OutVal)) \
3087 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in1=%s in2=%s\n" \
3088 "%s -> fsw=%#06x %s\n" \
3089 "%s expected %#06x %s%s%s (%s)\n", \
3090 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, \
3091 FormatR80(&paTests[iTest].InVal1), FormatR ## a_cBits(&paTests[iTest].InVal2), \
3092 iVar ? " " : "", Res.FSW, FormatR80(&Res.r80Result), \
3093 iVar ? " " : "", paTests[iTest].fFswOut, FormatR80(&paTests[iTest].OutVal), \
3094 FswDiff(Res.FSW, paTests[iTest].fFswOut), \
3095 RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].OutVal) ? " - val" : "", \
3096 FormatFcw(paTests[iTest].fFcw) ); \
3097 } \
3098 pfn = a_aSubTests[iFn].pfnNative; \
3099 } \
3100 } \
3101}
3102
3103TEST_FPU_BINARY_SMALL(64, RTFLOAT64U, FPU_BINARY_R64_T, g_aFpuBinaryR64, FPU_BINARY_R64_TEST_T)
3104TEST_FPU_BINARY_SMALL(32, RTFLOAT32U, FPU_BINARY_R32_T, g_aFpuBinaryR32, FPU_BINARY_R32_TEST_T)
3105
3106
3107/*
3108 * Binary operations on 80-, 64- and 32-bit floating point only affecting FSW.
3109 */
3110#ifdef TSTIEMAIMPL_WITH_GENERATOR
3111static struct { RTFLOAT80U Val1, Val2; } const s_aFpuBinaryFswR80Specials[] =
3112{
3113 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3114 RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS) }, /* whatever */
3115};
3116static struct { RTFLOAT80U Val1; RTFLOAT64U Val2; } const s_aFpuBinaryFswR64Specials[] =
3117{
3118 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3119 RTFLOAT64U_INIT_C(0, 0xfeeeeddddcccc, RTFLOAT64U_EXP_BIAS) }, /* whatever */
3120};
3121static struct { RTFLOAT80U Val1; RTFLOAT32U Val2; } const s_aFpuBinaryFswR32Specials[] =
3122{
3123 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3124 RTFLOAT32U_INIT_C(0, 0x7fffee, RTFLOAT32U_EXP_BIAS) }, /* whatever */
3125};
3126
3127# define GEN_FPU_BINARY_FSW(a_cBits, a_rdType, a_aSubTests, a_TestType) \
3128static void FpuBinaryFswR ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
3129{ \
3130 X86FXSTATE State; \
3131 RT_ZERO(State); \
3132 uint32_t cMinNormalPairs = cTests / 4; \
3133 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
3134 { \
3135 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
3136 uint32_t cNormalInputPairs = 0; \
3137 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aFpuBinaryFswR ## a_cBits ## Specials); iTest += 1) \
3138 { \
3139 RTFLOAT80U const InVal1 = iTest < cTests ? RandR80Ex() \
3140 : s_aFpuBinaryFswR ## a_cBits ## Specials[iTest - cTests].Val1; \
3141 a_rdType const InVal2 = iTest < cTests ? RandR ## a_cBits ## Src(a_cBits) \
3142 : s_aFpuBinaryFswR ## a_cBits ## Specials[iTest - cTests].Val2; \
3143 if (RTFLOAT80U_IS_NORMAL(&InVal1) && a_rdType ## _IS_NORMAL(&InVal2)) \
3144 cNormalInputPairs++; \
3145 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests) \
3146 { \
3147 iTest -= 1; \
3148 continue; \
3149 } \
3150 \
3151 uint16_t const fFcw = RandFcw(); \
3152 State.FSW = RandFsw(); \
3153 \
3154 /* Guess these aren't affected by precision or rounding, so just flip the exception mask. */ \
3155 for (uint16_t iMask = 0; iMask <= X86_FCW_MASK_ALL; iMask += X86_FCW_MASK_ALL) \
3156 { \
3157 State.FCW = (fFcw & ~(X86_FCW_MASK_ALL)) | iMask; \
3158 uint16_t uFswOut = 0; \
3159 a_aSubTests[iFn].pfn(&State, &uFswOut, &InVal1, &InVal2); \
3160 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%c */\n", \
3161 State.FCW, State.FSW, uFswOut, GenFormatR80(&InVal1), GenFormatR ## a_cBits(&InVal2), \
3162 iTest, iMask ? 'c' : 'u'); \
3163 } \
3164 } \
3165 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
3166 } \
3167}
3168#else
3169# define GEN_FPU_BINARY_FSW(a_cBits, a_rdType, a_aSubTests, a_TestType)
3170#endif
3171
3172#define TEST_FPU_BINARY_FSW(a_cBits, a_rdType, a_SubTestType, a_aSubTests, a_TestType, ...) \
3173TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLFPUR ## a_cBits ## FSW); \
3174\
3175static const a_SubTestType a_aSubTests[] = \
3176{ \
3177 ENTRY(RT_CONCAT(fcom_r80_by_r, a_cBits)), \
3178 __VA_ARGS__\
3179}; \
3180\
3181GEN_FPU_BINARY_FSW(a_cBits, a_rdType, a_aSubTests, a_TestType) \
3182\
3183static void FpuBinaryFswR ## a_cBits ##Test(void) \
3184{ \
3185 X86FXSTATE State; \
3186 RT_ZERO(State); \
3187 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
3188 { \
3189 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
3190 \
3191 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
3192 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
3193 PFNIEMAIMPLFPUR ## a_cBits ## FSW pfn = a_aSubTests[iFn].pfn; \
3194 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
3195 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
3196 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
3197 { \
3198 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
3199 { \
3200 RTFLOAT80U const InVal1 = paTests[iTest].InVal1; \
3201 a_rdType const InVal2 = paTests[iTest].InVal2; \
3202 State.FCW = paTests[iTest].fFcw; \
3203 State.FSW = paTests[iTest].fFswIn; \
3204 uint16_t uFswOut = 0; \
3205 pfn(&State, &uFswOut, &InVal1, &InVal2); \
3206 if (uFswOut != paTests[iTest].fFswOut) \
3207 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in1=%s in2=%s\n" \
3208 "%s -> fsw=%#06x\n" \
3209 "%s expected %#06x %s (%s)\n", \
3210 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, \
3211 FormatR80(&paTests[iTest].InVal1), FormatR ## a_cBits(&paTests[iTest].InVal2), \
3212 iVar ? " " : "", uFswOut, \
3213 iVar ? " " : "", paTests[iTest].fFswOut, \
3214 FswDiff(uFswOut, paTests[iTest].fFswOut), FormatFcw(paTests[iTest].fFcw) ); \
3215 } \
3216 pfn = a_aSubTests[iFn].pfnNative; \
3217 } \
3218 } \
3219}
3220
3221TEST_FPU_BINARY_FSW(80, RTFLOAT80U, FPU_BINARY_FSW_R80_T, g_aFpuBinaryFswR80, FPU_BINARY_R80_TEST_T, ENTRY(fucom_r80_by_r80))
3222TEST_FPU_BINARY_FSW(64, RTFLOAT64U, FPU_BINARY_FSW_R64_T, g_aFpuBinaryFswR64, FPU_BINARY_R64_TEST_T, RT_NOTHING)
3223TEST_FPU_BINARY_FSW(32, RTFLOAT32U, FPU_BINARY_FSW_R32_T, g_aFpuBinaryFswR32, FPU_BINARY_R32_TEST_T, RT_NOTHING)
3224
3225
3226/*
3227 * Binary operations on 80-bit floating point that effects only EFLAGS and possibly FSW.
3228 */
3229TYPEDEF_SUBTEST_TYPE(FPU_BINARY_EFL_R80_T, FPU_BINARY_EFL_R80_TEST_T, PFNIEMAIMPLFPUR80EFL);
3230
3231static const FPU_BINARY_EFL_R80_T g_aFpuBinaryEflR80[] =
3232{
3233 ENTRY(fcomi_r80_by_r80),
3234 ENTRY(fucomi_r80_by_r80),
3235};
3236
3237#ifdef TSTIEMAIMPL_WITH_GENERATOR
3238static struct { RTFLOAT80U Val1, Val2; } const s_aFpuBinaryEflR80Specials[] =
3239{
3240 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3241 RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS) }, /* whatever */
3242};
3243
3244static void FpuBinaryEflR80Generate(PRTSTREAM pOut, uint32_t cTests)
3245{
3246 X86FXSTATE State;
3247 RT_ZERO(State);
3248 uint32_t cMinNormalPairs = cTests / 4;
3249 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuBinaryEflR80); iFn++)
3250 {
3251 GenerateArrayStart(pOut, g_aFpuBinaryEflR80[iFn].pszName, "FPU_BINARY_EFL_R80_TEST_T");
3252 uint32_t cNormalInputPairs = 0;
3253 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aFpuBinaryEflR80Specials); iTest += 1)
3254 {
3255 RTFLOAT80U const InVal1 = iTest < cTests ? RandR80Ex() : s_aFpuBinaryEflR80Specials[iTest - cTests].Val1;
3256 RTFLOAT80U const InVal2 = iTest < cTests ? RandR80Ex() : s_aFpuBinaryEflR80Specials[iTest - cTests].Val2;
3257 if (RTFLOAT80U_IS_NORMAL(&InVal1) && RTFLOAT80U_IS_NORMAL(&InVal2))
3258 cNormalInputPairs++;
3259 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
3260 {
3261 iTest -= 1;
3262 continue;
3263 }
3264
3265 uint16_t const fFcw = RandFcw();
3266 State.FSW = RandFsw();
3267
3268 /* Guess these aren't affected by precision or rounding, so just flip the exception mask. */
3269 for (uint16_t iMask = 0; iMask <= X86_FCW_MASK_ALL; iMask += X86_FCW_MASK_ALL)
3270 {
3271 State.FCW = (fFcw & ~(X86_FCW_MASK_ALL)) | iMask;
3272 uint16_t uFswOut = 0;
3273 uint32_t fEflOut = g_aFpuBinaryEflR80[iFn].pfn(&State, &uFswOut, &InVal1, &InVal2);
3274 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s, %#08x }, /* #%u/%c */\n",
3275 State.FCW, State.FSW, uFswOut, GenFormatR80(&InVal1), GenFormatR80(&InVal2), fEflOut,
3276 iTest, iMask ? 'c' : 'u');
3277 }
3278 }
3279 GenerateArrayEnd(pOut, g_aFpuBinaryEflR80[iFn].pszName);
3280 }
3281}
3282#endif /*TSTIEMAIMPL_WITH_GENERATOR*/
3283
3284static void FpuBinaryEflR80Test(void)
3285{
3286 X86FXSTATE State;
3287 RT_ZERO(State);
3288 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuBinaryEflR80); iFn++)
3289 {
3290 RTTestSub(g_hTest, g_aFpuBinaryEflR80[iFn].pszName);
3291
3292 uint32_t const cTests = *g_aFpuBinaryEflR80[iFn].pcTests;
3293 FPU_BINARY_EFL_R80_TEST_T const * const paTests = g_aFpuBinaryEflR80[iFn].paTests;
3294 PFNIEMAIMPLFPUR80EFL pfn = g_aFpuBinaryEflR80[iFn].pfn;
3295 uint32_t const cVars = 1 + (g_aFpuBinaryEflR80[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && g_aFpuBinaryEflR80[iFn].pfnNative);
3296 if (!cTests) RTTestSkipped(g_hTest, "no tests");
3297 for (uint32_t iVar = 0; iVar < cVars; iVar++)
3298 {
3299 for (uint32_t iTest = 0; iTest < cTests; iTest++)
3300 {
3301 RTFLOAT80U const InVal1 = paTests[iTest].InVal1;
3302 RTFLOAT80U const InVal2 = paTests[iTest].InVal2;
3303 State.FCW = paTests[iTest].fFcw;
3304 State.FSW = paTests[iTest].fFswIn;
3305 uint16_t uFswOut = 0;
3306 uint32_t fEflOut = pfn(&State, &uFswOut, &InVal1, &InVal2);
3307 if ( uFswOut != paTests[iTest].fFswOut
3308 || fEflOut != paTests[iTest].fEflOut)
3309 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in1=%s in2=%s\n"
3310 "%s -> fsw=%#06x efl=%#08x\n"
3311 "%s expected %#06x %#08x %s (%s)\n",
3312 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
3313 FormatR80(&paTests[iTest].InVal1), FormatR80(&paTests[iTest].InVal2),
3314 iVar ? " " : "", uFswOut, fEflOut,
3315 iVar ? " " : "", paTests[iTest].fFswOut, paTests[iTest].fEflOut,
3316 EFlagsDiff(fEflOut, paTests[iTest].fEflOut), FormatFcw(paTests[iTest].fFcw));
3317 }
3318 pfn = g_aFpuBinaryEflR80[iFn].pfnNative;
3319 }
3320 }
3321}
3322
3323
3324
3325int main(int argc, char **argv)
3326{
3327 int rc = RTR3InitExe(argc, &argv, 0);
3328 if (RT_FAILURE(rc))
3329 return RTMsgInitFailure(rc);
3330
3331 /*
3332 * Determin the host CPU.
3333 * If not using the IEMAllAImpl.asm code, this will be set to Intel.
3334 */
3335#if (defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && !defined(IEM_WITHOUT_ASSEMBLY)
3336 g_idxCpuEflFlavour = ASMIsAmdCpu() || ASMIsHygonCpu()
3337 ? IEMTARGETCPU_EFL_BEHAVIOR_AMD
3338 : IEMTARGETCPU_EFL_BEHAVIOR_INTEL;
3339#else
3340 g_idxCpuEflFlavour = IEMTARGETCPU_EFL_BEHAVIOR_INTEL;
3341#endif
3342
3343 /*
3344 * Parse arguments.
3345 */
3346 enum { kModeNotSet, kModeTest, kModeGenerate }
3347 enmMode = kModeNotSet;
3348 bool fInt = true;
3349 bool fFpuLdSt = true;
3350 bool fFpuBinary1 = true;
3351 bool fFpuBinary2 = true;
3352 bool fFpuOther = true;
3353 bool fCpuData = true;
3354 bool fCommonData = true;
3355 uint32_t const cDefaultTests = 96;
3356 uint32_t cTests = cDefaultTests;
3357 RTGETOPTDEF const s_aOptions[] =
3358 {
3359 // mode:
3360 { "--generate", 'g', RTGETOPT_REQ_NOTHING },
3361 { "--test", 't', RTGETOPT_REQ_NOTHING },
3362 // test selection (both)
3363 { "--all", 'a', RTGETOPT_REQ_NOTHING },
3364 { "--none", 'z', RTGETOPT_REQ_NOTHING },
3365 { "--zap", 'z', RTGETOPT_REQ_NOTHING },
3366 { "--fpu-ld-st", 'F', RTGETOPT_REQ_NOTHING }, /* FPU stuff is upper case */
3367 { "--fpu-load-store", 'F', RTGETOPT_REQ_NOTHING },
3368 { "--fpu-binary-1", 'B', RTGETOPT_REQ_NOTHING },
3369 { "--fpu-binary-2", 'P', RTGETOPT_REQ_NOTHING },
3370 { "--fpu-other", 'O', RTGETOPT_REQ_NOTHING },
3371 { "--int", 'i', RTGETOPT_REQ_NOTHING },
3372 // generation parameters
3373 { "--common", 'm', RTGETOPT_REQ_NOTHING },
3374 { "--cpu", 'c', RTGETOPT_REQ_NOTHING },
3375 { "--number-of-tests", 'n', RTGETOPT_REQ_UINT32 },
3376 };
3377
3378 RTGETOPTSTATE State;
3379 rc = RTGetOptInit(&State, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
3380 AssertRCReturn(rc, RTEXITCODE_FAILURE);
3381
3382 RTGETOPTUNION ValueUnion;
3383 while ((rc = RTGetOpt(&State, &ValueUnion)))
3384 {
3385 switch (rc)
3386 {
3387 case 'g':
3388 enmMode = kModeGenerate;
3389 break;
3390 case 't':
3391 enmMode = kModeTest;
3392 break;
3393 case 'a':
3394 fCpuData = true;
3395 fCommonData = true;
3396 fInt = true;
3397 fFpuLdSt = true;
3398 fFpuBinary1 = true;
3399 fFpuBinary2 = true;
3400 fFpuOther = true;
3401 break;
3402 case 'z':
3403 fCpuData = false;
3404 fCommonData = false;
3405 fInt = false;
3406 fFpuLdSt = false;
3407 fFpuBinary1 = false;
3408 fFpuBinary2 = false;
3409 fFpuOther = false;
3410 break;
3411 case 'F':
3412 fFpuLdSt = true;
3413 break;
3414 case 'O':
3415 fFpuOther = true;
3416 break;
3417 case 'B':
3418 fFpuBinary1 = true;
3419 break;
3420 case 'P':
3421 fFpuBinary2 = true;
3422 break;
3423 case 'i':
3424 fInt = true;
3425 break;
3426 case 'm':
3427 fCommonData = true;
3428 break;
3429 case 'c':
3430 fCpuData = true;
3431 break;
3432 case 'n':
3433 cTests = ValueUnion.u32;
3434 break;
3435 case 'h':
3436 RTPrintf("usage: %s <-g|-t> [options]\n"
3437 "\n"
3438 "Mode:\n"
3439 " -g, --generate\n"
3440 " Generate test data.\n"
3441 " -t, --test\n"
3442 " Execute tests.\n"
3443 "\n"
3444 "Test selection (both modes):\n"
3445 " -a, --all\n"
3446 " Enable all tests and generated test data. (default)\n"
3447 " -z, --zap, --none\n"
3448 " Disable all tests and test data types.\n"
3449 " -i, --int\n"
3450 " Enable non-FPU tests.\n"
3451 " -F, --fpu-ld-st\n"
3452 " Enable FPU load and store tests.\n"
3453 " -B, --fpu-binary-1\n"
3454 " Enable FPU binary 80-bit FP tests.\n"
3455 " -P, --fpu-binary-2\n"
3456 " Enable FPU binary 64- and 32-bit FP tests.\n"
3457 " -O, --fpu-other\n"
3458 " Enable other FPU tests.\n"
3459 "\n"
3460 "Generation:\n"
3461 " -m, --common\n"
3462 " Enable generating common test data.\n"
3463 " -c, --only-cpu\n"
3464 " Enable generating CPU specific test data.\n"
3465 " -n, --number-of-test <count>\n"
3466 " Number of tests to generate. Default: %u\n"
3467 , argv[0], cDefaultTests);
3468 return RTEXITCODE_SUCCESS;
3469 default:
3470 return RTGetOptPrintError(rc, &ValueUnion);
3471 }
3472 }
3473
3474 /*
3475 * Generate data?
3476 */
3477 if (enmMode == kModeGenerate)
3478 {
3479#ifdef TSTIEMAIMPL_WITH_GENERATOR
3480 char szCpuDesc[256] = {0};
3481 RTMpGetDescription(NIL_RTCPUID, szCpuDesc, sizeof(szCpuDesc));
3482 const char * const pszCpuType = g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD ? "Amd" : "Intel";
3483# if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
3484 const char * const pszBitBucket = "NUL";
3485# else
3486 const char * const pszBitBucket = "/dev/null";
3487# endif
3488
3489 if (cTests == 0)
3490 cTests = cDefaultTests;
3491 g_cZeroDstTests = RT_MIN(cTests / 16, 32);
3492 g_cZeroSrcTests = g_cZeroDstTests * 2;
3493
3494 if (fInt)
3495 {
3496 const char *pszDataFile = fCommonData ? "tstIEMAImplDataInt.cpp" : pszBitBucket;
3497 PRTSTREAM pStrmData = GenerateOpenWithHdr(pszDataFile, szCpuDesc, NULL);
3498 const char *pszDataCpuFile = !fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
3499 ? "tstIEMAImplDataInt-Amd.cpp" : "tstIEMAImplDataInt-Intel.cpp";
3500 PRTSTREAM pStrmDataCpu = GenerateOpenWithHdr(pszDataCpuFile, szCpuDesc, pszCpuType);
3501 if (!pStrmData || !pStrmDataCpu)
3502 return RTEXITCODE_FAILURE;
3503
3504 BinU8Generate( pStrmData, pStrmDataCpu, cTests);
3505 BinU16Generate(pStrmData, pStrmDataCpu, cTests);
3506 BinU32Generate(pStrmData, pStrmDataCpu, cTests);
3507 BinU64Generate(pStrmData, pStrmDataCpu, cTests);
3508 ShiftDblGenerate(pStrmDataCpu, RT_MAX(cTests, 128));
3509 UnaryGenerate(pStrmData, cTests);
3510 ShiftGenerate(pStrmDataCpu, cTests);
3511 MulDivGenerate(pStrmDataCpu, cTests);
3512
3513 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile,
3514 GenerateFooterAndClose(pStrmData, pszDataFile, RTEXITCODE_SUCCESS));
3515 if (rcExit != RTEXITCODE_SUCCESS)
3516 return rcExit;
3517 }
3518
3519 if (fFpuLdSt)
3520 {
3521 const char *pszDataFile = fCommonData ? "tstIEMAImplDataFpuLdSt.cpp" : pszBitBucket;
3522 PRTSTREAM pStrmData = GenerateOpenWithHdr(pszDataFile, szCpuDesc, NULL);
3523 const char *pszDataCpuFile = !fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
3524 ? "tstIEMAImplDataFpuLdSt-Amd.cpp" : "tstIEMAImplDataFpuLdSt-Intel.cpp";
3525 PRTSTREAM pStrmDataCpu = GenerateOpenWithHdr(pszDataCpuFile, szCpuDesc, pszCpuType);
3526 if (!pStrmData || !pStrmDataCpu)
3527 return RTEXITCODE_FAILURE;
3528
3529 FpuLdConstGenerate(pStrmData, cTests);
3530 FpuLdIntGenerate(pStrmData, cTests);
3531 FpuLdD80Generate(pStrmData, cTests);
3532 FpuStIntGenerate(pStrmData, cTests);
3533 FpuStD80Generate(pStrmData, cTests);
3534 cTests = RT_MAX(cTests, 384); /* need better coverage for the next ones. */
3535 FpuLdMemGenerate(pStrmData, cTests);
3536 FpuStMemGenerate(pStrmData, cTests);
3537
3538 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile,
3539 GenerateFooterAndClose(pStrmData, pszDataFile, RTEXITCODE_SUCCESS));
3540 if (rcExit != RTEXITCODE_SUCCESS)
3541 return rcExit;
3542 }
3543
3544 if (fFpuBinary1)
3545 {
3546 const char *pszDataFile = fCommonData ? "tstIEMAImplDataFpuBinary1.cpp" : pszBitBucket;
3547 PRTSTREAM pStrmData = GenerateOpenWithHdr(pszDataFile, szCpuDesc, NULL);
3548 const char *pszDataCpuFile = pszBitBucket; /*!fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
3549 ? "tstIEMAImplDataFpuBinary1-Amd.cpp" : "tstIEMAImplDataFpuBinary1-Intel.cpp";*/
3550 PRTSTREAM pStrmDataCpu = GenerateOpenWithHdr(pszDataCpuFile, szCpuDesc, pszCpuType);
3551 if (!pStrmData || !pStrmDataCpu)
3552 return RTEXITCODE_FAILURE;
3553
3554 FpuBinaryR80Generate(pStrmData, cTests);
3555 FpuBinaryFswR80Generate(pStrmData, cTests);
3556 FpuBinaryEflR80Generate(pStrmData, cTests);
3557
3558 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile,
3559 GenerateFooterAndClose(pStrmData, pszDataFile, RTEXITCODE_SUCCESS));
3560 if (rcExit != RTEXITCODE_SUCCESS)
3561 return rcExit;
3562 }
3563
3564 if (fFpuBinary2)
3565 {
3566 const char *pszDataFile = fCommonData ? "tstIEMAImplDataFpuBinary2.cpp" : pszBitBucket;
3567 PRTSTREAM pStrmData = GenerateOpenWithHdr(pszDataFile, szCpuDesc, NULL);
3568 const char *pszDataCpuFile = pszBitBucket; /*!fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
3569 ? "tstIEMAImplDataFpuBinary2-Amd.cpp" : "tstIEMAImplDataFpuBinary2-Intel.cpp"; */
3570 PRTSTREAM pStrmDataCpu = GenerateOpenWithHdr(pszDataCpuFile, szCpuDesc, pszCpuType);
3571 if (!pStrmData || !pStrmDataCpu)
3572 return RTEXITCODE_FAILURE;
3573
3574 FpuBinaryR64Generate(pStrmData, cTests);
3575 FpuBinaryR32Generate(pStrmData, cTests);
3576 FpuBinaryFswR64Generate(pStrmData, cTests);
3577 FpuBinaryFswR32Generate(pStrmData, cTests);
3578
3579 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile,
3580 GenerateFooterAndClose(pStrmData, pszDataFile, RTEXITCODE_SUCCESS));
3581 if (rcExit != RTEXITCODE_SUCCESS)
3582 return rcExit;
3583 }
3584
3585# if 0
3586 if (fFpuOther)
3587 {
3588 const char *pszDataFile = fCommonData ? "tstIEMAImplDataFpuOther.cpp" : pszBitBucket;
3589 PRTSTREAM pStrmData = GenerateOpenWithHdr(pszDataFile, szCpuDesc, NULL);
3590 const char *pszDataCpuFile = !fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
3591 ? "tstIEMAImplDataFpuOther-Amd.cpp" : "tstIEMAImplDataFpuOther-Intel.cpp";
3592 PRTSTREAM pStrmDataCpu = GenerateOpenWithHdr(pszDataCpuFile, szCpuDesc, pszCpuType);
3593 if (!pStrmData || !pStrmDataCpu)
3594 return RTEXITCODE_FAILURE;
3595
3596 /* later */
3597
3598 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile,
3599 GenerateFooterAndClose(pStrmData, pszDataFile, RTEXITCODE_SUCCESS));
3600 if (rcExit != RTEXITCODE_SUCCESS)
3601 return rcExit;
3602 }
3603# endif
3604
3605 return RTEXITCODE_SUCCESS;
3606#else
3607 return RTMsgErrorExitFailure("Test data generator not compiled in!");
3608#endif
3609 }
3610
3611 /*
3612 * Do testing. Currrently disabled by default as data needs to be checked
3613 * on both intel and AMD systems first.
3614 */
3615 rc = RTTestCreate("tstIEMAimpl", &g_hTest);
3616 AssertRCReturn(rc, RTEXITCODE_FAILURE);
3617 if (enmMode == kModeTest)
3618 {
3619 RTTestBanner(g_hTest);
3620
3621 /* Allocate guarded memory for use in the tests. */
3622#define ALLOC_GUARDED_VAR(a_puVar) do { \
3623 rc = RTTestGuardedAlloc(g_hTest, sizeof(*a_puVar), sizeof(*a_puVar), false /*fHead*/, (void **)&a_puVar); \
3624 if (RT_FAILURE(rc)) RTTestFailed(g_hTest, "Failed to allocate guarded mem: " #a_puVar); \
3625 } while (0)
3626 ALLOC_GUARDED_VAR(g_pu8);
3627 ALLOC_GUARDED_VAR(g_pu16);
3628 ALLOC_GUARDED_VAR(g_pu32);
3629 ALLOC_GUARDED_VAR(g_pu64);
3630 ALLOC_GUARDED_VAR(g_pu128);
3631 ALLOC_GUARDED_VAR(g_pu8Two);
3632 ALLOC_GUARDED_VAR(g_pu16Two);
3633 ALLOC_GUARDED_VAR(g_pu32Two);
3634 ALLOC_GUARDED_VAR(g_pu64Two);
3635 ALLOC_GUARDED_VAR(g_pu128Two);
3636 ALLOC_GUARDED_VAR(g_pfEfl);
3637 if (RTTestErrorCount(g_hTest) == 0)
3638 {
3639 if (fInt)
3640 {
3641 BinU8Test();
3642 BinU16Test();
3643 BinU32Test();
3644 BinU64Test();
3645 XchgTest();
3646 XaddTest();
3647 CmpXchgTest();
3648 CmpXchg8bTest();
3649 CmpXchg16bTest();
3650 ShiftDblTest();
3651 UnaryTest();
3652 ShiftTest();
3653 MulDivTest();
3654 BswapTest();
3655 }
3656
3657 if (fFpuLdSt)
3658 {
3659 FpuLoadConstTest();
3660 FpuLdMemTest();
3661 FpuLdIntTest();
3662 FpuLdD80Test();
3663 FpuStMemTest();
3664 FpuStIntTest();
3665 FpuStD80Test();
3666 }
3667
3668 if (fFpuBinary1)
3669 {
3670 FpuBinaryR80Test();
3671 FpuBinaryFswR80Test();
3672 FpuBinaryEflR80Test();
3673 }
3674
3675 if (fFpuBinary2)
3676 {
3677 FpuBinaryR64Test();
3678 FpuBinaryR32Test();
3679 FpuBinaryFswR64Test();
3680 FpuBinaryFswR32Test();
3681 }
3682 }
3683 return RTTestSummaryAndDestroy(g_hTest);
3684 }
3685 return RTTestSkipAndDestroy(g_hTest, "unfinished testcase");
3686}
3687
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette