VirtualBox

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

最後變更 在這個檔案從94413是 94413,由 vboxsync 提交於 3 年 前

VMM/IEM,tstIEMAImpl: A handful of FPU instructions produces different results on AMD, it seems. bugref:9898

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 157.4 KB
 
1/* $Id: tstIEMAImpl.cpp 94413 2022-03-31 12:20:53Z 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.alldomusa.eu.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 ? 80U : 16U) || cTarget == 64U || cTarget == 32U || (cTarget == 59U && 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: 94413 $";
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 94413 2022-03-31 12:20:53Z 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.alldomusa.eu.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 */
2540TYPEDEF_SUBTEST_TYPE(FPU_ST_I16_T, FPU_ST_I16_TEST_T, PFNIEMAIMPLFPUSTR80TOI16);
2541TYPEDEF_SUBTEST_TYPE(FPU_ST_I32_T, FPU_ST_I32_TEST_T, PFNIEMAIMPLFPUSTR80TOI32);
2542TYPEDEF_SUBTEST_TYPE(FPU_ST_I64_T, FPU_ST_I64_TEST_T, PFNIEMAIMPLFPUSTR80TOI64);
2543
2544static const FPU_ST_I16_T g_aFpuStI16[] =
2545{
2546 ENTRY(fist_r80_to_i16),
2547 ENTRY_AMD( fistt_r80_to_i16, 0),
2548 ENTRY_INTEL(fistt_r80_to_i16, 0),
2549};
2550static const FPU_ST_I32_T g_aFpuStI32[] =
2551{
2552 ENTRY(fist_r80_to_i32),
2553 ENTRY(fistt_r80_to_i32),
2554};
2555static const FPU_ST_I64_T g_aFpuStI64[] =
2556{
2557 ENTRY(fist_r80_to_i64),
2558 ENTRY(fistt_r80_to_i64),
2559};
2560
2561#ifdef TSTIEMAIMPL_WITH_GENERATOR
2562static const RTFLOAT80U g_aFpuStI16Specials[] = /* 16-bit variant borrows properties from the 32-bit one, thus all this stuff. */
2563{
2564 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 13 + RTFLOAT80U_EXP_BIAS),
2565 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 13 + RTFLOAT80U_EXP_BIAS),
2566 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 14 + RTFLOAT80U_EXP_BIAS),
2567 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 14 + RTFLOAT80U_EXP_BIAS),
2568 RTFLOAT80U_INIT_C(0, 0x8000080000000000, 14 + RTFLOAT80U_EXP_BIAS),
2569 RTFLOAT80U_INIT_C(1, 0x8000080000000000, 14 + RTFLOAT80U_EXP_BIAS),
2570 RTFLOAT80U_INIT_C(0, 0x8000100000000000, 14 + RTFLOAT80U_EXP_BIAS),
2571 RTFLOAT80U_INIT_C(1, 0x8000100000000000, 14 + RTFLOAT80U_EXP_BIAS),
2572 RTFLOAT80U_INIT_C(0, 0x8000200000000000, 14 + RTFLOAT80U_EXP_BIAS),
2573 RTFLOAT80U_INIT_C(1, 0x8000200000000000, 14 + RTFLOAT80U_EXP_BIAS),
2574 RTFLOAT80U_INIT_C(0, 0x8000400000000000, 14 + RTFLOAT80U_EXP_BIAS),
2575 RTFLOAT80U_INIT_C(1, 0x8000400000000000, 14 + RTFLOAT80U_EXP_BIAS),
2576 RTFLOAT80U_INIT_C(0, 0x8000800000000000, 14 + RTFLOAT80U_EXP_BIAS),
2577 RTFLOAT80U_INIT_C(1, 0x8000800000000000, 14 + RTFLOAT80U_EXP_BIAS),
2578 RTFLOAT80U_INIT_C(1, 0x8000ffffffffffff, 14 + RTFLOAT80U_EXP_BIAS),
2579 RTFLOAT80U_INIT_C(0, 0x8001000000000000, 14 + RTFLOAT80U_EXP_BIAS),
2580 RTFLOAT80U_INIT_C(1, 0x8001000000000000, 14 + RTFLOAT80U_EXP_BIAS),
2581 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 14 + RTFLOAT80U_EXP_BIAS),
2582 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 14 + RTFLOAT80U_EXP_BIAS),
2583 RTFLOAT80U_INIT_C(0, 0xffff800000000000, 14 + RTFLOAT80U_EXP_BIAS),
2584 RTFLOAT80U_INIT_C(0, 0xffff000000000000, 14 + RTFLOAT80U_EXP_BIAS), /* overflow to min/nan */
2585 RTFLOAT80U_INIT_C(0, 0xfffe000000000000, 14 + RTFLOAT80U_EXP_BIAS),
2586 RTFLOAT80U_INIT_C(1, 0xffff800000000000, 14 + RTFLOAT80U_EXP_BIAS),
2587 RTFLOAT80U_INIT_C(1, 0xffff000000000000, 14 + RTFLOAT80U_EXP_BIAS), /* min */
2588 RTFLOAT80U_INIT_C(1, 0xfffe000000000000, 14 + RTFLOAT80U_EXP_BIAS),
2589 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 15 + RTFLOAT80U_EXP_BIAS),
2590 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 15 + RTFLOAT80U_EXP_BIAS),
2591 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 16 + RTFLOAT80U_EXP_BIAS),
2592 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 17 + RTFLOAT80U_EXP_BIAS),
2593 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 20 + RTFLOAT80U_EXP_BIAS),
2594 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 24 + RTFLOAT80U_EXP_BIAS),
2595 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 28 + RTFLOAT80U_EXP_BIAS),
2596 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 30 + RTFLOAT80U_EXP_BIAS),
2597 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 30 + RTFLOAT80U_EXP_BIAS),
2598 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 30 + RTFLOAT80U_EXP_BIAS),
2599 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 30 + RTFLOAT80U_EXP_BIAS),
2600 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 31 + RTFLOAT80U_EXP_BIAS),
2601 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 31 + RTFLOAT80U_EXP_BIAS),
2602 RTFLOAT80U_INIT_C(0, 0x8000000000000001, 31 + RTFLOAT80U_EXP_BIAS),
2603 RTFLOAT80U_INIT_C(1, 0x8000000000000001, 31 + RTFLOAT80U_EXP_BIAS),
2604 RTFLOAT80U_INIT_C(0, 0x8000ffffffffffff, 31 + RTFLOAT80U_EXP_BIAS),
2605 RTFLOAT80U_INIT_C(1, 0x8000ffffffffffff, 31 + RTFLOAT80U_EXP_BIAS),
2606 RTFLOAT80U_INIT_C(0, 0x8001000000000000, 31 + RTFLOAT80U_EXP_BIAS),
2607 RTFLOAT80U_INIT_C(1, 0x8001000000000000, 31 + RTFLOAT80U_EXP_BIAS),
2608 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 31 + RTFLOAT80U_EXP_BIAS),
2609 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 31 + RTFLOAT80U_EXP_BIAS),
2610 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 32 + RTFLOAT80U_EXP_BIAS),
2611};
2612static const RTFLOAT80U g_aFpuStI32Specials[] =
2613{
2614 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 30 + RTFLOAT80U_EXP_BIAS),
2615 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 30 + RTFLOAT80U_EXP_BIAS),
2616 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 30 + RTFLOAT80U_EXP_BIAS), /* overflow to min/nan */
2617 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 30 + RTFLOAT80U_EXP_BIAS), /* min */
2618 RTFLOAT80U_INIT_C(0, 0xffffffff80000000, 30 + RTFLOAT80U_EXP_BIAS), /* overflow to min/nan */
2619 RTFLOAT80U_INIT_C(1, 0xffffffff80000000, 30 + RTFLOAT80U_EXP_BIAS), /* min */
2620 RTFLOAT80U_INIT_C(0, 0xffffffff00000000, 30 + RTFLOAT80U_EXP_BIAS), /* overflow to min/nan */
2621 RTFLOAT80U_INIT_C(1, 0xffffffff00000000, 30 + RTFLOAT80U_EXP_BIAS), /* min */
2622 RTFLOAT80U_INIT_C(0, 0xfffffffe00000000, 30 + RTFLOAT80U_EXP_BIAS),
2623 RTFLOAT80U_INIT_C(1, 0xfffffffe00000000, 30 + RTFLOAT80U_EXP_BIAS),
2624 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 31 + RTFLOAT80U_EXP_BIAS),
2625 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 31 + RTFLOAT80U_EXP_BIAS),
2626 RTFLOAT80U_INIT_C(0, 0x8000000000000001, 31 + RTFLOAT80U_EXP_BIAS),
2627 RTFLOAT80U_INIT_C(1, 0x8000000000000001, 31 + RTFLOAT80U_EXP_BIAS),
2628 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 31 + RTFLOAT80U_EXP_BIAS),
2629 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 31 + RTFLOAT80U_EXP_BIAS),
2630};
2631static const RTFLOAT80U g_aFpuStI64Specials[] =
2632{
2633 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 61 + RTFLOAT80U_EXP_BIAS),
2634 RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, 61 + RTFLOAT80U_EXP_BIAS),
2635 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 62 + RTFLOAT80U_EXP_BIAS),
2636 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 62 + RTFLOAT80U_EXP_BIAS),
2637 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 62 + RTFLOAT80U_EXP_BIAS),
2638 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 62 + RTFLOAT80U_EXP_BIAS),
2639 RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, 62 + RTFLOAT80U_EXP_BIAS), /* overflow to min/nan */
2640 RTFLOAT80U_INIT_C(1, 0xffffffffffffffff, 62 + RTFLOAT80U_EXP_BIAS), /* min */
2641 RTFLOAT80U_INIT_C(0, 0xfffffffffffffffe, 62 + RTFLOAT80U_EXP_BIAS),
2642 RTFLOAT80U_INIT_C(1, 0xfffffffffffffffe, 62 + RTFLOAT80U_EXP_BIAS),
2643 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 63 + RTFLOAT80U_EXP_BIAS),
2644 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 63 + RTFLOAT80U_EXP_BIAS),
2645 RTFLOAT80U_INIT_C(0, 0x8000000000000001, 63 + RTFLOAT80U_EXP_BIAS),
2646 RTFLOAT80U_INIT_C(1, 0x8000000000000001, 63 + RTFLOAT80U_EXP_BIAS),
2647 RTFLOAT80U_INIT_C(0, 0x8000000000000002, 63 + RTFLOAT80U_EXP_BIAS),
2648 RTFLOAT80U_INIT_C(1, 0x8000000000000002, 63 + RTFLOAT80U_EXP_BIAS),
2649 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 63 + RTFLOAT80U_EXP_BIAS),
2650};
2651
2652# define GEN_FPU_STORE_INT(a_cBits, a_iType, a_szFmt, a_aSubTests, a_TestType) \
2653static void FpuStI ## a_cBits ## Generate(PRTSTREAM pOut, PRTSTREAM pOutCpu, uint32_t cTests) \
2654{ \
2655 X86FXSTATE State; \
2656 RT_ZERO(State); \
2657 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2658 { \
2659 PFNIEMAIMPLFPUSTR80TOI ## a_cBits const pfn = a_aSubTests[iFn].pfnNative \
2660 ? a_aSubTests[iFn].pfnNative : a_aSubTests[iFn].pfn; \
2661 PRTSTREAM pOutFn = pOut; \
2662 if (a_aSubTests[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE) \
2663 { \
2664 if (a_aSubTests[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour) \
2665 continue; \
2666 pOutFn = pOutCpu; \
2667 } \
2668 \
2669 GenerateArrayStart(pOutFn, a_aSubTests[iFn].pszName, #a_TestType); \
2670 uint32_t const cTotalTests = cTests + RT_ELEMENTS(g_aFpuStI ## a_cBits ## Specials); \
2671 for (uint32_t iTest = 0; iTest < cTotalTests; iTest++) \
2672 { \
2673 uint16_t const fFcw = RandFcw(); \
2674 State.FSW = RandFsw(); \
2675 RTFLOAT80U const InVal = iTest < cTests ? RandR80Ex(a_cBits, true) \
2676 : g_aFpuStI ## a_cBits ## Specials[iTest - cTests]; \
2677 \
2678 for (uint16_t iRounding = 0; iRounding < 4; iRounding++) \
2679 { \
2680 /* PC doesn't influence these, so leave as is. */ \
2681 AssertCompile(X86_FCW_OM_BIT + 1 == X86_FCW_UM_BIT && X86_FCW_UM_BIT + 1 == X86_FCW_PM_BIT); \
2682 for (uint16_t iMask = 0; iMask < 16; iMask += 2 /*1*/) \
2683 { \
2684 uint16_t uFswOut = 0; \
2685 a_iType iOutVal = ~(a_iType)2; \
2686 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_OM | X86_FCW_UM | X86_FCW_PM)) \
2687 | (iRounding << X86_FCW_RC_SHIFT); \
2688 /*if (iMask & 1) State.FCW ^= X86_FCW_MASK_ALL;*/ \
2689 State.FCW |= (iMask >> 1) << X86_FCW_OM_BIT; \
2690 pfn(&State, &uFswOut, &iOutVal, &InVal); \
2691 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u/%u */\n", \
2692 State.FCW, State.FSW, uFswOut, GenFormatR80(&InVal), \
2693 GenFormatI ## a_cBits(iOutVal), iTest, iRounding, iMask); \
2694 } \
2695 } \
2696 } \
2697 GenerateArrayEnd(pOutFn, a_aSubTests[iFn].pszName); \
2698 } \
2699}
2700#else
2701# define GEN_FPU_STORE_INT(a_cBits, a_iType, a_szFmt, a_aSubTests, a_TestType)
2702#endif
2703
2704#define TEST_FPU_STORE_INT(a_cBits, a_iType, a_szFmt, a_SubTestType, a_aSubTests, a_TestType) \
2705GEN_FPU_STORE_INT(a_cBits, a_iType, a_szFmt, a_aSubTests, a_TestType) \
2706\
2707static void FpuStI ## a_cBits ## Test(void) \
2708{ \
2709 X86FXSTATE State; \
2710 RT_ZERO(State); \
2711 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2712 { \
2713 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
2714 \
2715 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
2716 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
2717 PFNIEMAIMPLFPUSTR80TOI ## a_cBits pfn = a_aSubTests[iFn].pfn; \
2718 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
2719 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
2720 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
2721 { \
2722 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
2723 { \
2724 RTFLOAT80U const InVal = paTests[iTest].InVal; \
2725 uint16_t uFswOut = 0; \
2726 a_iType iOutVal = ~(a_iType)2; \
2727 State.FCW = paTests[iTest].fFcw; \
2728 State.FSW = paTests[iTest].fFswIn; \
2729 pfn(&State, &uFswOut, &iOutVal, &InVal); \
2730 if ( uFswOut != paTests[iTest].fFswOut \
2731 || iOutVal != paTests[iTest].iOutVal) \
2732 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in=%s\n" \
2733 "%s -> fsw=%#06x " a_szFmt "\n" \
2734 "%s expected %#06x " a_szFmt "%s%s (%s)\n", \
2735 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, \
2736 FormatR80(&paTests[iTest].InVal), \
2737 iVar ? " " : "", uFswOut, iOutVal, \
2738 iVar ? " " : "", paTests[iTest].fFswOut, paTests[iTest].iOutVal, \
2739 FswDiff(uFswOut, paTests[iTest].fFswOut), \
2740 iOutVal != paTests[iTest].iOutVal ? " - val" : "", FormatFcw(paTests[iTest].fFcw) ); \
2741 } \
2742 pfn = a_aSubTests[iFn].pfnNative; \
2743 } \
2744 } \
2745}
2746
2747//fistt_r80_to_i16 diffs for AMD, of course :-)
2748
2749TEST_FPU_STORE_INT(64, int64_t, "%RI64", FPU_ST_I64_T, g_aFpuStI64, FPU_ST_I64_TEST_T)
2750TEST_FPU_STORE_INT(32, int32_t, "%RI32", FPU_ST_I32_T, g_aFpuStI32, FPU_ST_I32_TEST_T)
2751TEST_FPU_STORE_INT(16, int16_t, "%RI16", FPU_ST_I16_T, g_aFpuStI16, FPU_ST_I16_TEST_T)
2752
2753#ifdef TSTIEMAIMPL_WITH_GENERATOR
2754static void FpuStIntGenerate(PRTSTREAM pOut, PRTSTREAM pOutCpu, uint32_t cTests)
2755{
2756 FpuStI64Generate(pOut, pOutCpu, cTests);
2757 FpuStI32Generate(pOut, pOutCpu, cTests);
2758 FpuStI16Generate(pOut, pOutCpu, cTests);
2759}
2760#endif
2761
2762static void FpuStIntTest(void)
2763{
2764 FpuStI64Test();
2765 FpuStI32Test();
2766 FpuStI16Test();
2767}
2768
2769
2770/*
2771 * Store as packed BCD value (memory).
2772 */
2773typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLFPUSTR80TOD80,(PCX86FXSTATE, uint16_t *, PRTPBCD80U, PCRTFLOAT80U));
2774typedef FNIEMAIMPLFPUSTR80TOD80 *PFNIEMAIMPLFPUSTR80TOD80;
2775TYPEDEF_SUBTEST_TYPE(FPU_ST_D80_T, FPU_ST_D80_TEST_T, PFNIEMAIMPLFPUSTR80TOD80);
2776
2777static const FPU_ST_D80_T g_aFpuStD80[] =
2778{
2779 ENTRY(fst_r80_to_d80),
2780};
2781
2782#ifdef TSTIEMAIMPL_WITH_GENERATOR
2783static void FpuStD80Generate(PRTSTREAM pOut, uint32_t cTests)
2784{
2785 static RTFLOAT80U const s_aSpecials[] =
2786 {
2787 RTFLOAT80U_INIT_C(0, 0xde0b6b3a763fffe0, RTFLOAT80U_EXP_BIAS + 59), /* 1 below max */
2788 RTFLOAT80U_INIT_C(1, 0xde0b6b3a763fffe0, RTFLOAT80U_EXP_BIAS + 59), /* 1 above min */
2789 RTFLOAT80U_INIT_C(0, 0xde0b6b3a763ffff0, RTFLOAT80U_EXP_BIAS + 59), /* exact max */
2790 RTFLOAT80U_INIT_C(1, 0xde0b6b3a763ffff0, RTFLOAT80U_EXP_BIAS + 59), /* exact min */
2791 RTFLOAT80U_INIT_C(0, 0xde0b6b3a763fffff, RTFLOAT80U_EXP_BIAS + 59), /* max & all rounded off bits set */
2792 RTFLOAT80U_INIT_C(1, 0xde0b6b3a763fffff, RTFLOAT80U_EXP_BIAS + 59), /* min & all rounded off bits set */
2793 RTFLOAT80U_INIT_C(0, 0xde0b6b3a763ffff8, RTFLOAT80U_EXP_BIAS + 59), /* max & some rounded off bits set */
2794 RTFLOAT80U_INIT_C(1, 0xde0b6b3a763ffff8, RTFLOAT80U_EXP_BIAS + 59), /* min & some rounded off bits set */
2795 RTFLOAT80U_INIT_C(0, 0xde0b6b3a763ffff1, RTFLOAT80U_EXP_BIAS + 59), /* max & some other rounded off bits set */
2796 RTFLOAT80U_INIT_C(1, 0xde0b6b3a763ffff1, RTFLOAT80U_EXP_BIAS + 59), /* min & some other rounded off bits set */
2797 RTFLOAT80U_INIT_C(0, 0xde0b6b3a76400000, RTFLOAT80U_EXP_BIAS + 59), /* 1 above max */
2798 RTFLOAT80U_INIT_C(1, 0xde0b6b3a76400000, RTFLOAT80U_EXP_BIAS + 59), /* 1 below min */
2799 };
2800
2801 X86FXSTATE State;
2802 RT_ZERO(State);
2803 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuStD80); iFn++)
2804 {
2805 GenerateArrayStart(pOut, g_aFpuStD80[iFn].pszName, "FPU_ST_D80_TEST_T");
2806 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
2807 {
2808 uint16_t const fFcw = RandFcw();
2809 State.FSW = RandFsw();
2810 RTFLOAT80U const InVal = iTest < cTests ? RandR80Ex(59, true) : s_aSpecials[iTest - cTests];
2811
2812 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
2813 {
2814 /* PC doesn't influence these, so leave as is. */
2815 AssertCompile(X86_FCW_OM_BIT + 1 == X86_FCW_UM_BIT && X86_FCW_UM_BIT + 1 == X86_FCW_PM_BIT);
2816 for (uint16_t iMask = 0; iMask < 16; iMask += 2 /*1*/)
2817 {
2818 uint16_t uFswOut = 0;
2819 RTPBCD80U OutVal = RTPBCD80U_INIT_ZERO(0);
2820 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_OM | X86_FCW_UM | X86_FCW_PM))
2821 | (iRounding << X86_FCW_RC_SHIFT);
2822 /*if (iMask & 1) State.FCW ^= X86_FCW_MASK_ALL;*/
2823 State.FCW |= (iMask >> 1) << X86_FCW_OM_BIT;
2824 g_aFpuStD80[iFn].pfn(&State, &uFswOut, &OutVal, &InVal);
2825 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u/%u */\n",
2826 State.FCW, State.FSW, uFswOut, GenFormatR80(&InVal),
2827 GenFormatD80(&OutVal), iTest, iRounding, iMask);
2828 }
2829 }
2830 }
2831 GenerateArrayEnd(pOut, g_aFpuStD80[iFn].pszName);
2832 }
2833}
2834#endif
2835
2836
2837static void FpuStD80Test(void)
2838{
2839 X86FXSTATE State;
2840 RT_ZERO(State);
2841 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuStD80); iFn++)
2842 {
2843 RTTestSub(g_hTest, g_aFpuStD80[iFn].pszName);
2844
2845 uint32_t const cTests = *g_aFpuStD80[iFn].pcTests;
2846 FPU_ST_D80_TEST_T const * const paTests = g_aFpuStD80[iFn].paTests;
2847 PFNIEMAIMPLFPUSTR80TOD80 pfn = g_aFpuStD80[iFn].pfn;
2848 uint32_t const cVars = 1 + (g_aFpuStD80[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && g_aFpuStD80[iFn].pfnNative);
2849 if (!cTests) RTTestSkipped(g_hTest, "no tests");
2850 for (uint32_t iVar = 0; iVar < cVars; iVar++)
2851 {
2852 for (uint32_t iTest = 0; iTest < cTests; iTest++)
2853 {
2854 RTFLOAT80U const InVal = paTests[iTest].InVal;
2855 uint16_t uFswOut = 0;
2856 RTPBCD80U OutVal = RTPBCD80U_INIT_ZERO(0);
2857 State.FCW = paTests[iTest].fFcw;
2858 State.FSW = paTests[iTest].fFswIn;
2859 pfn(&State, &uFswOut, &OutVal, &InVal);
2860 if ( uFswOut != paTests[iTest].fFswOut
2861 || !RTPBCD80U_ARE_IDENTICAL(&OutVal, &paTests[iTest].OutVal))
2862 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in=%s\n"
2863 "%s -> fsw=%#06x %s\n"
2864 "%s expected %#06x %s%s%s (%s)\n",
2865 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
2866 FormatR80(&paTests[iTest].InVal),
2867 iVar ? " " : "", uFswOut, FormatD80(&OutVal),
2868 iVar ? " " : "", paTests[iTest].fFswOut, FormatD80(&paTests[iTest].OutVal),
2869 FswDiff(uFswOut, paTests[iTest].fFswOut),
2870 RTPBCD80U_ARE_IDENTICAL(&OutVal, &paTests[iTest].OutVal) ? " - val" : "",
2871 FormatFcw(paTests[iTest].fFcw) );
2872 }
2873 pfn = g_aFpuStD80[iFn].pfnNative;
2874 }
2875 }
2876}
2877
2878
2879
2880/*********************************************************************************************************************************
2881* x87 FPU Binary Operations *
2882*********************************************************************************************************************************/
2883
2884/*
2885 * Binary FPU operations on two 80-bit floating point values.
2886 */
2887TYPEDEF_SUBTEST_TYPE(FPU_BINARY_R80_T, FPU_BINARY_R80_TEST_T, PFNIEMAIMPLFPUR80);
2888
2889static const FPU_BINARY_R80_T g_aFpuBinaryR80[] =
2890{
2891 ENTRY(fadd_r80_by_r80),
2892 ENTRY(fsub_r80_by_r80),
2893 ENTRY(fsubr_r80_by_r80),
2894 ENTRY(fmul_r80_by_r80),
2895 ENTRY(fdiv_r80_by_r80),
2896 ENTRY(fdivr_r80_by_r80),
2897 ENTRY(fprem_r80_by_r80),
2898 ENTRY(fprem1_r80_by_r80),
2899 ENTRY(fscale_r80_by_r80),
2900 ENTRY_AMD( fpatan_r80_by_r80, 0), // C1 and rounding differs on AMD
2901 ENTRY_INTEL(fpatan_r80_by_r80, 0), // C1 and rounding differs on AMD
2902 ENTRY_AMD( fyl2x_r80_by_r80, 0), // C1 and rounding differs on AMD
2903 ENTRY_INTEL(fyl2x_r80_by_r80, 0), // C1 and rounding differs on AMD
2904 ENTRY_AMD( fyl2xp1_r80_by_r80, 0), // C1 and rounding differs on AMD
2905 ENTRY_INTEL(fyl2xp1_r80_by_r80, 0), // C1 and rounding differs on AMD
2906};
2907
2908#ifdef TSTIEMAIMPL_WITH_GENERATOR
2909static void FpuBinaryR80Generate(PRTSTREAM pOut, PRTSTREAM pOutCpu, uint32_t cTests)
2910{
2911 static struct { RTFLOAT80U Val1, Val2; } const s_aSpecials[] =
2912 {
2913 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
2914 RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS) }, /* whatever */
2915 };
2916
2917 X86FXSTATE State;
2918 RT_ZERO(State);
2919 uint32_t cMinNormalPairs = cTests / 4;
2920 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuBinaryR80); iFn++)
2921 {
2922 PFNIEMAIMPLFPUR80 const pfn = g_aFpuBinaryR80[iFn].pfnNative ? g_aFpuBinaryR80[iFn].pfnNative : g_aFpuBinaryR80[iFn].pfn;
2923 PRTSTREAM pOutFn = pOut;
2924 if (g_aFpuBinaryR80[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE)
2925 {
2926 if (g_aFpuBinaryR80[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour)
2927 continue;
2928 pOutFn = pOutCpu;
2929 }
2930
2931 GenerateArrayStart(pOutFn, g_aFpuBinaryR80[iFn].pszName, "FPU_BINARY_R80_TEST_T");
2932 uint32_t cNormalInputPairs = 0;
2933 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
2934 {
2935 RTFLOAT80U const InVal1 = iTest < cTests ? RandR80Ex() : s_aSpecials[iTest - cTests].Val1;
2936 RTFLOAT80U const InVal2 = iTest < cTests ? RandR80Ex() : s_aSpecials[iTest - cTests].Val2;
2937 if (RTFLOAT80U_IS_NORMAL(&InVal1) && RTFLOAT80U_IS_NORMAL(&InVal2))
2938 cNormalInputPairs++;
2939 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
2940 {
2941 iTest -= 1;
2942 continue;
2943 }
2944
2945 uint16_t const fFcw = RandFcw();
2946 State.FSW = RandFsw();
2947
2948 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
2949 {
2950 for (uint16_t iPrecision = 0; iPrecision < 4; iPrecision++)
2951 {
2952 for (uint16_t iMask = 0; iMask <= X86_FCW_MASK_ALL; iMask += X86_FCW_MASK_ALL)
2953 {
2954 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_PC_MASK | X86_FCW_MASK_ALL))
2955 | (iRounding << X86_FCW_RC_SHIFT)
2956 | (iPrecision << X86_FCW_PC_SHIFT)
2957 | iMask;
2958 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 };
2959 pfn(&State, &Res, &InVal1, &InVal2);
2960 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/%c */\n",
2961 State.FCW, State.FSW, Res.FSW, GenFormatR80(&InVal1), GenFormatR80(&InVal2),
2962 GenFormatR80(&Res.r80Result), iTest, iRounding, iPrecision, iMask ? 'c' : 'u');
2963 }
2964 }
2965 }
2966 }
2967 GenerateArrayEnd(pOutFn, g_aFpuBinaryR80[iFn].pszName);
2968 }
2969}
2970#endif
2971
2972
2973static void FpuBinaryR80Test(void)
2974{
2975 X86FXSTATE State;
2976 RT_ZERO(State);
2977 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuBinaryR80); iFn++)
2978 {
2979 RTTestSub(g_hTest, g_aFpuBinaryR80[iFn].pszName);
2980
2981 uint32_t const cTests = *g_aFpuBinaryR80[iFn].pcTests;
2982 FPU_BINARY_R80_TEST_T const * const paTests = g_aFpuBinaryR80[iFn].paTests;
2983 PFNIEMAIMPLFPUR80 pfn = g_aFpuBinaryR80[iFn].pfn;
2984 uint32_t const cVars = 1 + (g_aFpuBinaryR80[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && g_aFpuBinaryR80[iFn].pfnNative);
2985 if (!cTests) RTTestSkipped(g_hTest, "no tests");
2986 for (uint32_t iVar = 0; iVar < cVars; iVar++)
2987 {
2988 for (uint32_t iTest = 0; iTest < cTests; iTest++)
2989 {
2990 RTFLOAT80U const InVal1 = paTests[iTest].InVal1;
2991 RTFLOAT80U const InVal2 = paTests[iTest].InVal2;
2992 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 };
2993 State.FCW = paTests[iTest].fFcw;
2994 State.FSW = paTests[iTest].fFswIn;
2995 pfn(&State, &Res, &InVal1, &InVal2);
2996 if ( Res.FSW != paTests[iTest].fFswOut
2997 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].OutVal))
2998 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in1=%s in2=%s\n"
2999 "%s -> fsw=%#06x %s\n"
3000 "%s expected %#06x %s%s%s (%s)\n",
3001 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
3002 FormatR80(&paTests[iTest].InVal1), FormatR80(&paTests[iTest].InVal2),
3003 iVar ? " " : "", Res.FSW, FormatR80(&Res.r80Result),
3004 iVar ? " " : "", paTests[iTest].fFswOut, FormatR80(&paTests[iTest].OutVal),
3005 FswDiff(Res.FSW, paTests[iTest].fFswOut),
3006 RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].OutVal) ? " - val" : "",
3007 FormatFcw(paTests[iTest].fFcw) );
3008 }
3009 pfn = g_aFpuBinaryR80[iFn].pfnNative;
3010 }
3011 }
3012}
3013
3014
3015/*
3016 * Binary FPU operations on one 80-bit floating point value and one 64-bit or 32-bit one.
3017 */
3018#ifdef TSTIEMAIMPL_WITH_GENERATOR
3019static struct { RTFLOAT80U Val1; RTFLOAT64U Val2; } const s_aFpuBinaryR64Specials[] =
3020{
3021 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3022 RTFLOAT64U_INIT_C(0, 0xfeeeeddddcccc, RTFLOAT64U_EXP_BIAS) }, /* whatever */
3023};
3024static struct { RTFLOAT80U Val1; RTFLOAT32U Val2; } const s_aFpuBinaryR32Specials[] =
3025{
3026 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3027 RTFLOAT32U_INIT_C(0, 0x7fffee, RTFLOAT32U_EXP_BIAS) }, /* whatever */
3028};
3029
3030# define GEN_FPU_BINARY_SMALL(a_cBits, a_rdType, a_aSubTests, a_TestType) \
3031static void FpuBinaryR ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
3032{ \
3033 X86FXSTATE State; \
3034 RT_ZERO(State); \
3035 uint32_t cMinNormalPairs = cTests / 4; \
3036 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
3037 { \
3038 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
3039 uint32_t cNormalInputPairs = 0; \
3040 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aFpuBinaryR ## a_cBits ## Specials); iTest += 1) \
3041 { \
3042 RTFLOAT80U const InVal1 = iTest < cTests ? RandR80Ex() \
3043 : s_aFpuBinaryR ## a_cBits ## Specials[iTest - cTests].Val1; \
3044 a_rdType const InVal2 = iTest < cTests ? RandR ## a_cBits ## Src(a_cBits) \
3045 : s_aFpuBinaryR ## a_cBits ## Specials[iTest - cTests].Val2; \
3046 if (RTFLOAT80U_IS_NORMAL(&InVal1) && a_rdType ## _IS_NORMAL(&InVal2)) \
3047 cNormalInputPairs++; \
3048 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests) \
3049 { \
3050 iTest -= 1; \
3051 continue; \
3052 } \
3053 \
3054 uint16_t const fFcw = RandFcw(); \
3055 State.FSW = RandFsw(); \
3056 \
3057 for (uint16_t iRounding = 0; iRounding < 4; iRounding++) \
3058 { \
3059 for (uint16_t iPrecision = 0; iPrecision < 4; iPrecision++) \
3060 { \
3061 for (uint16_t iMask = 0; iMask <= X86_FCW_MASK_ALL; iMask += X86_FCW_MASK_ALL) \
3062 { \
3063 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_PC_MASK | X86_FCW_MASK_ALL)) \
3064 | (iRounding << X86_FCW_RC_SHIFT) \
3065 | (iPrecision << X86_FCW_PC_SHIFT) \
3066 | iMask; \
3067 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 }; \
3068 a_aSubTests[iFn].pfn(&State, &Res, &InVal1, &InVal2); \
3069 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/%c */\n", \
3070 State.FCW, State.FSW, Res.FSW, GenFormatR80(&InVal1), GenFormatR ## a_cBits(&InVal2), \
3071 GenFormatR80(&Res.r80Result), iTest, iRounding, iPrecision, iMask ? 'c' : 'u'); \
3072 } \
3073 } \
3074 } \
3075 } \
3076 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
3077 } \
3078}
3079#else
3080# define GEN_FPU_BINARY_SMALL(a_cBits, a_rdType, a_aSubTests, a_TestType)
3081#endif
3082
3083#define TEST_FPU_BINARY_SMALL(a_cBits, a_rdType, a_SubTestType, a_aSubTests, a_TestType) \
3084TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLFPUR ## a_cBits); \
3085\
3086static const a_SubTestType a_aSubTests[] = \
3087{ \
3088 ENTRY(RT_CONCAT(fadd_r80_by_r, a_cBits)), \
3089 ENTRY(RT_CONCAT(fmul_r80_by_r, a_cBits)), \
3090 ENTRY(RT_CONCAT(fsub_r80_by_r, a_cBits)), \
3091 ENTRY(RT_CONCAT(fsubr_r80_by_r, a_cBits)), \
3092 ENTRY(RT_CONCAT(fdiv_r80_by_r, a_cBits)), \
3093 ENTRY(RT_CONCAT(fdivr_r80_by_r, a_cBits)), \
3094}; \
3095\
3096GEN_FPU_BINARY_SMALL(a_cBits, a_rdType, a_aSubTests, a_TestType) \
3097\
3098static void FpuBinaryR ## a_cBits ##Test(void) \
3099{ \
3100 X86FXSTATE State; \
3101 RT_ZERO(State); \
3102 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
3103 { \
3104 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
3105 \
3106 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
3107 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
3108 PFNIEMAIMPLFPUR ## a_cBits pfn = a_aSubTests[iFn].pfn; \
3109 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
3110 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
3111 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
3112 { \
3113 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
3114 { \
3115 RTFLOAT80U const InVal1 = paTests[iTest].InVal1; \
3116 a_rdType const InVal2 = paTests[iTest].InVal2; \
3117 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 }; \
3118 State.FCW = paTests[iTest].fFcw; \
3119 State.FSW = paTests[iTest].fFswIn; \
3120 pfn(&State, &Res, &InVal1, &InVal2); \
3121 if ( Res.FSW != paTests[iTest].fFswOut \
3122 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].OutVal)) \
3123 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in1=%s in2=%s\n" \
3124 "%s -> fsw=%#06x %s\n" \
3125 "%s expected %#06x %s%s%s (%s)\n", \
3126 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, \
3127 FormatR80(&paTests[iTest].InVal1), FormatR ## a_cBits(&paTests[iTest].InVal2), \
3128 iVar ? " " : "", Res.FSW, FormatR80(&Res.r80Result), \
3129 iVar ? " " : "", paTests[iTest].fFswOut, FormatR80(&paTests[iTest].OutVal), \
3130 FswDiff(Res.FSW, paTests[iTest].fFswOut), \
3131 RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].OutVal) ? " - val" : "", \
3132 FormatFcw(paTests[iTest].fFcw) ); \
3133 } \
3134 pfn = a_aSubTests[iFn].pfnNative; \
3135 } \
3136 } \
3137}
3138
3139TEST_FPU_BINARY_SMALL(64, RTFLOAT64U, FPU_BINARY_R64_T, g_aFpuBinaryR64, FPU_BINARY_R64_TEST_T)
3140TEST_FPU_BINARY_SMALL(32, RTFLOAT32U, FPU_BINARY_R32_T, g_aFpuBinaryR32, FPU_BINARY_R32_TEST_T)
3141
3142
3143/*
3144 * Binary operations on 80-, 64- and 32-bit floating point only affecting FSW.
3145 */
3146#ifdef TSTIEMAIMPL_WITH_GENERATOR
3147static struct { RTFLOAT80U Val1, Val2; } const s_aFpuBinaryFswR80Specials[] =
3148{
3149 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3150 RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS) }, /* whatever */
3151};
3152static struct { RTFLOAT80U Val1; RTFLOAT64U Val2; } const s_aFpuBinaryFswR64Specials[] =
3153{
3154 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3155 RTFLOAT64U_INIT_C(0, 0xfeeeeddddcccc, RTFLOAT64U_EXP_BIAS) }, /* whatever */
3156};
3157static struct { RTFLOAT80U Val1; RTFLOAT32U Val2; } const s_aFpuBinaryFswR32Specials[] =
3158{
3159 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3160 RTFLOAT32U_INIT_C(0, 0x7fffee, RTFLOAT32U_EXP_BIAS) }, /* whatever */
3161};
3162
3163# define GEN_FPU_BINARY_FSW(a_cBits, a_rdType, a_aSubTests, a_TestType) \
3164static void FpuBinaryFswR ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
3165{ \
3166 X86FXSTATE State; \
3167 RT_ZERO(State); \
3168 uint32_t cMinNormalPairs = cTests / 4; \
3169 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
3170 { \
3171 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
3172 uint32_t cNormalInputPairs = 0; \
3173 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aFpuBinaryFswR ## a_cBits ## Specials); iTest += 1) \
3174 { \
3175 RTFLOAT80U const InVal1 = iTest < cTests ? RandR80Ex() \
3176 : s_aFpuBinaryFswR ## a_cBits ## Specials[iTest - cTests].Val1; \
3177 a_rdType const InVal2 = iTest < cTests ? RandR ## a_cBits ## Src(a_cBits) \
3178 : s_aFpuBinaryFswR ## a_cBits ## Specials[iTest - cTests].Val2; \
3179 if (RTFLOAT80U_IS_NORMAL(&InVal1) && a_rdType ## _IS_NORMAL(&InVal2)) \
3180 cNormalInputPairs++; \
3181 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests) \
3182 { \
3183 iTest -= 1; \
3184 continue; \
3185 } \
3186 \
3187 uint16_t const fFcw = RandFcw(); \
3188 State.FSW = RandFsw(); \
3189 \
3190 /* Guess these aren't affected by precision or rounding, so just flip the exception mask. */ \
3191 for (uint16_t iMask = 0; iMask <= X86_FCW_MASK_ALL; iMask += X86_FCW_MASK_ALL) \
3192 { \
3193 State.FCW = (fFcw & ~(X86_FCW_MASK_ALL)) | iMask; \
3194 uint16_t uFswOut = 0; \
3195 a_aSubTests[iFn].pfn(&State, &uFswOut, &InVal1, &InVal2); \
3196 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%c */\n", \
3197 State.FCW, State.FSW, uFswOut, GenFormatR80(&InVal1), GenFormatR ## a_cBits(&InVal2), \
3198 iTest, iMask ? 'c' : 'u'); \
3199 } \
3200 } \
3201 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
3202 } \
3203}
3204#else
3205# define GEN_FPU_BINARY_FSW(a_cBits, a_rdType, a_aSubTests, a_TestType)
3206#endif
3207
3208#define TEST_FPU_BINARY_FSW(a_cBits, a_rdType, a_SubTestType, a_aSubTests, a_TestType, ...) \
3209TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLFPUR ## a_cBits ## FSW); \
3210\
3211static const a_SubTestType a_aSubTests[] = \
3212{ \
3213 ENTRY(RT_CONCAT(fcom_r80_by_r, a_cBits)), \
3214 __VA_ARGS__\
3215}; \
3216\
3217GEN_FPU_BINARY_FSW(a_cBits, a_rdType, a_aSubTests, a_TestType) \
3218\
3219static void FpuBinaryFswR ## a_cBits ##Test(void) \
3220{ \
3221 X86FXSTATE State; \
3222 RT_ZERO(State); \
3223 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
3224 { \
3225 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
3226 \
3227 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
3228 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
3229 PFNIEMAIMPLFPUR ## a_cBits ## FSW pfn = a_aSubTests[iFn].pfn; \
3230 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
3231 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
3232 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
3233 { \
3234 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
3235 { \
3236 RTFLOAT80U const InVal1 = paTests[iTest].InVal1; \
3237 a_rdType const InVal2 = paTests[iTest].InVal2; \
3238 State.FCW = paTests[iTest].fFcw; \
3239 State.FSW = paTests[iTest].fFswIn; \
3240 uint16_t uFswOut = 0; \
3241 pfn(&State, &uFswOut, &InVal1, &InVal2); \
3242 if (uFswOut != paTests[iTest].fFswOut) \
3243 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in1=%s in2=%s\n" \
3244 "%s -> fsw=%#06x\n" \
3245 "%s expected %#06x %s (%s)\n", \
3246 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, \
3247 FormatR80(&paTests[iTest].InVal1), FormatR ## a_cBits(&paTests[iTest].InVal2), \
3248 iVar ? " " : "", uFswOut, \
3249 iVar ? " " : "", paTests[iTest].fFswOut, \
3250 FswDiff(uFswOut, paTests[iTest].fFswOut), FormatFcw(paTests[iTest].fFcw) ); \
3251 } \
3252 pfn = a_aSubTests[iFn].pfnNative; \
3253 } \
3254 } \
3255}
3256
3257TEST_FPU_BINARY_FSW(80, RTFLOAT80U, FPU_BINARY_FSW_R80_T, g_aFpuBinaryFswR80, FPU_BINARY_R80_TEST_T, ENTRY(fucom_r80_by_r80))
3258TEST_FPU_BINARY_FSW(64, RTFLOAT64U, FPU_BINARY_FSW_R64_T, g_aFpuBinaryFswR64, FPU_BINARY_R64_TEST_T, RT_NOTHING)
3259TEST_FPU_BINARY_FSW(32, RTFLOAT32U, FPU_BINARY_FSW_R32_T, g_aFpuBinaryFswR32, FPU_BINARY_R32_TEST_T, RT_NOTHING)
3260
3261
3262/*
3263 * Binary operations on 80-bit floating point that effects only EFLAGS and possibly FSW.
3264 */
3265TYPEDEF_SUBTEST_TYPE(FPU_BINARY_EFL_R80_T, FPU_BINARY_EFL_R80_TEST_T, PFNIEMAIMPLFPUR80EFL);
3266
3267static const FPU_BINARY_EFL_R80_T g_aFpuBinaryEflR80[] =
3268{
3269 ENTRY(fcomi_r80_by_r80),
3270 ENTRY(fucomi_r80_by_r80),
3271};
3272
3273#ifdef TSTIEMAIMPL_WITH_GENERATOR
3274static struct { RTFLOAT80U Val1, Val2; } const s_aFpuBinaryEflR80Specials[] =
3275{
3276 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3277 RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS) }, /* whatever */
3278};
3279
3280static void FpuBinaryEflR80Generate(PRTSTREAM pOut, uint32_t cTests)
3281{
3282 X86FXSTATE State;
3283 RT_ZERO(State);
3284 uint32_t cMinNormalPairs = cTests / 4;
3285 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuBinaryEflR80); iFn++)
3286 {
3287 GenerateArrayStart(pOut, g_aFpuBinaryEflR80[iFn].pszName, "FPU_BINARY_EFL_R80_TEST_T");
3288 uint32_t cNormalInputPairs = 0;
3289 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aFpuBinaryEflR80Specials); iTest += 1)
3290 {
3291 RTFLOAT80U const InVal1 = iTest < cTests ? RandR80Ex() : s_aFpuBinaryEflR80Specials[iTest - cTests].Val1;
3292 RTFLOAT80U const InVal2 = iTest < cTests ? RandR80Ex() : s_aFpuBinaryEflR80Specials[iTest - cTests].Val2;
3293 if (RTFLOAT80U_IS_NORMAL(&InVal1) && RTFLOAT80U_IS_NORMAL(&InVal2))
3294 cNormalInputPairs++;
3295 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
3296 {
3297 iTest -= 1;
3298 continue;
3299 }
3300
3301 uint16_t const fFcw = RandFcw();
3302 State.FSW = RandFsw();
3303
3304 /* Guess these aren't affected by precision or rounding, so just flip the exception mask. */
3305 for (uint16_t iMask = 0; iMask <= X86_FCW_MASK_ALL; iMask += X86_FCW_MASK_ALL)
3306 {
3307 State.FCW = (fFcw & ~(X86_FCW_MASK_ALL)) | iMask;
3308 uint16_t uFswOut = 0;
3309 uint32_t fEflOut = g_aFpuBinaryEflR80[iFn].pfn(&State, &uFswOut, &InVal1, &InVal2);
3310 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s, %#08x }, /* #%u/%c */\n",
3311 State.FCW, State.FSW, uFswOut, GenFormatR80(&InVal1), GenFormatR80(&InVal2), fEflOut,
3312 iTest, iMask ? 'c' : 'u');
3313 }
3314 }
3315 GenerateArrayEnd(pOut, g_aFpuBinaryEflR80[iFn].pszName);
3316 }
3317}
3318#endif /*TSTIEMAIMPL_WITH_GENERATOR*/
3319
3320static void FpuBinaryEflR80Test(void)
3321{
3322 X86FXSTATE State;
3323 RT_ZERO(State);
3324 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuBinaryEflR80); iFn++)
3325 {
3326 RTTestSub(g_hTest, g_aFpuBinaryEflR80[iFn].pszName);
3327
3328 uint32_t const cTests = *g_aFpuBinaryEflR80[iFn].pcTests;
3329 FPU_BINARY_EFL_R80_TEST_T const * const paTests = g_aFpuBinaryEflR80[iFn].paTests;
3330 PFNIEMAIMPLFPUR80EFL pfn = g_aFpuBinaryEflR80[iFn].pfn;
3331 uint32_t const cVars = 1 + (g_aFpuBinaryEflR80[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && g_aFpuBinaryEflR80[iFn].pfnNative);
3332 if (!cTests) RTTestSkipped(g_hTest, "no tests");
3333 for (uint32_t iVar = 0; iVar < cVars; iVar++)
3334 {
3335 for (uint32_t iTest = 0; iTest < cTests; iTest++)
3336 {
3337 RTFLOAT80U const InVal1 = paTests[iTest].InVal1;
3338 RTFLOAT80U const InVal2 = paTests[iTest].InVal2;
3339 State.FCW = paTests[iTest].fFcw;
3340 State.FSW = paTests[iTest].fFswIn;
3341 uint16_t uFswOut = 0;
3342 uint32_t fEflOut = pfn(&State, &uFswOut, &InVal1, &InVal2);
3343 if ( uFswOut != paTests[iTest].fFswOut
3344 || fEflOut != paTests[iTest].fEflOut)
3345 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in1=%s in2=%s\n"
3346 "%s -> fsw=%#06x efl=%#08x\n"
3347 "%s expected %#06x %#08x %s (%s)\n",
3348 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
3349 FormatR80(&paTests[iTest].InVal1), FormatR80(&paTests[iTest].InVal2),
3350 iVar ? " " : "", uFswOut, fEflOut,
3351 iVar ? " " : "", paTests[iTest].fFswOut, paTests[iTest].fEflOut,
3352 EFlagsDiff(fEflOut, paTests[iTest].fEflOut), FormatFcw(paTests[iTest].fFcw));
3353 }
3354 pfn = g_aFpuBinaryEflR80[iFn].pfnNative;
3355 }
3356 }
3357}
3358
3359
3360
3361int main(int argc, char **argv)
3362{
3363 int rc = RTR3InitExe(argc, &argv, 0);
3364 if (RT_FAILURE(rc))
3365 return RTMsgInitFailure(rc);
3366
3367 /*
3368 * Determin the host CPU.
3369 * If not using the IEMAllAImpl.asm code, this will be set to Intel.
3370 */
3371#if (defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && !defined(IEM_WITHOUT_ASSEMBLY)
3372 g_idxCpuEflFlavour = ASMIsAmdCpu() || ASMIsHygonCpu()
3373 ? IEMTARGETCPU_EFL_BEHAVIOR_AMD
3374 : IEMTARGETCPU_EFL_BEHAVIOR_INTEL;
3375#else
3376 g_idxCpuEflFlavour = IEMTARGETCPU_EFL_BEHAVIOR_INTEL;
3377#endif
3378
3379 /*
3380 * Parse arguments.
3381 */
3382 enum { kModeNotSet, kModeTest, kModeGenerate }
3383 enmMode = kModeNotSet;
3384 bool fInt = true;
3385 bool fFpuLdSt = true;
3386 bool fFpuBinary1 = true;
3387 bool fFpuBinary2 = true;
3388 bool fFpuOther = true;
3389 bool fCpuData = true;
3390 bool fCommonData = true;
3391 uint32_t const cDefaultTests = 96;
3392 uint32_t cTests = cDefaultTests;
3393 RTGETOPTDEF const s_aOptions[] =
3394 {
3395 // mode:
3396 { "--generate", 'g', RTGETOPT_REQ_NOTHING },
3397 { "--test", 't', RTGETOPT_REQ_NOTHING },
3398 // test selection (both)
3399 { "--all", 'a', RTGETOPT_REQ_NOTHING },
3400 { "--none", 'z', RTGETOPT_REQ_NOTHING },
3401 { "--zap", 'z', RTGETOPT_REQ_NOTHING },
3402 { "--fpu-ld-st", 'F', RTGETOPT_REQ_NOTHING }, /* FPU stuff is upper case */
3403 { "--fpu-load-store", 'F', RTGETOPT_REQ_NOTHING },
3404 { "--fpu-binary-1", 'B', RTGETOPT_REQ_NOTHING },
3405 { "--fpu-binary-2", 'P', RTGETOPT_REQ_NOTHING },
3406 { "--fpu-other", 'O', RTGETOPT_REQ_NOTHING },
3407 { "--int", 'i', RTGETOPT_REQ_NOTHING },
3408 // generation parameters
3409 { "--common", 'm', RTGETOPT_REQ_NOTHING },
3410 { "--cpu", 'c', RTGETOPT_REQ_NOTHING },
3411 { "--number-of-tests", 'n', RTGETOPT_REQ_UINT32 },
3412 };
3413
3414 RTGETOPTSTATE State;
3415 rc = RTGetOptInit(&State, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
3416 AssertRCReturn(rc, RTEXITCODE_FAILURE);
3417
3418 RTGETOPTUNION ValueUnion;
3419 while ((rc = RTGetOpt(&State, &ValueUnion)))
3420 {
3421 switch (rc)
3422 {
3423 case 'g':
3424 enmMode = kModeGenerate;
3425 break;
3426 case 't':
3427 enmMode = kModeTest;
3428 break;
3429 case 'a':
3430 fCpuData = true;
3431 fCommonData = true;
3432 fInt = true;
3433 fFpuLdSt = true;
3434 fFpuBinary1 = true;
3435 fFpuBinary2 = true;
3436 fFpuOther = true;
3437 break;
3438 case 'z':
3439 fCpuData = false;
3440 fCommonData = false;
3441 fInt = false;
3442 fFpuLdSt = false;
3443 fFpuBinary1 = false;
3444 fFpuBinary2 = false;
3445 fFpuOther = false;
3446 break;
3447 case 'F':
3448 fFpuLdSt = true;
3449 break;
3450 case 'O':
3451 fFpuOther = true;
3452 break;
3453 case 'B':
3454 fFpuBinary1 = true;
3455 break;
3456 case 'P':
3457 fFpuBinary2 = true;
3458 break;
3459 case 'i':
3460 fInt = true;
3461 break;
3462 case 'm':
3463 fCommonData = true;
3464 break;
3465 case 'c':
3466 fCpuData = true;
3467 break;
3468 case 'n':
3469 cTests = ValueUnion.u32;
3470 break;
3471 case 'h':
3472 RTPrintf("usage: %s <-g|-t> [options]\n"
3473 "\n"
3474 "Mode:\n"
3475 " -g, --generate\n"
3476 " Generate test data.\n"
3477 " -t, --test\n"
3478 " Execute tests.\n"
3479 "\n"
3480 "Test selection (both modes):\n"
3481 " -a, --all\n"
3482 " Enable all tests and generated test data. (default)\n"
3483 " -z, --zap, --none\n"
3484 " Disable all tests and test data types.\n"
3485 " -i, --int\n"
3486 " Enable non-FPU tests.\n"
3487 " -F, --fpu-ld-st\n"
3488 " Enable FPU load and store tests.\n"
3489 " -B, --fpu-binary-1\n"
3490 " Enable FPU binary 80-bit FP tests.\n"
3491 " -P, --fpu-binary-2\n"
3492 " Enable FPU binary 64- and 32-bit FP tests.\n"
3493 " -O, --fpu-other\n"
3494 " Enable other FPU tests.\n"
3495 "\n"
3496 "Generation:\n"
3497 " -m, --common\n"
3498 " Enable generating common test data.\n"
3499 " -c, --only-cpu\n"
3500 " Enable generating CPU specific test data.\n"
3501 " -n, --number-of-test <count>\n"
3502 " Number of tests to generate. Default: %u\n"
3503 , argv[0], cDefaultTests);
3504 return RTEXITCODE_SUCCESS;
3505 default:
3506 return RTGetOptPrintError(rc, &ValueUnion);
3507 }
3508 }
3509
3510 /*
3511 * Generate data?
3512 */
3513 if (enmMode == kModeGenerate)
3514 {
3515#ifdef TSTIEMAIMPL_WITH_GENERATOR
3516 char szCpuDesc[256] = {0};
3517 RTMpGetDescription(NIL_RTCPUID, szCpuDesc, sizeof(szCpuDesc));
3518 const char * const pszCpuType = g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD ? "Amd" : "Intel";
3519# if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
3520 const char * const pszBitBucket = "NUL";
3521# else
3522 const char * const pszBitBucket = "/dev/null";
3523# endif
3524
3525 if (cTests == 0)
3526 cTests = cDefaultTests;
3527 g_cZeroDstTests = RT_MIN(cTests / 16, 32);
3528 g_cZeroSrcTests = g_cZeroDstTests * 2;
3529
3530 if (fInt)
3531 {
3532 const char *pszDataFile = fCommonData ? "tstIEMAImplDataInt.cpp" : pszBitBucket;
3533 PRTSTREAM pStrmData = GenerateOpenWithHdr(pszDataFile, szCpuDesc, NULL);
3534 const char *pszDataCpuFile = !fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
3535 ? "tstIEMAImplDataInt-Amd.cpp" : "tstIEMAImplDataInt-Intel.cpp";
3536 PRTSTREAM pStrmDataCpu = GenerateOpenWithHdr(pszDataCpuFile, szCpuDesc, pszCpuType);
3537 if (!pStrmData || !pStrmDataCpu)
3538 return RTEXITCODE_FAILURE;
3539
3540 BinU8Generate( pStrmData, pStrmDataCpu, cTests);
3541 BinU16Generate(pStrmData, pStrmDataCpu, cTests);
3542 BinU32Generate(pStrmData, pStrmDataCpu, cTests);
3543 BinU64Generate(pStrmData, pStrmDataCpu, cTests);
3544 ShiftDblGenerate(pStrmDataCpu, RT_MAX(cTests, 128));
3545 UnaryGenerate(pStrmData, cTests);
3546 ShiftGenerate(pStrmDataCpu, cTests);
3547 MulDivGenerate(pStrmDataCpu, cTests);
3548
3549 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile,
3550 GenerateFooterAndClose(pStrmData, pszDataFile, RTEXITCODE_SUCCESS));
3551 if (rcExit != RTEXITCODE_SUCCESS)
3552 return rcExit;
3553 }
3554
3555 if (fFpuLdSt)
3556 {
3557 const char *pszDataFile = fCommonData ? "tstIEMAImplDataFpuLdSt.cpp" : pszBitBucket;
3558 PRTSTREAM pStrmData = GenerateOpenWithHdr(pszDataFile, szCpuDesc, NULL);
3559 const char *pszDataCpuFile = !fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
3560 ? "tstIEMAImplDataFpuLdSt-Amd.cpp" : "tstIEMAImplDataFpuLdSt-Intel.cpp";
3561 PRTSTREAM pStrmDataCpu = GenerateOpenWithHdr(pszDataCpuFile, szCpuDesc, pszCpuType);
3562 if (!pStrmData || !pStrmDataCpu)
3563 return RTEXITCODE_FAILURE;
3564
3565 FpuLdConstGenerate(pStrmData, cTests);
3566 FpuLdIntGenerate(pStrmData, cTests);
3567 FpuLdD80Generate(pStrmData, cTests);
3568 FpuStIntGenerate(pStrmData, pStrmDataCpu, cTests);
3569 FpuStD80Generate(pStrmData, cTests);
3570 cTests = RT_MAX(cTests, 384); /* need better coverage for the next ones. */
3571 FpuLdMemGenerate(pStrmData, cTests);
3572 FpuStMemGenerate(pStrmData, cTests);
3573
3574 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile,
3575 GenerateFooterAndClose(pStrmData, pszDataFile, RTEXITCODE_SUCCESS));
3576 if (rcExit != RTEXITCODE_SUCCESS)
3577 return rcExit;
3578 }
3579
3580 if (fFpuBinary1)
3581 {
3582 const char *pszDataFile = fCommonData ? "tstIEMAImplDataFpuBinary1.cpp" : pszBitBucket;
3583 PRTSTREAM pStrmData = GenerateOpenWithHdr(pszDataFile, szCpuDesc, NULL);
3584 const char *pszDataCpuFile = !fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
3585 ? "tstIEMAImplDataFpuBinary1-Amd.cpp" : "tstIEMAImplDataFpuBinary1-Intel.cpp";
3586 PRTSTREAM pStrmDataCpu = GenerateOpenWithHdr(pszDataCpuFile, szCpuDesc, pszCpuType);
3587 if (!pStrmData || !pStrmDataCpu)
3588 return RTEXITCODE_FAILURE;
3589
3590 FpuBinaryR80Generate(pStrmData, pStrmDataCpu, cTests);
3591 FpuBinaryFswR80Generate(pStrmData, cTests);
3592 FpuBinaryEflR80Generate(pStrmData, cTests);
3593
3594 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile,
3595 GenerateFooterAndClose(pStrmData, pszDataFile, RTEXITCODE_SUCCESS));
3596 if (rcExit != RTEXITCODE_SUCCESS)
3597 return rcExit;
3598 }
3599
3600 if (fFpuBinary2)
3601 {
3602 const char *pszDataFile = fCommonData ? "tstIEMAImplDataFpuBinary2.cpp" : pszBitBucket;
3603 PRTSTREAM pStrmData = GenerateOpenWithHdr(pszDataFile, szCpuDesc, NULL);
3604 const char *pszDataCpuFile = pszBitBucket; /*!fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
3605 ? "tstIEMAImplDataFpuBinary2-Amd.cpp" : "tstIEMAImplDataFpuBinary2-Intel.cpp"; */
3606 PRTSTREAM pStrmDataCpu = GenerateOpenWithHdr(pszDataCpuFile, szCpuDesc, pszCpuType);
3607 if (!pStrmData || !pStrmDataCpu)
3608 return RTEXITCODE_FAILURE;
3609
3610 FpuBinaryR64Generate(pStrmData, cTests);
3611 FpuBinaryR32Generate(pStrmData, cTests);
3612 FpuBinaryFswR64Generate(pStrmData, cTests);
3613 FpuBinaryFswR32Generate(pStrmData, cTests);
3614
3615 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile,
3616 GenerateFooterAndClose(pStrmData, pszDataFile, RTEXITCODE_SUCCESS));
3617 if (rcExit != RTEXITCODE_SUCCESS)
3618 return rcExit;
3619 }
3620
3621# if 0
3622 if (fFpuOther)
3623 {
3624 const char *pszDataFile = fCommonData ? "tstIEMAImplDataFpuOther.cpp" : pszBitBucket;
3625 PRTSTREAM pStrmData = GenerateOpenWithHdr(pszDataFile, szCpuDesc, NULL);
3626 const char *pszDataCpuFile = !fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
3627 ? "tstIEMAImplDataFpuOther-Amd.cpp" : "tstIEMAImplDataFpuOther-Intel.cpp";
3628 PRTSTREAM pStrmDataCpu = GenerateOpenWithHdr(pszDataCpuFile, szCpuDesc, pszCpuType);
3629 if (!pStrmData || !pStrmDataCpu)
3630 return RTEXITCODE_FAILURE;
3631
3632 /* later */
3633
3634 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile,
3635 GenerateFooterAndClose(pStrmData, pszDataFile, RTEXITCODE_SUCCESS));
3636 if (rcExit != RTEXITCODE_SUCCESS)
3637 return rcExit;
3638 }
3639# endif
3640
3641 return RTEXITCODE_SUCCESS;
3642#else
3643 return RTMsgErrorExitFailure("Test data generator not compiled in!");
3644#endif
3645 }
3646
3647 /*
3648 * Do testing. Currrently disabled by default as data needs to be checked
3649 * on both intel and AMD systems first.
3650 */
3651 rc = RTTestCreate("tstIEMAimpl", &g_hTest);
3652 AssertRCReturn(rc, RTEXITCODE_FAILURE);
3653 if (enmMode == kModeTest)
3654 {
3655 RTTestBanner(g_hTest);
3656
3657 /* Allocate guarded memory for use in the tests. */
3658#define ALLOC_GUARDED_VAR(a_puVar) do { \
3659 rc = RTTestGuardedAlloc(g_hTest, sizeof(*a_puVar), sizeof(*a_puVar), false /*fHead*/, (void **)&a_puVar); \
3660 if (RT_FAILURE(rc)) RTTestFailed(g_hTest, "Failed to allocate guarded mem: " #a_puVar); \
3661 } while (0)
3662 ALLOC_GUARDED_VAR(g_pu8);
3663 ALLOC_GUARDED_VAR(g_pu16);
3664 ALLOC_GUARDED_VAR(g_pu32);
3665 ALLOC_GUARDED_VAR(g_pu64);
3666 ALLOC_GUARDED_VAR(g_pu128);
3667 ALLOC_GUARDED_VAR(g_pu8Two);
3668 ALLOC_GUARDED_VAR(g_pu16Two);
3669 ALLOC_GUARDED_VAR(g_pu32Two);
3670 ALLOC_GUARDED_VAR(g_pu64Two);
3671 ALLOC_GUARDED_VAR(g_pu128Two);
3672 ALLOC_GUARDED_VAR(g_pfEfl);
3673 if (RTTestErrorCount(g_hTest) == 0)
3674 {
3675 if (fInt)
3676 {
3677 BinU8Test();
3678 BinU16Test();
3679 BinU32Test();
3680 BinU64Test();
3681 XchgTest();
3682 XaddTest();
3683 CmpXchgTest();
3684 CmpXchg8bTest();
3685 CmpXchg16bTest();
3686 ShiftDblTest();
3687 UnaryTest();
3688 ShiftTest();
3689 MulDivTest();
3690 BswapTest();
3691 }
3692
3693 if (fFpuLdSt)
3694 {
3695 FpuLoadConstTest();
3696 FpuLdMemTest();
3697 FpuLdIntTest();
3698 FpuLdD80Test();
3699 FpuStMemTest();
3700 FpuStIntTest();
3701 FpuStD80Test();
3702 }
3703
3704 if (fFpuBinary1)
3705 {
3706 FpuBinaryR80Test();
3707 FpuBinaryFswR80Test();
3708 FpuBinaryEflR80Test();
3709 }
3710
3711 if (fFpuBinary2)
3712 {
3713 FpuBinaryR64Test();
3714 FpuBinaryR32Test();
3715 FpuBinaryFswR64Test();
3716 FpuBinaryFswR32Test();
3717 }
3718 }
3719 return RTTestSummaryAndDestroy(g_hTest);
3720 }
3721 return RTTestSkipAndDestroy(g_hTest, "unfinished testcase");
3722}
3723
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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