VirtualBox

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

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

iprt/types.h,VMM,ValKit,IPRT: Dropped the bit counts in member prefixes in the RTFLOATxxU types and added a RTFLOAT32U. Added some fld [mem] tests. bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 98.8 KB
Line 
1/* $Id: tstIEMAImpl.cpp 94261 2022-03-16 01:34:29Z vboxsync $ */
2/** @file
3 * IEM Assembly Instruction Helper Testcase.
4 */
5
6/*
7 * Copyright (C) 2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include "../include/IEMInternal.h"
23
24#include <iprt/errcore.h>
25#include <VBox/log.h>
26#include <iprt/assert.h>
27#include <iprt/ctype.h>
28#include <iprt/getopt.h>
29#include <iprt/initterm.h>
30#include <iprt/message.h>
31#include <iprt/mp.h>
32#include <iprt/rand.h>
33#include <iprt/stream.h>
34#include <iprt/string.h>
35#include <iprt/test.h>
36
37
38/*********************************************************************************************************************************
39* Structures and Typedefs *
40*********************************************************************************************************************************/
41/** @name 8-bit binary (PFNIEMAIMPLBINU8)
42 * @{ */
43typedef struct BINU8_TEST_T
44{
45 uint32_t fEflIn;
46 uint32_t fEflOut;
47 uint8_t uDstIn;
48 uint8_t uDstOut;
49 uint8_t uSrcIn;
50 uint8_t uMisc;
51} BINU8_TEST_T;
52
53typedef struct BINU8_T
54{
55 const char *pszName;
56 PFNIEMAIMPLBINU8 pfn;
57 PFNIEMAIMPLBINU8 pfnNative;
58 BINU8_TEST_T const *paTests;
59 uint32_t cTests;
60 uint32_t uExtra;
61 uint8_t idxCpuEflFlavour;
62} BINU8_T;
63/** @} */
64
65
66/** @name 16-bit binary (PFNIEMAIMPLBINU16)
67 * @{ */
68typedef struct BINU16_TEST_T
69{
70 uint32_t fEflIn;
71 uint32_t fEflOut;
72 uint16_t uDstIn;
73 uint16_t uDstOut;
74 uint16_t uSrcIn;
75 uint16_t uMisc;
76} BINU16_TEST_T;
77
78typedef struct BINU16_T
79{
80 const char *pszName;
81 PFNIEMAIMPLBINU16 pfn;
82 PFNIEMAIMPLBINU16 pfnNative;
83 BINU16_TEST_T const *paTests;
84 uint32_t cTests;
85 uint32_t uExtra;
86 uint8_t idxCpuEflFlavour;
87} BINU16_T;
88/** @} */
89
90
91/** @name 32-bit binary (PFNIEMAIMPLBINU32)
92 * @{ */
93typedef struct BINU32_TEST_T
94{
95 uint32_t fEflIn;
96 uint32_t fEflOut;
97 uint32_t uDstIn;
98 uint32_t uDstOut;
99 uint32_t uSrcIn;
100 uint32_t uMisc;
101} BINU32_TEST_T;
102
103typedef struct BINU32_T
104{
105 const char *pszName;
106 PFNIEMAIMPLBINU32 pfn;
107 PFNIEMAIMPLBINU32 pfnNative;
108 BINU32_TEST_T const *paTests;
109 uint32_t cTests;
110 uint32_t uExtra;
111 uint8_t idxCpuEflFlavour;
112} BINU32_T;
113/** @} */
114
115
116/** @name 64-bit binary (PFNIEMAIMPLBINU64)
117 * @{ */
118typedef struct BINU64_TEST_T
119{
120 uint32_t fEflIn;
121 uint32_t fEflOut;
122 uint64_t uDstIn;
123 uint64_t uDstOut;
124 uint64_t uSrcIn;
125 uint64_t uMisc;
126} BINU64_TEST_T;
127
128typedef struct BINU64_T
129{
130 const char *pszName;
131 PFNIEMAIMPLBINU64 pfn;
132 PFNIEMAIMPLBINU64 pfnNative;
133 BINU64_TEST_T const *paTests;
134 uint32_t cTests;
135 uint32_t uExtra;
136 uint8_t idxCpuEflFlavour;
137} BINU64_T;
138/** @} */
139
140
141/** @name mult/div (PFNIEMAIMPLBINU8, PFNIEMAIMPLBINU16, PFNIEMAIMPLBINU32, PFNIEMAIMPLBINU64)
142 * @{ */
143typedef struct MULDIVU8_TEST_T
144{
145 uint32_t fEflIn;
146 uint32_t fEflOut;
147 uint16_t uDstIn;
148 uint16_t uDstOut;
149 uint8_t uSrcIn;
150 int32_t rc;
151} MULDIVU8_TEST_T;
152
153typedef struct MULDIVU16_TEST_T
154{
155 uint32_t fEflIn;
156 uint32_t fEflOut;
157 uint16_t uDst1In;
158 uint16_t uDst1Out;
159 uint16_t uDst2In;
160 uint16_t uDst2Out;
161 uint16_t uSrcIn;
162 int32_t rc;
163} MULDIVU16_TEST_T;
164
165typedef struct MULDIVU32_TEST_T
166{
167 uint32_t fEflIn;
168 uint32_t fEflOut;
169 uint32_t uDst1In;
170 uint32_t uDst1Out;
171 uint32_t uDst2In;
172 uint32_t uDst2Out;
173 uint32_t uSrcIn;
174 int32_t rc;
175} MULDIVU32_TEST_T;
176
177typedef struct MULDIVU64_TEST_T
178{
179 uint32_t fEflIn;
180 uint32_t fEflOut;
181 uint64_t uDst1In;
182 uint64_t uDst1Out;
183 uint64_t uDst2In;
184 uint64_t uDst2Out;
185 uint64_t uSrcIn;
186 int32_t rc;
187} MULDIVU64_TEST_T;
188/** @} */
189
190
191/*********************************************************************************************************************************
192* Defined Constants And Macros *
193*********************************************************************************************************************************/
194#define ENTRY(a_Name) ENTRY_EX(a_Name, 0)
195#define ENTRY_EX(a_Name, a_uExtra) \
196 { RT_XSTR(a_Name), iemAImpl_ ## a_Name, NULL, \
197 g_aTests_ ## a_Name, RT_ELEMENTS(g_aTests_ ## a_Name), \
198 a_uExtra, IEMTARGETCPU_EFL_BEHAVIOR_NATIVE /* means same for all here */ }
199
200#define ENTRY_INTEL(a_Name, a_fEflUndef) ENTRY_INTEL_EX(a_Name, a_fEflUndef, 0)
201#define ENTRY_INTEL_EX(a_Name, a_fEflUndef, a_uExtra) \
202 { RT_XSTR(a_Name) "_intel", iemAImpl_ ## a_Name ## _intel, iemAImpl_ ## a_Name, \
203 g_aTests_ ## a_Name ## _intel, RT_ELEMENTS(g_aTests_ ## a_Name ## _intel), \
204 a_uExtra, IEMTARGETCPU_EFL_BEHAVIOR_INTEL }
205
206#define ENTRY_AMD(a_Name, a_fEflUndef) ENTRY_AMD_EX(a_Name, a_fEflUndef, 0)
207#define ENTRY_AMD_EX(a_Name, a_fEflUndef, a_uExtra) \
208 { RT_XSTR(a_Name) "_amd", iemAImpl_ ## a_Name ## _amd, iemAImpl_ ## a_Name, \
209 g_aTests_ ## a_Name ## _amd, RT_ELEMENTS(g_aTests_ ## a_Name ## _amd), \
210 a_uExtra, IEMTARGETCPU_EFL_BEHAVIOR_AMD }
211
212
213/*********************************************************************************************************************************
214* Global Variables *
215*********************************************************************************************************************************/
216static RTTEST g_hTest;
217static uint8_t g_idxCpuEflFlavour = IEMTARGETCPU_EFL_BEHAVIOR_INTEL;
218#ifdef TSTIEMAIMPL_WITH_GENERATOR
219static uint32_t g_cZeroDstTests = 2;
220static uint32_t g_cZeroSrcTests = 4;
221#endif
222static uint8_t *g_pu8, *g_pu8Two;
223static uint16_t *g_pu16, *g_pu16Two;
224static uint32_t *g_pu32, *g_pu32Two, *g_pfEfl;
225static uint64_t *g_pu64, *g_pu64Two;
226static RTUINT128U *g_pu128, *g_pu128Two;
227
228static char g_aszBuf[16][256];
229static unsigned g_idxBuf = 0;
230
231
232#include "tstIEMAImplData.h"
233#include "tstIEMAImplData-Intel.h"
234#include "tstIEMAImplData-Amd.h"
235
236
237/*
238 * Random helpers.
239 */
240
241static uint32_t RandEFlags(void)
242{
243 uint32_t fEfl = RTRandU32();
244 return (fEfl & X86_EFL_LIVE_MASK) | X86_EFL_RA1_MASK;
245}
246
247
248static uint8_t RandU8(void)
249{
250 return RTRandU32Ex(0, 0xff);
251}
252
253
254static uint16_t RandU16(void)
255{
256 return RTRandU32Ex(0, 0xffff);
257}
258
259
260static uint32_t RandU32(void)
261{
262 return RTRandU32();
263}
264
265
266static uint64_t RandU64(void)
267{
268 return RTRandU64();
269}
270
271
272static RTUINT128U RandU128(void)
273{
274 RTUINT128U Ret;
275 Ret.s.Hi = RTRandU64();
276 Ret.s.Lo = RTRandU64();
277 return Ret;
278}
279
280#ifdef TSTIEMAIMPL_WITH_GENERATOR
281
282static uint8_t RandU8Dst(uint32_t iTest)
283{
284 if (iTest < g_cZeroDstTests)
285 return 0;
286 return RandU8();
287}
288
289
290static uint8_t RandU8Src(uint32_t iTest)
291{
292 if (iTest < g_cZeroSrcTests)
293 return 0;
294 return RandU8();
295}
296
297
298static uint16_t RandU16Dst(uint32_t iTest)
299{
300 if (iTest < g_cZeroDstTests)
301 return 0;
302 return RandU16();
303}
304
305
306static uint16_t RandU16Src(uint32_t iTest)
307{
308 if (iTest < g_cZeroSrcTests)
309 return 0;
310 return RandU16();
311}
312
313
314static uint32_t RandU32Dst(uint32_t iTest)
315{
316 if (iTest < g_cZeroDstTests)
317 return 0;
318 return RandU32();
319}
320
321
322static uint32_t RandU32Src(uint32_t iTest)
323{
324 if (iTest < g_cZeroSrcTests)
325 return 0;
326 return RandU32();
327}
328
329
330static uint64_t RandU64Dst(uint32_t iTest)
331{
332 if (iTest < g_cZeroDstTests)
333 return 0;
334 return RandU64();
335}
336
337
338static uint64_t RandU64Src(uint32_t iTest)
339{
340 if (iTest < g_cZeroSrcTests)
341 return 0;
342 return RandU64();
343}
344
345
346static RTFLOAT80U RandR80Src(uint32_t iTest)
347{
348 RTFLOAT80U lrd;
349 if (iTest < g_cZeroSrcTests)
350 {
351 lrd.au64[0] = 0;
352 lrd.au16[4] = 0;
353 }
354 else
355 {
356 lrd.au64[0] = RandU64();
357 lrd.au16[4] = RandU16();
358 }
359 return lrd;
360}
361
362
363static RTFLOAT64U RandR64Src(uint32_t iTest)
364{
365 RTFLOAT64U rd;
366 if (iTest < g_cZeroSrcTests)
367 rd.u = 0;
368 else
369 rd.u = RandU64();
370 return rd;
371}
372
373
374static RTFLOAT32U RandR32Src(uint32_t iTest)
375{
376 RTFLOAT32U r;
377 if (iTest < g_cZeroSrcTests)
378 r.u = 0;
379 else
380 r.u = RandU32();
381 return r;
382}
383
384
385const char *GenFormatR80(PCRTFLOAT80U plrd)
386{
387 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
388 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "RTFLOAT80U_INIT_C(%d,%#RX64,%u)",
389 plrd->s.fSign, plrd->s.uMantissa, plrd->s.uExponent);
390 return pszBuf;
391}
392
393const char *GenFormatR64(PCRTFLOAT64U prd)
394{
395 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
396 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "RTFLOAT64U_INIT_C(%d,%#RX64,%u)",
397 prd->s.fSign, RT_MAKE_U64(prd->s.uFractionLow, prd->s.uFractionHigh), prd->s.uExponent);
398 return pszBuf;
399}
400
401
402const char *GenFormatR32(PCRTFLOAT32U pr)
403{
404 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
405 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "RTFLOAT32U_INIT_C(%d,%#RX32,%u)", pr->s.fSign, pr->s.uFraction, pr->s.uExponent);
406 return pszBuf;
407}
408
409
410static void GenerateHeader(PRTSTREAM pOut, const char *pszFileInfix,
411 const char *pszCpuDesc, const char *pszCpuType, const char *pszCpuSuffU)
412{
413 /* We want to tag the generated source code with the revision that produced it. */
414 static char s_szRev[] = "$Revision: 94261 $";
415 const char *pszRev = RTStrStripL(strchr(s_szRev, ':') + 1);
416 size_t cchRev = 0;
417 while (RT_C_IS_DIGIT(pszRev[cchRev]))
418 cchRev++;
419
420 RTStrmPrintf(pOut,
421 "/* $Id: tstIEMAImpl.cpp 94261 2022-03-16 01:34:29Z vboxsync $ */\n"
422 "/** @file\n"
423 " * IEM Assembly Instruction Helper Testcase Data%s%s - r%.*s on %s.\n"
424 " */\n"
425 "\n"
426 "/*\n"
427 " * Copyright (C) 2022 Oracle Corporation\n"
428 " *\n"
429 " * This file is part of VirtualBox Open Source Edition (OSE), as\n"
430 " * available from http://www.virtualbox.org. This file is free software;\n"
431 " * you can redistribute it and/or modify it under the terms of the GNU\n"
432 " * General Public License (GPL) as published by the Free Software\n"
433 " * Foundation, in version 2 as it comes in the \"COPYING\" file of the\n"
434 " * VirtualBox OSE distribution. VirtualBox OSE is distributed in the\n"
435 " * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.\n"
436 " */\n"
437 "\n"
438 "#ifndef VMM_INCLUDED_SRC_testcase_tstIEMAImplData%s%s_h\n"
439 "#define VMM_INCLUDED_SRC_testcase_tstIEMAImplData%s%s_h\n"
440 "#ifndef RT_WITHOUT_PRAGMA_ONCE\n"
441 "# pragma once\n"
442 "#endif\n"
443 ,
444 pszCpuType ? " " : "", pszCpuType ? pszCpuType : "", cchRev, pszRev, pszCpuDesc,
445 pszFileInfix, pszCpuSuffU,
446 pszFileInfix, pszCpuSuffU);
447}
448
449
450static RTEXITCODE GenerateFooterAndClose(PRTSTREAM pOut, const char *pszFilename, const char *pszFileInfix,
451 const char *pszCpuSuff, RTEXITCODE rcExit)
452{
453 RTStrmPrintf(pOut,
454 "\n"
455 "#endif /* !VMM_INCLUDED_SRC_testcase_tstIEMAImplData%s%s_h */\n", pszFileInfix, pszCpuSuff);
456 int rc = RTStrmClose(pOut);
457 if (RT_SUCCESS(rc))
458 return rcExit;
459 return RTMsgErrorExitFailure("RTStrmClose failed on %s: %Rrc", pszFilename, rc);
460}
461
462#endif
463
464
465/*
466 * Test helpers.
467 */
468static const char *EFlagsDiff(uint32_t fActual, uint32_t fExpected)
469{
470 if (fActual == fExpected)
471 return "";
472
473 uint32_t const fXor = fActual ^ fExpected;
474 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
475 size_t cch = RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), " - %#x", fXor);
476
477 static struct
478 {
479 const char *pszName;
480 uint32_t fFlag;
481 } const s_aFlags[] =
482 {
483#define EFL_ENTRY(a_Flags) { #a_Flags, X86_EFL_ ## a_Flags }
484 EFL_ENTRY(CF),
485 EFL_ENTRY(PF),
486 EFL_ENTRY(AF),
487 EFL_ENTRY(ZF),
488 EFL_ENTRY(SF),
489 EFL_ENTRY(TF),
490 EFL_ENTRY(IF),
491 EFL_ENTRY(DF),
492 EFL_ENTRY(OF),
493 EFL_ENTRY(IOPL),
494 EFL_ENTRY(NT),
495 EFL_ENTRY(RF),
496 EFL_ENTRY(VM),
497 EFL_ENTRY(AC),
498 EFL_ENTRY(VIF),
499 EFL_ENTRY(VIP),
500 EFL_ENTRY(ID),
501 };
502 for (size_t i = 0; i < RT_ELEMENTS(s_aFlags); i++)
503 if (s_aFlags[i].fFlag & fXor)
504 cch += RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch,
505 s_aFlags[i].fFlag & fActual ? "/%s" : "/!%s", s_aFlags[i].pszName);
506 RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, "");
507 return pszBuf;
508}
509
510
511static const char *FswDiff(uint16_t fActual, uint16_t fExpected)
512{
513 if (fActual == fExpected)
514 return "";
515
516 uint16_t const fXor = fActual ^ fExpected;
517 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
518 size_t cch = RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), " - %#x", fXor);
519
520 static struct
521 {
522 const char *pszName;
523 uint32_t fFlag;
524 } const s_aFlags[] =
525 {
526#define FSW_ENTRY(a_Flags) { #a_Flags, X86_FSW_ ## a_Flags }
527 FSW_ENTRY(IE),
528 FSW_ENTRY(DE),
529 FSW_ENTRY(ZE),
530 FSW_ENTRY(OE),
531 FSW_ENTRY(UE),
532 FSW_ENTRY(PE),
533 FSW_ENTRY(SF),
534 FSW_ENTRY(ES),
535 FSW_ENTRY(C0),
536 FSW_ENTRY(C1),
537 FSW_ENTRY(C2),
538 FSW_ENTRY(C3),
539 FSW_ENTRY(B),
540 };
541 for (size_t i = 0; i < RT_ELEMENTS(s_aFlags); i++)
542 if (s_aFlags[i].fFlag & fXor)
543 cch += RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch,
544 s_aFlags[i].fFlag & fActual ? "/%s" : "/!%s", s_aFlags[i].pszName);
545 if (fXor & X86_FSW_TOP_MASK)
546 cch += RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, "/TOP%u!%u",
547 X86_FSW_TOP_GET(fActual), X86_FSW_TOP_GET(fExpected));
548 RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, "");
549 return pszBuf;
550}
551
552
553static const char *FormatFcw(uint16_t fFcw)
554{
555 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
556
557 const char *pszPC = NULL; /* (msc+gcc are too stupid) */
558 switch (fFcw & X86_FCW_PC_MASK)
559 {
560 case X86_FCW_PC_24: pszPC = "PC24"; break;
561 case X86_FCW_PC_RSVD: pszPC = "PCRSVD!"; break;
562 case X86_FCW_PC_53: pszPC = "PC53"; break;
563 case X86_FCW_PC_64: pszPC = "PC64"; break;
564 }
565
566 const char *pszRC = NULL; /* (msc+gcc are too stupid) */
567 switch (fFcw & X86_FCW_RC_MASK)
568 {
569 case X86_FCW_RC_NEAREST: pszRC = "NEAR"; break;
570 case X86_FCW_RC_DOWN: pszRC = "DOWN"; break;
571 case X86_FCW_RC_UP: pszRC = "UP"; break;
572 case X86_FCW_RC_ZERO: pszRC = "ZERO"; break;
573 }
574 size_t cch = RTStrPrintf(&pszBuf[0], sizeof(g_aszBuf[0]), "%s %s", pszPC, pszRC);
575
576 static struct
577 {
578 const char *pszName;
579 uint32_t fFlag;
580 } const s_aFlags[] =
581 {
582#define FCW_ENTRY(a_Flags) { #a_Flags, X86_FCW_ ## a_Flags }
583 FCW_ENTRY(IM),
584 FCW_ENTRY(DM),
585 FCW_ENTRY(ZM),
586 FCW_ENTRY(OM),
587 FCW_ENTRY(UM),
588 FCW_ENTRY(PM),
589 { "6M", 64 },
590 };
591 for (size_t i = 0; i < RT_ELEMENTS(s_aFlags); i++)
592 if (fFcw & s_aFlags[i].fFlag)
593 cch += RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, " %s", s_aFlags[i].pszName);
594
595 RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, "");
596 return pszBuf;
597}
598
599
600static const char *FormatR80(PCRTFLOAT80U pr80)
601{
602 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
603 RTStrFormatR80(pszBuf, sizeof(g_aszBuf[0]), pr80, 0, 0, RTSTR_F_SPECIAL);
604 return pszBuf;
605}
606
607
608static const char *FormatR64(PCRTFLOAT64U pr64)
609{
610 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
611 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "%c1m%#015RX64^%d",
612 pr64->s.fSign ? '-' : '+',
613 RT_MAKE_U64(pr64->s.uFractionLow, pr64->s.uFractionHigh),
614 pr64->s.uExponent - 1023);
615 return pszBuf;
616}
617
618
619static const char *FormatR32(PCRTFLOAT32U pr32)
620{
621 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
622 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "%c1m%#010RX32^%d",
623 pr32->s.fSign ? '-' : '+',
624 pr32->s.uFraction,
625 pr32->s.uExponent - 127);
626 return pszBuf;
627}
628
629
630/*
631 * Binary operations.
632 */
633#ifdef TSTIEMAIMPL_WITH_GENERATOR
634# define GEN_BINARY_TESTS(a_cBits, a_Fmt) \
635static void BinU ## a_cBits ## Generate(PRTSTREAM pOut, PRTSTREAM pOutCpu, const char *pszCpuSuffU, uint32_t cTests) \
636{ \
637 RTStrmPrintf(pOut, "\n\n#define HAVE_BINU%u_TESTS\n", a_cBits); \
638 RTStrmPrintf(pOutCpu, "\n\n#define HAVE_BINU%u_TESTS%s\n", a_cBits, pszCpuSuffU); \
639 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aBinU ## a_cBits); iFn++) \
640 { \
641 PFNIEMAIMPLBINU ## a_cBits const pfn = g_aBinU ## a_cBits[iFn].pfnNative \
642 ? g_aBinU ## a_cBits[iFn].pfnNative : g_aBinU ## a_cBits[iFn].pfn; \
643 PRTSTREAM pOutFn = pOut; \
644 if (g_aBinU ## a_cBits[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE) \
645 { \
646 if (g_aBinU ## a_cBits[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour) \
647 continue; \
648 pOutFn = pOutCpu; \
649 } \
650 \
651 RTStrmPrintf(pOutFn, "static const BINU%u_TEST_T g_aTests_%s[] =\n{\n", a_cBits, g_aBinU ## a_cBits[iFn].pszName); \
652 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
653 { \
654 BINU ## a_cBits ## _TEST_T Test; \
655 Test.fEflIn = RandEFlags(); \
656 Test.fEflOut = Test.fEflIn; \
657 Test.uDstIn = RandU ## a_cBits ## Dst(iTest); \
658 Test.uDstOut = Test.uDstIn; \
659 Test.uSrcIn = RandU ## a_cBits ## Src(iTest); \
660 if (g_aBinU ## a_cBits[iFn].uExtra) \
661 Test.uSrcIn &= a_cBits - 1; /* Restrict bit index according to operand width */ \
662 Test.uMisc = 0; \
663 pfn(&Test.uDstOut, Test.uSrcIn, &Test.fEflOut); \
664 RTStrmPrintf(pOutFn, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", " a_Fmt ", %#x }, /* #%u */\n", \
665 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uSrcIn, Test.uMisc, iTest); \
666 } \
667 RTStrmPrintf(pOutFn, "};\n"); \
668 } \
669}
670#else
671# define GEN_BINARY_TESTS(a_cBits, a_Fmt)
672#endif
673
674#define TEST_BINARY_OPS(a_cBits, a_uType, a_Fmt, a_aSubTests) \
675GEN_BINARY_TESTS(a_cBits, a_Fmt) \
676\
677static void BinU ## a_cBits ## Test(void) \
678{ \
679 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
680 { \
681 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
682 BINU ## a_cBits ## _TEST_T const * const paTests = a_aSubTests[iFn].paTests; \
683 uint32_t const cTests = a_aSubTests[iFn].cTests; \
684 PFNIEMAIMPLBINU ## a_cBits pfn = a_aSubTests[iFn].pfn; \
685 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
686 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
687 { \
688 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
689 { \
690 uint32_t fEfl = paTests[iTest].fEflIn; \
691 a_uType uDst = paTests[iTest].uDstIn; \
692 pfn(&uDst, paTests[iTest].uSrcIn, &fEfl); \
693 if ( uDst != paTests[iTest].uDstOut \
694 || fEfl != paTests[iTest].fEflOut) \
695 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", \
696 iTest, !iVar ? "" : "/n", paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn, \
697 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut, \
698 EFlagsDiff(fEfl, paTests[iTest].fEflOut), \
699 uDst == paTests[iTest].uDstOut ? "eflags" : fEfl == paTests[iTest].fEflOut ? "dst" : "both"); \
700 else \
701 { \
702 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
703 *g_pfEfl = paTests[iTest].fEflIn; \
704 pfn(g_pu ## a_cBits, paTests[iTest].uSrcIn, g_pfEfl); \
705 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDstOut); \
706 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut); \
707 } \
708 } \
709 pfn = a_aSubTests[iFn].pfnNative; \
710 } \
711 } \
712}
713
714
715/*
716 * 8-bit binary operations.
717 */
718
719#ifndef HAVE_BINU8_TESTS
720static const BINU8_TEST_T g_aTests_add_u8[] = { {0} };
721static const BINU8_TEST_T g_aTests_add_u8_locked[] = { {0} };
722static const BINU8_TEST_T g_aTests_adc_u8[] = { {0} };
723static const BINU8_TEST_T g_aTests_adc_u8_locked[] = { {0} };
724static const BINU8_TEST_T g_aTests_sub_u8[] = { {0} };
725static const BINU8_TEST_T g_aTests_sub_u8_locked[] = { {0} };
726static const BINU8_TEST_T g_aTests_sbb_u8[] = { {0} };
727static const BINU8_TEST_T g_aTests_sbb_u8_locked[] = { {0} };
728static const BINU8_TEST_T g_aTests_or_u8[] = { {0} };
729static const BINU8_TEST_T g_aTests_or_u8_locked[] = { {0} };
730static const BINU8_TEST_T g_aTests_xor_u8[] = { {0} };
731static const BINU8_TEST_T g_aTests_xor_u8_locked[] = { {0} };
732static const BINU8_TEST_T g_aTests_and_u8[] = { {0} };
733static const BINU8_TEST_T g_aTests_and_u8_locked[] = { {0} };
734static const BINU8_TEST_T g_aTests_cmp_u8[] = { {0} };
735static const BINU8_TEST_T g_aTests_test_u8[] = { {0} };
736#endif
737
738static const BINU8_T g_aBinU8[] =
739{
740 ENTRY(add_u8),
741 ENTRY(add_u8_locked),
742 ENTRY(adc_u8),
743 ENTRY(adc_u8_locked),
744 ENTRY(sub_u8),
745 ENTRY(sub_u8_locked),
746 ENTRY(sbb_u8),
747 ENTRY(sbb_u8_locked),
748 ENTRY(or_u8),
749 ENTRY(or_u8_locked),
750 ENTRY(xor_u8),
751 ENTRY(xor_u8_locked),
752 ENTRY(and_u8),
753 ENTRY(and_u8_locked),
754 ENTRY(cmp_u8),
755 ENTRY(test_u8),
756};
757
758TEST_BINARY_OPS(8, uint8_t, "%#04x", g_aBinU8)
759
760
761/*
762 * 16-bit binary operations.
763 */
764
765#ifndef HAVE_BINU16_TESTS
766static const BINU16_TEST_T g_aTests_add_u16[] = { {0} };
767static const BINU16_TEST_T g_aTests_add_u16_locked[] = { {0} };
768static const BINU16_TEST_T g_aTests_adc_u16[] = { {0} };
769static const BINU16_TEST_T g_aTests_adc_u16_locked[] = { {0} };
770static const BINU16_TEST_T g_aTests_sub_u16[] = { {0} };
771static const BINU16_TEST_T g_aTests_sub_u16_locked[] = { {0} };
772static const BINU16_TEST_T g_aTests_sbb_u16[] = { {0} };
773static const BINU16_TEST_T g_aTests_sbb_u16_locked[] = { {0} };
774static const BINU16_TEST_T g_aTests_or_u16[] = { {0} };
775static const BINU16_TEST_T g_aTests_or_u16_locked[] = { {0} };
776static const BINU16_TEST_T g_aTests_xor_u16[] = { {0} };
777static const BINU16_TEST_T g_aTests_xor_u16_locked[] = { {0} };
778static const BINU16_TEST_T g_aTests_and_u16[] = { {0} };
779static const BINU16_TEST_T g_aTests_and_u16_locked[] = { {0} };
780static const BINU16_TEST_T g_aTests_cmp_u16[] = { {0} };
781static const BINU16_TEST_T g_aTests_test_u16[] = { {0} };
782static const BINU16_TEST_T g_aTests_bt_u16[] = { {0} };
783static const BINU16_TEST_T g_aTests_btc_u16[] = { {0} };
784static const BINU16_TEST_T g_aTests_btc_u16_locked[] = { {0} };
785static const BINU16_TEST_T g_aTests_btr_u16[] = { {0} };
786static const BINU16_TEST_T g_aTests_btr_u16_locked[] = { {0} };
787static const BINU16_TEST_T g_aTests_bts_u16[] = { {0} };
788static const BINU16_TEST_T g_aTests_bts_u16_locked[] = { {0} };
789static const BINU16_TEST_T g_aTests_arpl[] = { {0} };
790#endif
791#ifndef HAVE_BINU16_TESTS_AMD
792static const BINU16_TEST_T g_aTests_bsf_u16_amd[] = { {0} };
793static const BINU16_TEST_T g_aTests_bsr_u16_amd[] = { {0} };
794static const BINU16_TEST_T g_aTests_imul_two_u16_amd[] = { {0} };
795#endif
796#ifndef HAVE_BINU16_TESTS_INTEL
797static const BINU16_TEST_T g_aTests_bsf_u16_intel[] = { {0} };
798static const BINU16_TEST_T g_aTests_bsr_u16_intel[] = { {0} };
799static const BINU16_TEST_T g_aTests_imul_two_u16_intel[] = { {0} };
800#endif
801
802static const BINU16_T g_aBinU16[] =
803{
804 ENTRY(add_u16),
805 ENTRY(add_u16_locked),
806 ENTRY(adc_u16),
807 ENTRY(adc_u16_locked),
808 ENTRY(sub_u16),
809 ENTRY(sub_u16_locked),
810 ENTRY(sbb_u16),
811 ENTRY(sbb_u16_locked),
812 ENTRY(or_u16),
813 ENTRY(or_u16_locked),
814 ENTRY(xor_u16),
815 ENTRY(xor_u16_locked),
816 ENTRY(and_u16),
817 ENTRY(and_u16_locked),
818 ENTRY(cmp_u16),
819 ENTRY(test_u16),
820 ENTRY_EX(bt_u16, 1),
821 ENTRY_EX(btc_u16, 1),
822 ENTRY_EX(btc_u16_locked, 1),
823 ENTRY_EX(btr_u16, 1),
824 ENTRY_EX(btr_u16_locked, 1),
825 ENTRY_EX(bts_u16, 1),
826 ENTRY_EX(bts_u16_locked, 1),
827 ENTRY_AMD( bsf_u16, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
828 ENTRY_INTEL(bsf_u16, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
829 ENTRY_AMD( bsr_u16, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
830 ENTRY_INTEL(bsr_u16, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
831 ENTRY_AMD( imul_two_u16, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
832 ENTRY_INTEL(imul_two_u16, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
833 ENTRY(arpl),
834};
835
836TEST_BINARY_OPS(16, uint16_t, "%#06x", g_aBinU16)
837
838
839/*
840 * 32-bit binary operations.
841 */
842
843#ifndef HAVE_BINU32_TESTS
844static const BINU32_TEST_T g_aTests_add_u32[] = { {0} };
845static const BINU32_TEST_T g_aTests_add_u32_locked[] = { {0} };
846static const BINU32_TEST_T g_aTests_adc_u32[] = { {0} };
847static const BINU32_TEST_T g_aTests_adc_u32_locked[] = { {0} };
848static const BINU32_TEST_T g_aTests_sub_u32[] = { {0} };
849static const BINU32_TEST_T g_aTests_sub_u32_locked[] = { {0} };
850static const BINU32_TEST_T g_aTests_sbb_u32[] = { {0} };
851static const BINU32_TEST_T g_aTests_sbb_u32_locked[] = { {0} };
852static const BINU32_TEST_T g_aTests_or_u32[] = { {0} };
853static const BINU32_TEST_T g_aTests_or_u32_locked[] = { {0} };
854static const BINU32_TEST_T g_aTests_xor_u32[] = { {0} };
855static const BINU32_TEST_T g_aTests_xor_u32_locked[] = { {0} };
856static const BINU32_TEST_T g_aTests_and_u32[] = { {0} };
857static const BINU32_TEST_T g_aTests_and_u32_locked[] = { {0} };
858static const BINU32_TEST_T g_aTests_cmp_u32[] = { {0} };
859static const BINU32_TEST_T g_aTests_test_u32[] = { {0} };
860static const BINU32_TEST_T g_aTests_bt_u32[] = { {0} };
861static const BINU32_TEST_T g_aTests_btc_u32[] = { {0} };
862static const BINU32_TEST_T g_aTests_btc_u32_locked[] = { {0} };
863static const BINU32_TEST_T g_aTests_btr_u32[] = { {0} };
864static const BINU32_TEST_T g_aTests_btr_u32_locked[] = { {0} };
865static const BINU32_TEST_T g_aTests_bts_u32[] = { {0} };
866static const BINU32_TEST_T g_aTests_bts_u32_locked[] = { {0} };
867#endif
868#ifndef HAVE_BINU32_TESTS_AMD
869static const BINU32_TEST_T g_aTests_bsf_u32_amd[] = { {0} };
870static const BINU32_TEST_T g_aTests_bsr_u32_amd[] = { {0} };
871static const BINU32_TEST_T g_aTests_imul_two_u32_amd[] = { {0} };
872#endif
873#ifndef HAVE_BINU32_TESTS_INTEL
874static const BINU32_TEST_T g_aTests_bsf_u32_intel[] = { {0} };
875static const BINU32_TEST_T g_aTests_bsr_u32_intel[] = { {0} };
876static const BINU32_TEST_T g_aTests_imul_two_u32_intel[] = { {0} };
877#endif
878
879static const BINU32_T g_aBinU32[] =
880{
881 ENTRY(add_u32),
882 ENTRY(add_u32_locked),
883 ENTRY(adc_u32),
884 ENTRY(adc_u32_locked),
885 ENTRY(sub_u32),
886 ENTRY(sub_u32_locked),
887 ENTRY(sbb_u32),
888 ENTRY(sbb_u32_locked),
889 ENTRY(or_u32),
890 ENTRY(or_u32_locked),
891 ENTRY(xor_u32),
892 ENTRY(xor_u32_locked),
893 ENTRY(and_u32),
894 ENTRY(and_u32_locked),
895 ENTRY(cmp_u32),
896 ENTRY(test_u32),
897 ENTRY_EX(bt_u32, 1),
898 ENTRY_EX(btc_u32, 1),
899 ENTRY_EX(btc_u32_locked, 1),
900 ENTRY_EX(btr_u32, 1),
901 ENTRY_EX(btr_u32_locked, 1),
902 ENTRY_EX(bts_u32, 1),
903 ENTRY_EX(bts_u32_locked, 1),
904 ENTRY_AMD( bsf_u32, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
905 ENTRY_INTEL(bsf_u32, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
906 ENTRY_AMD( bsr_u32, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
907 ENTRY_INTEL(bsr_u32, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
908 ENTRY_AMD( imul_two_u32, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
909 ENTRY_INTEL(imul_two_u32, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
910};
911
912TEST_BINARY_OPS(32, uint32_t, "%#010RX32", g_aBinU32)
913
914
915/*
916 * 64-bit binary operations.
917 */
918
919#ifndef HAVE_BINU64_TESTS
920static const BINU64_TEST_T g_aTests_add_u64[] = { {0} };
921static const BINU64_TEST_T g_aTests_add_u64_locked[] = { {0} };
922static const BINU64_TEST_T g_aTests_adc_u64[] = { {0} };
923static const BINU64_TEST_T g_aTests_adc_u64_locked[] = { {0} };
924static const BINU64_TEST_T g_aTests_sub_u64[] = { {0} };
925static const BINU64_TEST_T g_aTests_sub_u64_locked[] = { {0} };
926static const BINU64_TEST_T g_aTests_sbb_u64[] = { {0} };
927static const BINU64_TEST_T g_aTests_sbb_u64_locked[] = { {0} };
928static const BINU64_TEST_T g_aTests_or_u64[] = { {0} };
929static const BINU64_TEST_T g_aTests_or_u64_locked[] = { {0} };
930static const BINU64_TEST_T g_aTests_xor_u64[] = { {0} };
931static const BINU64_TEST_T g_aTests_xor_u64_locked[] = { {0} };
932static const BINU64_TEST_T g_aTests_and_u64[] = { {0} };
933static const BINU64_TEST_T g_aTests_and_u64_locked[] = { {0} };
934static const BINU64_TEST_T g_aTests_cmp_u64[] = { {0} };
935static const BINU64_TEST_T g_aTests_test_u64[] = { {0} };
936static const BINU64_TEST_T g_aTests_bt_u64[] = { {0} };
937static const BINU64_TEST_T g_aTests_btc_u64[] = { {0} };
938static const BINU64_TEST_T g_aTests_btc_u64_locked[] = { {0} };
939static const BINU64_TEST_T g_aTests_btr_u64[] = { {0} };
940static const BINU64_TEST_T g_aTests_btr_u64_locked[] = { {0} };
941static const BINU64_TEST_T g_aTests_bts_u64[] = { {0} };
942static const BINU64_TEST_T g_aTests_bts_u64_locked[] = { {0} };
943#endif
944#ifndef HAVE_BINU64_TESTS_AMD
945static const BINU64_TEST_T g_aTests_bsf_u64_amd[] = { {0} };
946static const BINU64_TEST_T g_aTests_bsr_u64_amd[] = { {0} };
947static const BINU64_TEST_T g_aTests_imul_two_u64_amd[] = { {0} };
948#endif
949#ifndef HAVE_BINU64_TESTS_INTEL
950static const BINU64_TEST_T g_aTests_bsf_u64_intel[] = { {0} };
951static const BINU64_TEST_T g_aTests_bsr_u64_intel[] = { {0} };
952static const BINU64_TEST_T g_aTests_imul_two_u64_intel[] = { {0} };
953#endif
954
955static const BINU64_T g_aBinU64[] =
956{
957 ENTRY(add_u64),
958 ENTRY(add_u64_locked),
959 ENTRY(adc_u64),
960 ENTRY(adc_u64_locked),
961 ENTRY(sub_u64),
962 ENTRY(sub_u64_locked),
963 ENTRY(sbb_u64),
964 ENTRY(sbb_u64_locked),
965 ENTRY(or_u64),
966 ENTRY(or_u64_locked),
967 ENTRY(xor_u64),
968 ENTRY(xor_u64_locked),
969 ENTRY(and_u64),
970 ENTRY(and_u64_locked),
971 ENTRY(cmp_u64),
972 ENTRY(test_u64),
973 ENTRY_EX(bt_u64, 1),
974 ENTRY_EX(btc_u64, 1),
975 ENTRY_EX(btc_u64_locked, 1),
976 ENTRY_EX(btr_u64, 1),
977 ENTRY_EX(btr_u64_locked, 1),
978 ENTRY_EX(bts_u64, 1),
979 ENTRY_EX(bts_u64_locked, 1),
980 ENTRY_AMD( bsf_u64, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
981 ENTRY_INTEL(bsf_u64, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
982 ENTRY_AMD( bsr_u64, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
983 ENTRY_INTEL(bsr_u64, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
984 ENTRY_AMD( imul_two_u64, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
985 ENTRY_INTEL(imul_two_u64, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
986};
987
988TEST_BINARY_OPS(64, uint64_t, "%#018RX64", g_aBinU64)
989
990
991/*
992 * XCHG
993 */
994static void XchgTest(void)
995{
996 RTTestSub(g_hTest, "xchg");
997 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU8, (uint8_t *pu8Mem, uint8_t *pu8Reg));
998 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU16,(uint16_t *pu16Mem, uint16_t *pu16Reg));
999 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU32,(uint32_t *pu32Mem, uint32_t *pu32Reg));
1000 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU64,(uint64_t *pu64Mem, uint64_t *pu64Reg));
1001
1002 static struct
1003 {
1004 uint8_t cb; uint64_t fMask;
1005 union
1006 {
1007 uintptr_t pfn;
1008 FNIEMAIMPLXCHGU8 *pfnU8;
1009 FNIEMAIMPLXCHGU16 *pfnU16;
1010 FNIEMAIMPLXCHGU32 *pfnU32;
1011 FNIEMAIMPLXCHGU64 *pfnU64;
1012 } u;
1013 }
1014 s_aXchgWorkers[] =
1015 {
1016 { 1, UINT8_MAX, { (uintptr_t)iemAImpl_xchg_u8_locked } },
1017 { 2, UINT16_MAX, { (uintptr_t)iemAImpl_xchg_u16_locked } },
1018 { 4, UINT32_MAX, { (uintptr_t)iemAImpl_xchg_u32_locked } },
1019 { 8, UINT64_MAX, { (uintptr_t)iemAImpl_xchg_u64_locked } },
1020 { 1, UINT8_MAX, { (uintptr_t)iemAImpl_xchg_u8_unlocked } },
1021 { 2, UINT16_MAX, { (uintptr_t)iemAImpl_xchg_u16_unlocked } },
1022 { 4, UINT32_MAX, { (uintptr_t)iemAImpl_xchg_u32_unlocked } },
1023 { 8, UINT64_MAX, { (uintptr_t)iemAImpl_xchg_u64_unlocked } },
1024 };
1025 for (size_t i = 0; i < RT_ELEMENTS(s_aXchgWorkers); i++)
1026 {
1027 RTUINT64U uIn1, uIn2, uMem, uDst;
1028 uMem.u = uIn1.u = RTRandU64Ex(0, s_aXchgWorkers[i].fMask);
1029 uDst.u = uIn2.u = RTRandU64Ex(0, s_aXchgWorkers[i].fMask);
1030 if (uIn1.u == uIn2.u)
1031 uDst.u = uIn2.u = ~uIn2.u;
1032
1033 switch (s_aXchgWorkers[i].cb)
1034 {
1035 case 1:
1036 s_aXchgWorkers[i].u.pfnU8(g_pu8, g_pu8Two);
1037 s_aXchgWorkers[i].u.pfnU8(&uMem.au8[0], &uDst.au8[0]);
1038 break;
1039 case 2:
1040 s_aXchgWorkers[i].u.pfnU16(g_pu16, g_pu16Two);
1041 s_aXchgWorkers[i].u.pfnU16(&uMem.Words.w0, &uDst.Words.w0);
1042 break;
1043 case 4:
1044 s_aXchgWorkers[i].u.pfnU32(g_pu32, g_pu32Two);
1045 s_aXchgWorkers[i].u.pfnU32(&uMem.DWords.dw0, &uDst.DWords.dw0);
1046 break;
1047 case 8:
1048 s_aXchgWorkers[i].u.pfnU64(g_pu64, g_pu64Two);
1049 s_aXchgWorkers[i].u.pfnU64(&uMem.u, &uDst.u);
1050 break;
1051 default: RTTestFailed(g_hTest, "%d\n", s_aXchgWorkers[i].cb); break;
1052 }
1053
1054 if (uMem.u != uIn2.u || uDst.u != uIn1.u)
1055 RTTestFailed(g_hTest, "i=%u: %#RX64, %#RX64 -> %#RX64, %#RX64\n", i, uIn1.u, uIn2.u, uMem.u, uDst.u);
1056 }
1057}
1058
1059
1060/*
1061 * XADD
1062 */
1063static void XaddTest(void)
1064{
1065#define TEST_XADD(a_cBits, a_Type, a_Fmt) do { \
1066 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXADDU ## a_cBits, (a_Type *, a_Type *, uint32_t *)); \
1067 static struct \
1068 { \
1069 const char *pszName; \
1070 FNIEMAIMPLXADDU ## a_cBits *pfn; \
1071 BINU ## a_cBits ## _TEST_T const *paTests; \
1072 uint32_t cTests; \
1073 } const s_aFuncs[] = \
1074 { \
1075 { "xadd_u" # a_cBits, iemAImpl_xadd_u ## a_cBits, \
1076 g_aTests_add_u ## a_cBits, RT_ELEMENTS(g_aTests_add_u ## a_cBits) }, \
1077 { "xadd_u" # a_cBits "8_locked", iemAImpl_xadd_u ## a_cBits ## _locked, \
1078 g_aTests_add_u ## a_cBits, RT_ELEMENTS(g_aTests_add_u ## a_cBits) }, \
1079 }; \
1080 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++) \
1081 { \
1082 RTTestSub(g_hTest, s_aFuncs[iFn].pszName); \
1083 BINU ## a_cBits ## _TEST_T const * const paTests = s_aFuncs[iFn].paTests; \
1084 uint32_t const cTests = s_aFuncs[iFn].cTests; \
1085 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
1086 { \
1087 uint32_t fEfl = paTests[iTest].fEflIn; \
1088 a_Type uSrc = paTests[iTest].uSrcIn; \
1089 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
1090 s_aFuncs[iFn].pfn(g_pu ## a_cBits, &uSrc, &fEfl); \
1091 if ( fEfl != paTests[iTest].fEflOut \
1092 || *g_pu ## a_cBits != paTests[iTest].uDstOut \
1093 || uSrc != paTests[iTest].uDstIn) \
1094 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", \
1095 s_aFuncs[iFn].pszName, iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn, \
1096 fEfl, *g_pu ## a_cBits, uSrc, paTests[iTest].fEflOut, paTests[iTest].uDstOut, paTests[iTest].uDstIn, \
1097 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
1098 } \
1099 } \
1100 } while(0)
1101 TEST_XADD(8, uint8_t, "%#04x");
1102 TEST_XADD(16, uint16_t, "%#06x");
1103 TEST_XADD(32, uint32_t, "%#010RX32");
1104 TEST_XADD(64, uint64_t, "%#010RX64");
1105}
1106
1107
1108/*
1109 * CMPXCHG
1110 */
1111
1112static void CmpXchgTest(void)
1113{
1114#define TEST_CMPXCHG(a_cBits, a_Type, a_Fmt) do {\
1115 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLCMPXCHGU ## a_cBits, (a_Type *, a_Type *, a_Type, uint32_t *)); \
1116 static struct \
1117 { \
1118 const char *pszName; \
1119 FNIEMAIMPLCMPXCHGU ## a_cBits *pfn; \
1120 PFNIEMAIMPLBINU ## a_cBits pfnSub; \
1121 BINU ## a_cBits ## _TEST_T const *paTests; \
1122 uint32_t cTests; \
1123 } const s_aFuncs[] = \
1124 { \
1125 { "cmpxchg_u" # a_cBits, iemAImpl_cmpxchg_u ## a_cBits, iemAImpl_sub_u ## a_cBits, \
1126 g_aTests_cmp_u ## a_cBits, RT_ELEMENTS(g_aTests_cmp_u ## a_cBits) }, \
1127 { "cmpxchg_u" # a_cBits "_locked", iemAImpl_cmpxchg_u ## a_cBits ## _locked, iemAImpl_sub_u ## a_cBits, \
1128 g_aTests_cmp_u ## a_cBits, RT_ELEMENTS(g_aTests_cmp_u ## a_cBits) }, \
1129 }; \
1130 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++) \
1131 { \
1132 RTTestSub(g_hTest, s_aFuncs[iFn].pszName); \
1133 BINU ## a_cBits ## _TEST_T const * const paTests = s_aFuncs[iFn].paTests; \
1134 uint32_t const cTests = s_aFuncs[iFn].cTests; \
1135 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
1136 { \
1137 /* as is (99% likely to be negative). */ \
1138 uint32_t fEfl = paTests[iTest].fEflIn; \
1139 a_Type const uNew = paTests[iTest].uSrcIn + 0x42; \
1140 a_Type uA = paTests[iTest].uDstIn; \
1141 *g_pu ## a_cBits = paTests[iTest].uSrcIn; \
1142 a_Type const uExpect = uA != paTests[iTest].uSrcIn ? paTests[iTest].uSrcIn : uNew; \
1143 s_aFuncs[iFn].pfn(g_pu ## a_cBits, &uA, uNew, &fEfl); \
1144 if ( fEfl != paTests[iTest].fEflOut \
1145 || *g_pu ## a_cBits != uExpect \
1146 || uA != paTests[iTest].uSrcIn) \
1147 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", \
1148 s_aFuncs[iFn].pszName, iTest, paTests[iTest].fEflIn, paTests[iTest].uSrcIn, paTests[iTest].uDstIn, \
1149 uNew, fEfl, *g_pu ## a_cBits, uA, paTests[iTest].fEflOut, uExpect, paTests[iTest].uSrcIn, \
1150 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
1151 /* positive */ \
1152 uint32_t fEflExpect = paTests[iTest].fEflIn; \
1153 uA = paTests[iTest].uDstIn; \
1154 s_aFuncs[iFn].pfnSub(&uA, uA, &fEflExpect); \
1155 fEfl = paTests[iTest].fEflIn; \
1156 uA = paTests[iTest].uDstIn; \
1157 *g_pu ## a_cBits = uA; \
1158 s_aFuncs[iFn].pfn(g_pu ## a_cBits, &uA, uNew, &fEfl); \
1159 if ( fEfl != fEflExpect \
1160 || *g_pu ## a_cBits != uNew \
1161 || uA != paTests[iTest].uDstIn) \
1162 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", \
1163 s_aFuncs[iFn].pszName, iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uDstIn, \
1164 uNew, fEfl, *g_pu ## a_cBits, uA, fEflExpect, uNew, paTests[iTest].uDstIn, \
1165 EFlagsDiff(fEfl, fEflExpect)); \
1166 } \
1167 } \
1168 } while(0)
1169 TEST_CMPXCHG(8, uint8_t, "%#04RX8");
1170 TEST_CMPXCHG(16, uint16_t, "%#06x");
1171 TEST_CMPXCHG(32, uint32_t, "%#010RX32");
1172#if ARCH_BITS != 32 /* calling convension issue, skipping as it's an unsupported host */
1173 TEST_CMPXCHG(64, uint64_t, "%#010RX64");
1174#endif
1175}
1176
1177static void CmpXchg8bTest(void)
1178{
1179 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLCMPXCHG8B,(uint64_t *, PRTUINT64U, PRTUINT64U, uint32_t *));
1180 static struct
1181 {
1182 const char *pszName;
1183 FNIEMAIMPLCMPXCHG8B *pfn;
1184 } const s_aFuncs[] =
1185 {
1186 { "cmpxchg8b", iemAImpl_cmpxchg8b },
1187 { "cmpxchg8b_locked", iemAImpl_cmpxchg8b_locked },
1188 };
1189 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++)
1190 {
1191 RTTestSub(g_hTest, s_aFuncs[iFn].pszName);
1192 for (uint32_t iTest = 0; iTest < 4; iTest += 2)
1193 {
1194 uint64_t const uOldValue = RandU64();
1195 uint64_t const uNewValue = RandU64();
1196
1197 /* positive test. */
1198 RTUINT64U uA, uB;
1199 uB.u = uNewValue;
1200 uA.u = uOldValue;
1201 *g_pu64 = uOldValue;
1202 uint32_t fEflIn = RandEFlags();
1203 uint32_t fEfl = fEflIn;
1204 s_aFuncs[iFn].pfn(g_pu64, &uA, &uB, &fEfl);
1205 if ( fEfl != (fEflIn | X86_EFL_ZF)
1206 || *g_pu64 != uNewValue
1207 || uA.u != uOldValue)
1208 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",
1209 iTest, fEflIn, uOldValue, uOldValue, uNewValue,
1210 fEfl, *g_pu64, uA.u,
1211 (fEflIn | X86_EFL_ZF), uNewValue, uOldValue, EFlagsDiff(fEfl, fEflIn | X86_EFL_ZF));
1212 RTTEST_CHECK(g_hTest, uB.u == uNewValue);
1213
1214 /* negative */
1215 uint64_t const uExpect = ~uOldValue;
1216 *g_pu64 = uExpect;
1217 uA.u = uOldValue;
1218 uB.u = uNewValue;
1219 fEfl = fEflIn = RandEFlags();
1220 s_aFuncs[iFn].pfn(g_pu64, &uA, &uB, &fEfl);
1221 if ( fEfl != (fEflIn & ~X86_EFL_ZF)
1222 || *g_pu64 != uExpect
1223 || uA.u != uExpect)
1224 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",
1225 iTest + 1, fEflIn, uExpect, uOldValue, uNewValue,
1226 fEfl, *g_pu64, uA.u,
1227 (fEflIn & ~X86_EFL_ZF), uExpect, uExpect, EFlagsDiff(fEfl, fEflIn & ~X86_EFL_ZF));
1228 RTTEST_CHECK(g_hTest, uB.u == uNewValue);
1229 }
1230 }
1231}
1232
1233static void CmpXchg16bTest(void)
1234{
1235 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLCMPXCHG16B,(PRTUINT128U, PRTUINT128U, PRTUINT128U, uint32_t *));
1236 static struct
1237 {
1238 const char *pszName;
1239 FNIEMAIMPLCMPXCHG16B *pfn;
1240 } const s_aFuncs[] =
1241 {
1242 { "cmpxchg16b", iemAImpl_cmpxchg16b },
1243 { "cmpxchg16b_locked", iemAImpl_cmpxchg16b_locked },
1244#if !defined(RT_ARCH_ARM64)
1245 { "cmpxchg16b_fallback", iemAImpl_cmpxchg16b_fallback },
1246#endif
1247 };
1248 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++)
1249 {
1250#if !defined(IEM_WITHOUT_ASSEMBLY) && defined(RT_ARCH_AMD64)
1251 if (!(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_CX16))
1252 continue;
1253#endif
1254 RTTestSub(g_hTest, s_aFuncs[iFn].pszName);
1255 for (uint32_t iTest = 0; iTest < 4; iTest += 2)
1256 {
1257 RTUINT128U const uOldValue = RandU128();
1258 RTUINT128U const uNewValue = RandU128();
1259
1260 /* positive test. */
1261 RTUINT128U uA, uB;
1262 uB = uNewValue;
1263 uA = uOldValue;
1264 *g_pu128 = uOldValue;
1265 uint32_t fEflIn = RandEFlags();
1266 uint32_t fEfl = fEflIn;
1267 s_aFuncs[iFn].pfn(g_pu128, &uA, &uB, &fEfl);
1268 if ( fEfl != (fEflIn | X86_EFL_ZF)
1269 || g_pu128->s.Lo != uNewValue.s.Lo
1270 || g_pu128->s.Hi != uNewValue.s.Hi
1271 || uA.s.Lo != uOldValue.s.Lo
1272 || uA.s.Hi != uOldValue.s.Hi)
1273 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=%#018RX64'%016RX64 cmp=%#018RX64'%016RX64 new=%#018RX64'%016RX64\n"
1274 " -> efl=%#08x dst=%#018RX64'%016RX64 old=%#018RX64'%016RX64,\n"
1275 " wanted %#08x, %#018RX64'%016RX64, %#018RX64'%016RX64%s\n",
1276 iTest, fEflIn, uOldValue.s.Hi, uOldValue.s.Lo, uOldValue.s.Hi, uOldValue.s.Lo, uNewValue.s.Hi, uNewValue.s.Lo,
1277 fEfl, g_pu128->s.Hi, g_pu128->s.Lo, uA.s.Hi, uA.s.Lo,
1278 (fEflIn | X86_EFL_ZF), uNewValue.s.Hi, uNewValue.s.Lo, uOldValue.s.Hi, uOldValue.s.Lo,
1279 EFlagsDiff(fEfl, fEflIn | X86_EFL_ZF));
1280 RTTEST_CHECK(g_hTest, uB.s.Lo == uNewValue.s.Lo && uB.s.Hi == uNewValue.s.Hi);
1281
1282 /* negative */
1283 RTUINT128U const uExpect = RTUINT128_INIT(~uOldValue.s.Hi, ~uOldValue.s.Lo);
1284 *g_pu128 = uExpect;
1285 uA = uOldValue;
1286 uB = uNewValue;
1287 fEfl = fEflIn = RandEFlags();
1288 s_aFuncs[iFn].pfn(g_pu128, &uA, &uB, &fEfl);
1289 if ( fEfl != (fEflIn & ~X86_EFL_ZF)
1290 || g_pu128->s.Lo != uExpect.s.Lo
1291 || g_pu128->s.Hi != uExpect.s.Hi
1292 || uA.s.Lo != uExpect.s.Lo
1293 || uA.s.Hi != uExpect.s.Hi)
1294 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=%#018RX64'%016RX64 cmp=%#018RX64'%016RX64 new=%#018RX64'%016RX64\n"
1295 " -> efl=%#08x dst=%#018RX64'%016RX64 old=%#018RX64'%016RX64,\n"
1296 " wanted %#08x, %#018RX64'%016RX64, %#018RX64'%016RX64%s\n",
1297 iTest + 1, fEflIn, uExpect.s.Hi, uExpect.s.Lo, uOldValue.s.Hi, uOldValue.s.Lo, uNewValue.s.Hi, uNewValue.s.Lo,
1298 fEfl, g_pu128->s.Hi, g_pu128->s.Lo, uA.s.Hi, uA.s.Lo,
1299 (fEflIn & ~X86_EFL_ZF), uExpect.s.Hi, uExpect.s.Lo, uExpect.s.Hi, uExpect.s.Lo,
1300 EFlagsDiff(fEfl, fEflIn & ~X86_EFL_ZF));
1301 RTTEST_CHECK(g_hTest, uB.s.Lo == uNewValue.s.Lo && uB.s.Hi == uNewValue.s.Hi);
1302 }
1303 }
1304}
1305
1306
1307/*
1308 * Double shifts.
1309 *
1310 * Note! We use BINUxx_TEST_T with the shift value in the uMisc field.
1311 */
1312
1313#ifndef HAVE_SHIFT_DBL_TESTS_AMD
1314static const BINU16_TEST_T g_aTests_shrd_u16_amd[] = { {0} };
1315static const BINU16_TEST_T g_aTests_shld_u16_amd[] = { {0} };
1316static const BINU32_TEST_T g_aTests_shrd_u32_amd[] = { {0} };
1317static const BINU32_TEST_T g_aTests_shld_u32_amd[] = { {0} };
1318static const BINU64_TEST_T g_aTests_shrd_u64_amd[] = { {0} };
1319static const BINU64_TEST_T g_aTests_shld_u64_amd[] = { {0} };
1320#endif
1321#ifndef HAVE_SHIFT_DBL_TESTS_INTEL
1322static const BINU16_TEST_T g_aTests_shrd_u16_intel[] = { {0} };
1323static const BINU16_TEST_T g_aTests_shld_u16_intel[] = { {0} };
1324static const BINU32_TEST_T g_aTests_shrd_u32_intel[] = { {0} };
1325static const BINU32_TEST_T g_aTests_shld_u32_intel[] = { {0} };
1326static const BINU64_TEST_T g_aTests_shrd_u64_intel[] = { {0} };
1327static const BINU64_TEST_T g_aTests_shld_u64_intel[] = { {0} };
1328#endif
1329
1330#ifdef TSTIEMAIMPL_WITH_GENERATOR
1331# define GEN_SHIFT_DBL(a_cBits, a_Fmt, a_aSubTests) \
1332void ShiftDblU ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
1333{ \
1334 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
1335 { \
1336 if ( a_aSubTests[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE \
1337 && a_aSubTests[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour) \
1338 continue; \
1339 RTStrmPrintf(pOut, "static const BINU" #a_cBits "_TEST_T g_aTests_%s[] =\n{\n", a_aSubTests[iFn].pszName); \
1340 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1341 { \
1342 BINU ## a_cBits ## _TEST_T Test; \
1343 Test.fEflIn = RandEFlags(); \
1344 Test.fEflOut = Test.fEflIn; \
1345 Test.uDstIn = RandU ## a_cBits ## Dst(iTest); \
1346 Test.uDstOut = Test.uDstIn; \
1347 Test.uSrcIn = RandU ## a_cBits ## Src(iTest); \
1348 Test.uMisc = RandU8() & (a_cBits * 4 - 1); /* need to go way beyond the a_cBits limit */ \
1349 a_aSubTests[iFn].pfnNative(&Test.uDstOut, Test.uSrcIn, Test.uMisc, &Test.fEflOut); \
1350 RTStrmPrintf(pOut, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", " a_Fmt ", %2u }, /* #%u */\n", \
1351 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uSrcIn, Test.uMisc, iTest); \
1352 } \
1353 RTStrmPrintf(pOut, "};\n"); \
1354 } \
1355}
1356#else
1357# define GEN_SHIFT_DBL(a_cBits, a_Fmt, a_aSubTests)
1358#endif
1359
1360#define TEST_SHIFT_DBL(a_cBits, a_Type, a_Fmt, a_aSubTests) \
1361static const struct \
1362{ \
1363 const char *pszName; \
1364 PFNIEMAIMPLSHIFTDBLU ## a_cBits pfn; \
1365 PFNIEMAIMPLSHIFTDBLU ## a_cBits pfnNative; \
1366 BINU ## a_cBits ## _TEST_T const *paTests; \
1367 uint32_t cTests, uExtra; \
1368 uint8_t idxCpuEflFlavour; \
1369} a_aSubTests[] = \
1370{ \
1371 ENTRY_AMD(shld_u ## a_cBits, X86_EFL_OF | X86_EFL_CF), \
1372 ENTRY_INTEL(shld_u ## a_cBits, X86_EFL_OF | X86_EFL_CF), \
1373 ENTRY_AMD(shrd_u ## a_cBits, X86_EFL_OF | X86_EFL_CF), \
1374 ENTRY_INTEL(shrd_u ## a_cBits, X86_EFL_OF | X86_EFL_CF), \
1375}; \
1376\
1377GEN_SHIFT_DBL(a_cBits, a_Fmt, a_aSubTests) \
1378\
1379static void ShiftDblU ## a_cBits ## Test(void) \
1380{ \
1381 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
1382 { \
1383 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
1384 BINU ## a_cBits ## _TEST_T const * const paTests = a_aSubTests[iFn].paTests; \
1385 uint32_t const cTests = a_aSubTests[iFn].cTests; \
1386 PFNIEMAIMPLSHIFTDBLU ## a_cBits pfn = a_aSubTests[iFn].pfn; \
1387 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
1388 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
1389 { \
1390 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1391 { \
1392 uint32_t fEfl = paTests[iTest].fEflIn; \
1393 a_Type uDst = paTests[iTest].uDstIn; \
1394 pfn(&uDst, paTests[iTest].uSrcIn, paTests[iTest].uMisc, &fEfl); \
1395 if ( uDst != paTests[iTest].uDstOut \
1396 || fEfl != paTests[iTest].fEflOut) \
1397 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", \
1398 iTest, iVar == 0 ? "" : "/n", paTests[iTest].fEflIn, \
1399 paTests[iTest].uDstIn, paTests[iTest].uSrcIn, (unsigned)paTests[iTest].uMisc, \
1400 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut, \
1401 EFlagsDiff(fEfl, paTests[iTest].fEflOut), uDst == paTests[iTest].uDstOut ? "" : " dst!"); \
1402 else \
1403 { \
1404 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
1405 *g_pfEfl = paTests[iTest].fEflIn; \
1406 pfn(g_pu ## a_cBits, paTests[iTest].uSrcIn, paTests[iTest].uMisc, g_pfEfl); \
1407 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDstOut); \
1408 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut); \
1409 } \
1410 } \
1411 pfn = a_aSubTests[iFn].pfnNative; \
1412 } \
1413 } \
1414}
1415TEST_SHIFT_DBL(16, uint16_t, "%#06RX16", g_aShiftDblU16)
1416TEST_SHIFT_DBL(32, uint32_t, "%#010RX32", g_aShiftDblU32)
1417TEST_SHIFT_DBL(64, uint64_t, "%#018RX64", g_aShiftDblU64)
1418
1419#ifdef TSTIEMAIMPL_WITH_GENERATOR
1420static void ShiftDblGenerate(PRTSTREAM pOut, const char *pszCpuSuffU, uint32_t cTests)
1421{
1422 RTStrmPrintf(pOut, "\n\n#define HAVE_SHIFT_DBL_TESTS%s\n", pszCpuSuffU);
1423 ShiftDblU16Generate(pOut, cTests);
1424 ShiftDblU32Generate(pOut, cTests);
1425 ShiftDblU64Generate(pOut, cTests);
1426}
1427#endif
1428
1429static void ShiftDblTest(void)
1430{
1431 ShiftDblU16Test();
1432 ShiftDblU32Test();
1433 ShiftDblU64Test();
1434}
1435
1436
1437/*
1438 * Unary operators.
1439 *
1440 * Note! We use BINUxx_TEST_T ignoreing uSrcIn and uMisc.
1441 */
1442
1443#ifndef HAVE_UNARY_TESTS
1444# define DUMMY_UNARY_TESTS(a_cBits, a_Type) \
1445 static const a_Type g_aTests_inc_u ## a_cBits[] = { {0} }; \
1446 static const a_Type g_aTests_inc_u ## a_cBits ## _locked[] = { {0} }; \
1447 static const a_Type g_aTests_dec_u ## a_cBits[] = { {0} }; \
1448 static const a_Type g_aTests_dec_u ## a_cBits ## _locked[] = { {0} }; \
1449 static const a_Type g_aTests_not_u ## a_cBits[] = { {0} }; \
1450 static const a_Type g_aTests_not_u ## a_cBits ## _locked[] = { {0} }; \
1451 static const a_Type g_aTests_neg_u ## a_cBits[] = { {0} }; \
1452 static const a_Type g_aTests_neg_u ## a_cBits ## _locked[] = { {0} }
1453DUMMY_UNARY_TESTS(8, BINU8_TEST_T);
1454DUMMY_UNARY_TESTS(16, BINU16_TEST_T);
1455DUMMY_UNARY_TESTS(32, BINU32_TEST_T);
1456DUMMY_UNARY_TESTS(64, BINU64_TEST_T);
1457#endif
1458
1459#define TEST_UNARY(a_cBits, a_Type, a_Fmt, a_TestType) \
1460static const struct \
1461{ \
1462 const char *pszName; \
1463 PFNIEMAIMPLUNARYU ## a_cBits pfn; \
1464 PFNIEMAIMPLUNARYU ## a_cBits pfnNative; \
1465 a_TestType const *paTests; \
1466 uint32_t cTests, uExtra; \
1467 uint8_t idxCpuEflFlavour; \
1468} g_aUnaryU ## a_cBits [] = \
1469{ \
1470 ENTRY(inc_u ## a_cBits), \
1471 ENTRY(inc_u ## a_cBits ## _locked), \
1472 ENTRY(dec_u ## a_cBits), \
1473 ENTRY(dec_u ## a_cBits ## _locked), \
1474 ENTRY(not_u ## a_cBits), \
1475 ENTRY(not_u ## a_cBits ## _locked), \
1476 ENTRY(neg_u ## a_cBits), \
1477 ENTRY(neg_u ## a_cBits ## _locked), \
1478}; \
1479\
1480void UnaryU ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
1481{ \
1482 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aUnaryU ## a_cBits); iFn++) \
1483 { \
1484 RTStrmPrintf(pOut, "static const BINU" #a_cBits "_TEST_T g_aTests_%s[] =\n{\n", g_aUnaryU ## a_cBits[iFn].pszName); \
1485 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1486 { \
1487 a_TestType Test; \
1488 Test.fEflIn = RandEFlags(); \
1489 Test.fEflOut = Test.fEflIn; \
1490 Test.uDstIn = RandU ## a_cBits(); \
1491 Test.uDstOut = Test.uDstIn; \
1492 Test.uSrcIn = 0; \
1493 Test.uMisc = 0; \
1494 g_aUnaryU ## a_cBits[iFn].pfn(&Test.uDstOut, &Test.fEflOut); \
1495 RTStrmPrintf(pOut, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", 0, 0 }, /* #%u */\n", \
1496 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, iTest); \
1497 } \
1498 RTStrmPrintf(pOut, "};\n"); \
1499 } \
1500} \
1501\
1502static void UnaryU ## a_cBits ## Test(void) \
1503{ \
1504 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aUnaryU ## a_cBits); iFn++) \
1505 { \
1506 RTTestSub(g_hTest, g_aUnaryU ## a_cBits[iFn].pszName); \
1507 a_TestType const * const paTests = g_aUnaryU ## a_cBits[iFn].paTests; \
1508 uint32_t const cTests = g_aUnaryU ## a_cBits[iFn].cTests; \
1509 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1510 { \
1511 uint32_t fEfl = paTests[iTest].fEflIn; \
1512 a_Type uDst = paTests[iTest].uDstIn; \
1513 g_aUnaryU ## a_cBits[iFn].pfn(&uDst, &fEfl); \
1514 if ( uDst != paTests[iTest].uDstOut \
1515 || fEfl != paTests[iTest].fEflOut) \
1516 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=" a_Fmt " -> efl=%#08x dst=" a_Fmt ", expected %#08x & " a_Fmt "%s\n", \
1517 iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, \
1518 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut, \
1519 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
1520 else \
1521 { \
1522 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
1523 *g_pfEfl = paTests[iTest].fEflIn; \
1524 g_aUnaryU ## a_cBits[iFn].pfn(g_pu ## a_cBits, g_pfEfl); \
1525 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDstOut); \
1526 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut); \
1527 } \
1528 } \
1529 } \
1530}
1531TEST_UNARY(8, uint8_t, "%#04RX8", BINU8_TEST_T)
1532TEST_UNARY(16, uint16_t, "%#06RX16", BINU16_TEST_T)
1533TEST_UNARY(32, uint32_t, "%#010RX32", BINU32_TEST_T)
1534TEST_UNARY(64, uint64_t, "%#018RX64", BINU64_TEST_T)
1535
1536#ifdef TSTIEMAIMPL_WITH_GENERATOR
1537static void UnaryGenerate(PRTSTREAM pOut, uint32_t cTests)
1538{
1539 RTStrmPrintf(pOut, "\n\n#define HAVE_UNARY_TESTS\n");
1540 UnaryU8Generate(pOut, cTests);
1541 UnaryU16Generate(pOut, cTests);
1542 UnaryU32Generate(pOut, cTests);
1543 UnaryU64Generate(pOut, cTests);
1544}
1545#endif
1546
1547static void UnaryTest(void)
1548{
1549 UnaryU8Test();
1550 UnaryU16Test();
1551 UnaryU32Test();
1552 UnaryU64Test();
1553}
1554
1555
1556/*
1557 * Shifts.
1558 *
1559 * Note! We use BINUxx_TEST_T with the shift count in uMisc and uSrcIn unused.
1560 */
1561#define DUMMY_SHIFT_TESTS(a_cBits, a_Type, a_Vendor) \
1562 static const a_Type g_aTests_rol_u ## a_cBits ## a_Vendor[] = { {0} }; \
1563 static const a_Type g_aTests_ror_u ## a_cBits ## a_Vendor[] = { {0} }; \
1564 static const a_Type g_aTests_rcl_u ## a_cBits ## a_Vendor[] = { {0} }; \
1565 static const a_Type g_aTests_rcr_u ## a_cBits ## a_Vendor[] = { {0} }; \
1566 static const a_Type g_aTests_shl_u ## a_cBits ## a_Vendor[] = { {0} }; \
1567 static const a_Type g_aTests_shr_u ## a_cBits ## a_Vendor[] = { {0} }; \
1568 static const a_Type g_aTests_sar_u ## a_cBits ## a_Vendor[] = { {0} }
1569#ifndef HAVE_SHIFT_TESTS_AMD
1570DUMMY_SHIFT_TESTS(8, BINU8_TEST_T, _amd);
1571DUMMY_SHIFT_TESTS(16, BINU16_TEST_T, _amd);
1572DUMMY_SHIFT_TESTS(32, BINU32_TEST_T, _amd);
1573DUMMY_SHIFT_TESTS(64, BINU64_TEST_T, _amd);
1574#endif
1575#ifndef HAVE_SHIFT_TESTS_INTEL
1576DUMMY_SHIFT_TESTS(8, BINU8_TEST_T, _intel);
1577DUMMY_SHIFT_TESTS(16, BINU16_TEST_T, _intel);
1578DUMMY_SHIFT_TESTS(32, BINU32_TEST_T, _intel);
1579DUMMY_SHIFT_TESTS(64, BINU64_TEST_T, _intel);
1580#endif
1581
1582#ifdef TSTIEMAIMPL_WITH_GENERATOR
1583# define GEN_SHIFT(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
1584void ShiftU ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
1585{ \
1586 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
1587 { \
1588 if ( a_aSubTests[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE \
1589 && a_aSubTests[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour) \
1590 continue; \
1591 RTStrmPrintf(pOut, "static const BINU" #a_cBits "_TEST_T g_aTests_%s[] =\n{\n", a_aSubTests[iFn].pszName); \
1592 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1593 { \
1594 a_TestType Test; \
1595 Test.fEflIn = RandEFlags(); \
1596 Test.fEflOut = Test.fEflIn; \
1597 Test.uDstIn = RandU ## a_cBits ## Dst(iTest); \
1598 Test.uDstOut = Test.uDstIn; \
1599 Test.uSrcIn = 0; \
1600 Test.uMisc = RandU8() & (a_cBits * 4 - 1); /* need to go way beyond the a_cBits limit */ \
1601 a_aSubTests[iFn].pfnNative(&Test.uDstOut, Test.uMisc, &Test.fEflOut); \
1602 RTStrmPrintf(pOut, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", 0, %-2u }, /* #%u */\n", \
1603 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uMisc, iTest); \
1604 \
1605 Test.fEflIn = (~Test.fEflIn & X86_EFL_LIVE_MASK) | X86_EFL_RA1_MASK; \
1606 Test.fEflOut = Test.fEflIn; \
1607 Test.uDstOut = Test.uDstIn; \
1608 a_aSubTests[iFn].pfnNative(&Test.uDstOut, Test.uMisc, &Test.fEflOut); \
1609 RTStrmPrintf(pOut, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", 0, %-2u }, /* #%u b */\n", \
1610 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uMisc, iTest); \
1611 } \
1612 RTStrmPrintf(pOut, "};\n"); \
1613 } \
1614}
1615#else
1616# define GEN_SHIFT(a_cBits, a_Fmt, a_TestType, a_aSubTests)
1617#endif
1618
1619#define TEST_SHIFT(a_cBits, a_Type, a_Fmt, a_TestType, a_aSubTests) \
1620static const struct \
1621{ \
1622 const char *pszName; \
1623 PFNIEMAIMPLSHIFTU ## a_cBits pfn; \
1624 PFNIEMAIMPLSHIFTU ## a_cBits pfnNative; \
1625 a_TestType const *paTests; \
1626 uint32_t cTests, uExtra; \
1627 uint8_t idxCpuEflFlavour; \
1628} a_aSubTests[] = \
1629{ \
1630 ENTRY_AMD( rol_u ## a_cBits, X86_EFL_OF), \
1631 ENTRY_INTEL(rol_u ## a_cBits, X86_EFL_OF), \
1632 ENTRY_AMD( ror_u ## a_cBits, X86_EFL_OF), \
1633 ENTRY_INTEL(ror_u ## a_cBits, X86_EFL_OF), \
1634 ENTRY_AMD( rcl_u ## a_cBits, X86_EFL_OF), \
1635 ENTRY_INTEL(rcl_u ## a_cBits, X86_EFL_OF), \
1636 ENTRY_AMD( rcr_u ## a_cBits, X86_EFL_OF), \
1637 ENTRY_INTEL(rcr_u ## a_cBits, X86_EFL_OF), \
1638 ENTRY_AMD( shl_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
1639 ENTRY_INTEL(shl_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
1640 ENTRY_AMD( shr_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
1641 ENTRY_INTEL(shr_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
1642 ENTRY_AMD( sar_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
1643 ENTRY_INTEL(sar_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
1644}; \
1645\
1646GEN_SHIFT(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
1647\
1648static void ShiftU ## a_cBits ## Test(void) \
1649{ \
1650 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
1651 { \
1652 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
1653 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
1654 uint32_t const cTests = a_aSubTests[iFn].cTests; \
1655 PFNIEMAIMPLSHIFTU ## a_cBits pfn = a_aSubTests[iFn].pfn; \
1656 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
1657 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
1658 { \
1659 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1660 { \
1661 uint32_t fEfl = paTests[iTest].fEflIn; \
1662 a_Type uDst = paTests[iTest].uDstIn; \
1663 pfn(&uDst, paTests[iTest].uMisc, &fEfl); \
1664 if ( uDst != paTests[iTest].uDstOut \
1665 || fEfl != paTests[iTest].fEflOut ) \
1666 RTTestFailed(g_hTest, "#%u%s: efl=%#08x dst=" a_Fmt " shift=%2u -> efl=%#08x dst=" a_Fmt ", expected %#08x & " a_Fmt "%s\n", \
1667 iTest, iVar == 0 ? "" : "/n", \
1668 paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uMisc, \
1669 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut, \
1670 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
1671 else \
1672 { \
1673 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
1674 *g_pfEfl = paTests[iTest].fEflIn; \
1675 pfn(g_pu ## a_cBits, paTests[iTest].uMisc, g_pfEfl); \
1676 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDstOut); \
1677 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut); \
1678 } \
1679 } \
1680 pfn = a_aSubTests[iFn].pfnNative; \
1681 } \
1682 } \
1683}
1684TEST_SHIFT(8, uint8_t, "%#04RX8", BINU8_TEST_T, g_aShiftU8)
1685TEST_SHIFT(16, uint16_t, "%#06RX16", BINU16_TEST_T, g_aShiftU16)
1686TEST_SHIFT(32, uint32_t, "%#010RX32", BINU32_TEST_T, g_aShiftU32)
1687TEST_SHIFT(64, uint64_t, "%#018RX64", BINU64_TEST_T, g_aShiftU64)
1688
1689#ifdef TSTIEMAIMPL_WITH_GENERATOR
1690static void ShiftGenerate(PRTSTREAM pOut, const char *pszCpuSuffU, uint32_t cTests)
1691{
1692 RTStrmPrintf(pOut, "\n\n#define HAVE_SHIFT_TESTS%s\n", pszCpuSuffU);
1693 ShiftU8Generate(pOut, cTests);
1694 ShiftU16Generate(pOut, cTests);
1695 ShiftU32Generate(pOut, cTests);
1696 ShiftU64Generate(pOut, cTests);
1697}
1698#endif
1699
1700static void ShiftTest(void)
1701{
1702 ShiftU8Test();
1703 ShiftU16Test();
1704 ShiftU32Test();
1705 ShiftU64Test();
1706}
1707
1708
1709/*
1710 * Multiplication and division.
1711 *
1712 * Note! The 8-bit functions has a different format, so we need to duplicate things.
1713 * Note! Currently ignoring undefined bits.
1714 */
1715
1716# define DUMMY_MULDIV_TESTS(a_cBits, a_Type, a_Vendor) \
1717 static const a_Type g_aTests_mul_u ## a_cBits ## a_Vendor[] = { {0} }; \
1718 static const a_Type g_aTests_imul_u ## a_cBits ## a_Vendor[] = { {0} }; \
1719 static const a_Type g_aTests_div_u ## a_cBits ## a_Vendor[] = { {0} }; \
1720 static const a_Type g_aTests_idiv_u ## a_cBits ## a_Vendor[] = { {0} }
1721
1722#ifndef HAVE_MULDIV_TESTS_AMD
1723DUMMY_MULDIV_TESTS(8, MULDIVU8_TEST_T, _amd);
1724DUMMY_MULDIV_TESTS(16, MULDIVU16_TEST_T, _amd);
1725DUMMY_MULDIV_TESTS(32, MULDIVU32_TEST_T, _amd);
1726DUMMY_MULDIV_TESTS(64, MULDIVU64_TEST_T, _amd);
1727#endif
1728
1729#ifndef HAVE_MULDIV_TESTS_INTEL
1730DUMMY_MULDIV_TESTS(8, MULDIVU8_TEST_T, _intel);
1731DUMMY_MULDIV_TESTS(16, MULDIVU16_TEST_T, _intel);
1732DUMMY_MULDIV_TESTS(32, MULDIVU32_TEST_T, _intel);
1733DUMMY_MULDIV_TESTS(64, MULDIVU64_TEST_T, _intel);
1734#endif
1735
1736/* U8 */
1737static const struct
1738{
1739 const char *pszName;
1740 PFNIEMAIMPLMULDIVU8 pfn;
1741 PFNIEMAIMPLMULDIVU8 pfnNative;
1742 MULDIVU8_TEST_T const *paTests;
1743 uint32_t cTests, uExtra;
1744 uint8_t idxCpuEflFlavour;
1745} g_aMulDivU8[] =
1746{
1747 ENTRY_AMD_EX(mul_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF,
1748 X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF),
1749 ENTRY_INTEL_EX(mul_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0),
1750 ENTRY_AMD_EX(imul_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF,
1751 X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF),
1752 ENTRY_INTEL_EX(imul_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0),
1753 ENTRY_AMD_EX(div_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0),
1754 ENTRY_INTEL_EX(div_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0),
1755 ENTRY_AMD_EX(idiv_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0),
1756 ENTRY_INTEL_EX(idiv_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0),
1757};
1758
1759#ifdef TSTIEMAIMPL_WITH_GENERATOR
1760static void MulDivU8Generate(PRTSTREAM pOut, uint32_t cTests)
1761{
1762 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aMulDivU8); iFn++)
1763 {
1764 if ( g_aMulDivU8[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE
1765 && g_aMulDivU8[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour)
1766 continue;
1767 RTStrmPrintf(pOut, "static const MULDIVU8_TEST_T g_aTests_%s[] =\n{\n", g_aMulDivU8[iFn].pszName);
1768 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
1769 {
1770 MULDIVU8_TEST_T Test;
1771 Test.fEflIn = RandEFlags();
1772 Test.fEflOut = Test.fEflIn;
1773 Test.uDstIn = RandU16Dst(iTest);
1774 Test.uDstOut = Test.uDstIn;
1775 Test.uSrcIn = RandU8Src(iTest);
1776 Test.rc = g_aMulDivU8[iFn].pfnNative(&Test.uDstOut, Test.uSrcIn, &Test.fEflOut);
1777 RTStrmPrintf(pOut, " { %#08x, %#08x, %#06RX16, %#06RX16, %#04RX8, %d }, /* #%u */\n",
1778 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uSrcIn, Test.rc, iTest);
1779 }
1780 RTStrmPrintf(pOut, "};\n");
1781 }
1782}
1783#endif
1784
1785static void MulDivU8Test(void)
1786{
1787 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aMulDivU8); iFn++)
1788 {
1789 RTTestSub(g_hTest, g_aMulDivU8[iFn].pszName);
1790 MULDIVU8_TEST_T const * const paTests = g_aMulDivU8[iFn].paTests;
1791 uint32_t const cTests = g_aMulDivU8[iFn].cTests;
1792 uint32_t const fEflIgn = g_aMulDivU8[iFn].uExtra;
1793 PFNIEMAIMPLMULDIVU8 pfn = g_aMulDivU8[iFn].pfn;
1794 uint32_t const cVars = 1 + (g_aMulDivU8[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && g_aMulDivU8[iFn].pfnNative);
1795 for (uint32_t iVar = 0; iVar < cVars; iVar++)
1796 {
1797 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
1798 {
1799 uint32_t fEfl = paTests[iTest].fEflIn;
1800 uint16_t uDst = paTests[iTest].uDstIn;
1801 int rc = g_aMulDivU8[iFn].pfn(&uDst, paTests[iTest].uSrcIn, &fEfl);
1802 if ( uDst != paTests[iTest].uDstOut
1803 || (fEfl | fEflIgn) != (paTests[iTest].fEflOut | fEflIgn)
1804 || rc != paTests[iTest].rc)
1805 RTTestFailed(g_hTest, "#%02u%s: efl=%#08x dst=%#06RX16 src=%#04RX8\n"
1806 " %s-> efl=%#08x dst=%#06RX16 rc=%d\n"
1807 "%sexpected %#08x %#06RX16 %d%s\n",
1808 iTest, iVar ? "/n" : "", paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn,
1809 iVar ? " " : "", fEfl, uDst, rc,
1810 iVar ? " " : "", paTests[iTest].fEflOut, paTests[iTest].uDstOut, paTests[iTest].rc,
1811 EFlagsDiff(fEfl | fEflIgn, paTests[iTest].fEflOut | fEflIgn));
1812 else
1813 {
1814 *g_pu16 = paTests[iTest].uDstIn;
1815 *g_pfEfl = paTests[iTest].fEflIn;
1816 rc = g_aMulDivU8[iFn].pfn(g_pu16, paTests[iTest].uSrcIn, g_pfEfl);
1817 RTTEST_CHECK(g_hTest, *g_pu16 == paTests[iTest].uDstOut);
1818 RTTEST_CHECK(g_hTest, (*g_pfEfl | fEflIgn) == (paTests[iTest].fEflOut | fEflIgn));
1819 RTTEST_CHECK(g_hTest, rc == paTests[iTest].rc);
1820 }
1821 }
1822 pfn = g_aMulDivU8[iFn].pfnNative;
1823 }
1824 }
1825}
1826
1827#ifdef TSTIEMAIMPL_WITH_GENERATOR
1828# define GEN_MULDIV(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
1829void MulDivU ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
1830{ \
1831 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
1832 { \
1833 if ( a_aSubTests[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE \
1834 && a_aSubTests[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour) \
1835 continue; \
1836 RTStrmPrintf(pOut, "static const MULDIVU" #a_cBits "_TEST_T g_aTests_%s[] =\n{\n", a_aSubTests[iFn].pszName); \
1837 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1838 { \
1839 a_TestType Test; \
1840 Test.fEflIn = RandEFlags(); \
1841 Test.fEflOut = Test.fEflIn; \
1842 Test.uDst1In = RandU ## a_cBits ## Dst(iTest); \
1843 Test.uDst1Out = Test.uDst1In; \
1844 Test.uDst2In = RandU ## a_cBits ## Dst(iTest); \
1845 Test.uDst2Out = Test.uDst2In; \
1846 Test.uSrcIn = RandU ## a_cBits ## Src(iTest); \
1847 Test.rc = a_aSubTests[iFn].pfnNative(&Test.uDst1Out, &Test.uDst2Out, Test.uSrcIn, &Test.fEflOut); \
1848 RTStrmPrintf(pOut, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", " a_Fmt ", " a_Fmt ", " a_Fmt ", %d }, /* #%u */\n", \
1849 Test.fEflIn, Test.fEflOut, Test.uDst1In, Test.uDst1Out, Test.uDst2In, Test.uDst2Out, Test.uSrcIn, \
1850 Test.rc, iTest); \
1851 } \
1852 RTStrmPrintf(pOut, "};\n"); \
1853 } \
1854}
1855#else
1856# define GEN_MULDIV(a_cBits, a_Fmt, a_TestType, a_aSubTests)
1857#endif
1858
1859#define TEST_MULDIV(a_cBits, a_Type, a_Fmt, a_TestType, a_aSubTests) \
1860static const struct \
1861{ \
1862 const char *pszName; \
1863 PFNIEMAIMPLMULDIVU ## a_cBits pfn; \
1864 PFNIEMAIMPLMULDIVU ## a_cBits pfnNative; \
1865 a_TestType const *paTests; \
1866 uint32_t cTests, uExtra; \
1867 uint8_t idxCpuEflFlavour; \
1868} a_aSubTests [] = \
1869{ \
1870 ENTRY_AMD_EX(mul_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0), \
1871 ENTRY_INTEL_EX(mul_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0), \
1872 ENTRY_AMD_EX(imul_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0), \
1873 ENTRY_INTEL_EX(imul_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0), \
1874 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), \
1875 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), \
1876 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), \
1877 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), \
1878}; \
1879\
1880GEN_MULDIV(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
1881\
1882static void MulDivU ## a_cBits ## Test(void) \
1883{ \
1884 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
1885 { \
1886 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
1887 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
1888 uint32_t const cTests = a_aSubTests[iFn].cTests; \
1889 uint32_t const fEflIgn = a_aSubTests[iFn].uExtra; \
1890 PFNIEMAIMPLMULDIVU ## a_cBits pfn = a_aSubTests[iFn].pfn; \
1891 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
1892 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
1893 { \
1894 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1895 { \
1896 uint32_t fEfl = paTests[iTest].fEflIn; \
1897 a_Type uDst1 = paTests[iTest].uDst1In; \
1898 a_Type uDst2 = paTests[iTest].uDst2In; \
1899 int rc = pfn(&uDst1, &uDst2, paTests[iTest].uSrcIn, &fEfl); \
1900 if ( uDst1 != paTests[iTest].uDst1Out \
1901 || uDst2 != paTests[iTest].uDst2Out \
1902 || (fEfl | fEflIgn) != (paTests[iTest].fEflOut | fEflIgn)\
1903 || rc != paTests[iTest].rc) \
1904 RTTestFailed(g_hTest, "#%02u%s: efl=%#08x dst1=" a_Fmt " dst2=" a_Fmt " src=" a_Fmt "\n" \
1905 " -> efl=%#08x dst1=" a_Fmt " dst2=" a_Fmt " rc=%d\n" \
1906 "expected %#08x " a_Fmt " " a_Fmt " %d%s -%s%s%s\n", \
1907 iTest, iVar == 0 ? "" : "/n", \
1908 paTests[iTest].fEflIn, paTests[iTest].uDst1In, paTests[iTest].uDst2In, paTests[iTest].uSrcIn, \
1909 fEfl, uDst1, uDst2, rc, \
1910 paTests[iTest].fEflOut, paTests[iTest].uDst1Out, paTests[iTest].uDst2Out, paTests[iTest].rc, \
1911 EFlagsDiff(fEfl | fEflIgn, paTests[iTest].fEflOut | fEflIgn), \
1912 uDst1 != paTests[iTest].uDst1Out ? " dst1" : "", uDst2 != paTests[iTest].uDst2Out ? " dst2" : "", \
1913 (fEfl | fEflIgn) != (paTests[iTest].fEflOut | fEflIgn) ? " eflags" : ""); \
1914 else \
1915 { \
1916 *g_pu ## a_cBits = paTests[iTest].uDst1In; \
1917 *g_pu ## a_cBits ## Two = paTests[iTest].uDst2In; \
1918 *g_pfEfl = paTests[iTest].fEflIn; \
1919 rc = pfn(g_pu ## a_cBits, g_pu ## a_cBits ## Two, paTests[iTest].uSrcIn, g_pfEfl); \
1920 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDst1Out); \
1921 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits ## Two == paTests[iTest].uDst2Out); \
1922 RTTEST_CHECK(g_hTest, (*g_pfEfl | fEflIgn) == (paTests[iTest].fEflOut | fEflIgn)); \
1923 RTTEST_CHECK(g_hTest, rc == paTests[iTest].rc); \
1924 } \
1925 } \
1926 pfn = a_aSubTests[iFn].pfnNative; \
1927 } \
1928 } \
1929}
1930TEST_MULDIV(16, uint16_t, "%#06RX16", MULDIVU16_TEST_T, g_aMulDivU16)
1931TEST_MULDIV(32, uint32_t, "%#010RX32", MULDIVU32_TEST_T, g_aMulDivU32)
1932TEST_MULDIV(64, uint64_t, "%#018RX64", MULDIVU64_TEST_T, g_aMulDivU64)
1933
1934#ifdef TSTIEMAIMPL_WITH_GENERATOR
1935static void MulDivGenerate(PRTSTREAM pOut, const char *pszCpuSuffU, uint32_t cTests)
1936{
1937 RTStrmPrintf(pOut, "\n\n#define HAVE_MULDIV_TESTS%s\n", pszCpuSuffU);
1938 MulDivU8Generate(pOut, cTests);
1939 MulDivU16Generate(pOut, cTests);
1940 MulDivU32Generate(pOut, cTests);
1941 MulDivU64Generate(pOut, cTests);
1942}
1943#endif
1944
1945static void MulDivTest(void)
1946{
1947 MulDivU8Test();
1948 MulDivU16Test();
1949 MulDivU32Test();
1950 MulDivU64Test();
1951}
1952
1953
1954/*
1955 * BSWAP
1956 */
1957static void BswapTest(void)
1958{
1959 RTTestSub(g_hTest, "bswap_u16");
1960 *g_pu32 = UINT32_C(0x12345678);
1961 iemAImpl_bswap_u16(g_pu32);
1962#if 0
1963 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0x12347856), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
1964#else
1965 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0x12340000), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
1966#endif
1967 *g_pu32 = UINT32_C(0xffff1122);
1968 iemAImpl_bswap_u16(g_pu32);
1969#if 0
1970 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0xffff2211), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
1971#else
1972 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0xffff0000), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
1973#endif
1974
1975 RTTestSub(g_hTest, "bswap_u32");
1976 *g_pu32 = UINT32_C(0x12345678);
1977 iemAImpl_bswap_u32(g_pu32);
1978 RTTEST_CHECK(g_hTest, *g_pu32 == UINT32_C(0x78563412));
1979
1980 RTTestSub(g_hTest, "bswap_u64");
1981 *g_pu64 = UINT64_C(0x0123456789abcdef);
1982 iemAImpl_bswap_u64(g_pu64);
1983 RTTEST_CHECK(g_hTest, *g_pu64 == UINT64_C(0xefcdab8967452301));
1984}
1985
1986
1987
1988/*********************************************************************************************************************************
1989* Floating point (x87 style) *
1990*********************************************************************************************************************************/
1991
1992typedef struct FPU_LD_CONST_TEST_T
1993{
1994 uint16_t fFcw;
1995 uint16_t fFswIn;
1996 uint16_t fFswOut;
1997 RTFLOAT80U rdResult;
1998} FPU_LD_CONST_TEST_T;
1999
2000typedef struct FPU_R32_IN_TEST_T
2001{
2002 uint16_t fFcw;
2003 uint16_t fFswIn;
2004 uint16_t fFswOut;
2005 RTFLOAT80U rdResult;
2006 RTFLOAT32U InVal;
2007} FPU_R32_IN_TEST_T;
2008
2009typedef struct FPU_R64_IN_TEST_T
2010{
2011 uint16_t fFcw;
2012 uint16_t fFswIn;
2013 uint16_t fFswOut;
2014 RTFLOAT80U rdResult;
2015 RTFLOAT64U InVal;
2016} FPU_R64_IN_TEST_T;
2017
2018typedef struct FPU_R80_IN_TEST_T
2019{
2020 uint16_t fFcw;
2021 uint16_t fFswIn;
2022 uint16_t fFswOut;
2023 RTFLOAT80U rdResult;
2024 RTFLOAT80U InVal;
2025} FPU_R80_IN_TEST_T;
2026#include "tstIEMAImplDataFpu.h"
2027
2028
2029/*
2030 * FPU constant loading.
2031 */
2032
2033#ifndef HAVE_FPU_LOAD_CONST_TESTS
2034static const FPU_LD_CONST_TEST_T g_aTests_fld1[] = { {0} };
2035static const FPU_LD_CONST_TEST_T g_aTests_fldl2t[] = { {0} };
2036static const FPU_LD_CONST_TEST_T g_aTests_fldl2e[] = { {0} };
2037static const FPU_LD_CONST_TEST_T g_aTests_fldpi[] = { {0} };
2038static const FPU_LD_CONST_TEST_T g_aTests_fldlg2[] = { {0} };
2039static const FPU_LD_CONST_TEST_T g_aTests_fldln2[] = { {0} };
2040static const FPU_LD_CONST_TEST_T g_aTests_fldz[] = { {0} };
2041#endif
2042
2043typedef struct FPU_LD_CONST_T
2044{
2045 const char *pszName;
2046 PFNIEMAIMPLFPUR80LDCONST pfn;
2047 PFNIEMAIMPLFPUR80LDCONST pfnNative;
2048 FPU_LD_CONST_TEST_T const *paTests;
2049 uint32_t cTests;
2050 uint32_t uExtra;
2051 uint8_t idxCpuEflFlavour;
2052} FPU_LD_CONST_T;
2053
2054static const FPU_LD_CONST_T g_aFpuLdConst[] =
2055{
2056 ENTRY(fld1),
2057 ENTRY(fldl2t),
2058 ENTRY(fldl2e),
2059 ENTRY(fldpi),
2060 ENTRY(fldlg2),
2061 ENTRY(fldln2),
2062 ENTRY(fldz),
2063};
2064
2065#ifdef TSTIEMAIMPL_WITH_GENERATOR
2066static void FpuLdConstGenerate(PRTSTREAM pOut, uint32_t cTests)
2067{
2068 RTStrmPrintf(pOut, "\n\n#define HAVE_FPU_LOAD_CONST_TESTS\n");
2069 X86FXSTATE State;
2070 RT_ZERO(State);
2071 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuLdConst); iFn++)
2072 {
2073 RTStrmPrintf(pOut, "static const FPU_LD_CONST_TEST_T g_aTests_%s[] =\n{\n", g_aFpuLdConst[iFn].pszName);
2074 for (uint32_t iTest = 0; iTest < cTests; iTest += 4)
2075 {
2076 State.FCW = RandU16() & (X86_FCW_MASK_ALL | X86_FCW_PC_MASK);
2077 State.FSW = RandU16() & (X86_FSW_C_MASK | X86_FSW_XCPT_ES_MASK | X86_FSW_TOP_MASK | X86_FSW_B);
2078
2079 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
2080 {
2081 IEMFPURESULT Res;
2082 State.FCW = (State.FCW & ~X86_FCW_RC_MASK) | (iRounding << X86_FCW_RC_SHIFT);
2083 g_aFpuLdConst[iFn].pfn(&State, &Res);
2084 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s }, /* #%u */\n",
2085 State.FCW, State.FSW, Res.FSW, GenFormatR80(&Res.r80Result), iTest + iRounding);
2086 }
2087 }
2088 RTStrmPrintf(pOut, "};\n");
2089 }
2090}
2091#endif
2092
2093static void FpuLoadConstTest(void)
2094{
2095 /*
2096 * Inputs:
2097 * - FSW: C0, C1, C2, C3
2098 * - FCW: Exception masks, Precision control, Rounding control.
2099 *
2100 * C1 set to 1 on stack overflow, zero otherwise. C0, C2, and C3 are "undefined".
2101 */
2102 X86FXSTATE State;
2103 RT_ZERO(State);
2104 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuLdConst); iFn++)
2105 {
2106 RTTestSub(g_hTest, g_aFpuLdConst[iFn].pszName);
2107
2108 uint32_t const cTests = g_aFpuLdConst[iFn].cTests;
2109 FPU_LD_CONST_TEST_T const *paTests = g_aFpuLdConst[iFn].paTests;
2110 PFNIEMAIMPLFPUR80LDCONST pfn = g_aFpuLdConst[iFn].pfn;
2111 uint32_t const cVars = 1 + (g_aFpuLdConst[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && g_aFpuLdConst[iFn].pfnNative);
2112 for (uint32_t iVar = 0; iVar < cVars; iVar++)
2113 {
2114 for (uint32_t iTest = 0; iTest < cTests; iTest++)
2115 {
2116 State.FCW = paTests[iTest].fFcw;
2117 State.FSW = paTests[iTest].fFswIn;
2118 IEMFPURESULT Res;
2119 pfn(&State, &Res);
2120 if ( Res.FSW != paTests[iTest].fFswOut
2121 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult))
2122 RTTestFailed(g_hTest, "#%u%s: fcw=%#06x fsw=%#06x -> fsw=%#06x %s, expected %#06x %s%s%s (%s)\n",
2123 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
2124 Res.FSW, FormatR80(&Res.r80Result),
2125 paTests[iTest].fFswOut, FormatR80(&paTests[iTest].rdResult),
2126 FswDiff(Res.FSW, paTests[iTest].fFswOut),
2127 !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult) ? " - val" : "",
2128 FormatFcw(paTests[iTest].fFcw) );
2129 }
2130 pfn = g_aFpuLdConst[iFn].pfnNative;
2131 }
2132 }
2133}
2134
2135
2136/*
2137 * Load values from memory.
2138 */
2139
2140#ifndef HAVE_FPU_LD_MEM
2141static FPU_R80_IN_TEST_T const g_aTests_fld_r80_from_r80[] = { {0} };
2142static FPU_R64_IN_TEST_T const g_aTests_fld_r80_from_r64[] = { {0} };
2143static FPU_R32_IN_TEST_T const g_aTests_fld_r80_from_r32[] = { {0} };
2144#endif
2145
2146#ifdef TSTIEMAIMPL_WITH_GENERATOR
2147# define GEN_FPU_LOAD(a_cBits, a_rdTypeIn, a_aSubTests, a_TestType) \
2148static void FpuLdR ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
2149{ \
2150 X86FXSTATE State; \
2151 RT_ZERO(State); \
2152 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2153 { \
2154 RTStrmPrintf(pOut, "static const " #a_TestType " g_aTests_%s[] =\n{\n", a_aSubTests[iFn].pszName); \
2155 for (uint32_t iTest = 0; iTest < cTests; iTest += 4) \
2156 { \
2157 State.FCW = RandU16() & (X86_FCW_MASK_ALL | X86_FCW_PC_MASK); \
2158 State.FSW = RandU16() & (X86_FSW_C_MASK | X86_FSW_XCPT_ES_MASK | X86_FSW_TOP_MASK | X86_FSW_B); \
2159 a_rdTypeIn InVal = RandR ## a_cBits ## Src(iTest); \
2160 \
2161 for (uint16_t iRounding = 0; iRounding < 4; iRounding++) \
2162 { \
2163 IEMFPURESULT Res; \
2164 State.FCW = (State.FCW & ~X86_FCW_RC_MASK) | (iRounding << X86_FCW_RC_SHIFT); \
2165 a_aSubTests[iFn].pfn(&State, &Res, &InVal); \
2166 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u */\n", \
2167 State.FCW, State.FSW, Res.FSW, GenFormatR80(&Res.r80Result), \
2168 GenFormatR ## a_cBits(&InVal), iTest + iRounding); \
2169 } \
2170 } \
2171 RTStrmPrintf(pOut, "};\n"); \
2172 } \
2173}
2174#else
2175# define GEN_FPU_LOAD(a_cBits, a_rdTypeIn, a_aSubTests, a_TestType)
2176#endif
2177
2178#define TEST_FPU_LOAD(a_cBits, a_rdTypeIn, a_SubTestType, a_aSubTests, a_TestType) \
2179typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLFPULDR80FROM ## a_cBits,(PCX86FXSTATE, PIEMFPURESULT, PC ## a_rdTypeIn)); \
2180typedef FNIEMAIMPLFPULDR80FROM ## a_cBits *PFNIEMAIMPLFPULDR80FROM ## a_cBits; \
2181typedef struct a_SubTestType \
2182{ \
2183 const char *pszName; \
2184 PFNIEMAIMPLFPULDR80FROM ## a_cBits pfn, pfnNative; \
2185 a_TestType const *paTests; \
2186 uint32_t cTests; \
2187 uint32_t uExtra; \
2188 uint8_t idxCpuEflFlavour; \
2189} a_SubTestType; \
2190\
2191static const a_SubTestType a_aSubTests[] = \
2192{ \
2193 ENTRY(RT_CONCAT(fld_r80_from_r,a_cBits)) \
2194}; \
2195GEN_FPU_LOAD(a_cBits, a_rdTypeIn, a_aSubTests, a_TestType) \
2196\
2197static void FpuLdR ## a_cBits ## Test(void) \
2198{ \
2199 X86FXSTATE State; \
2200 RT_ZERO(State); \
2201 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2202 { \
2203 RTTestSub(g_hTest, a_aSubTests[iFn].pszName); \
2204 \
2205 uint32_t const cTests = a_aSubTests[iFn].cTests; \
2206 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
2207 PFNIEMAIMPLFPULDR80FROM ## a_cBits pfn = a_aSubTests[iFn].pfn; \
2208 uint32_t const cVars = 1 + (a_aSubTests[iFn].idxCpuEflFlavour == g_idxCpuEflFlavour && a_aSubTests[iFn].pfnNative); \
2209 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
2210 { \
2211 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
2212 { \
2213 a_rdTypeIn const InVal = paTests[iTest].InVal; \
2214 State.FCW = paTests[iTest].fFcw; \
2215 State.FSW = paTests[iTest].fFswIn; \
2216 IEMFPURESULT Res; \
2217 pfn(&State, &Res, &InVal); \
2218 if ( Res.FSW != paTests[iTest].fFswOut \
2219 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult)) \
2220 RTTestFailed(g_hTest, "#%u%s: fcw=%#06x fsw=%#06x in=%s -> fsw=%#06x %s, expected %#06x %s%s%s (%s)\n", \
2221 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, \
2222 FormatR ## a_cBits(&paTests[iTest].InVal), \
2223 Res.FSW, FormatR80(&Res.r80Result), \
2224 paTests[iTest].fFswOut, FormatR80(&paTests[iTest].rdResult), \
2225 FswDiff(Res.FSW, paTests[iTest].fFswOut), \
2226 !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult) ? " - val" : "", \
2227 FormatFcw(paTests[iTest].fFcw) ); \
2228 } \
2229 pfn = a_aSubTests[iFn].pfnNative; \
2230 } \
2231 } \
2232}
2233
2234TEST_FPU_LOAD(80, RTFLOAT80U, FPU_LD_R80_T, g_aFpuLdR80, FPU_R80_IN_TEST_T)
2235TEST_FPU_LOAD(64, RTFLOAT64U, FPU_LD_R64_T, g_aFpuLdR64, FPU_R64_IN_TEST_T)
2236TEST_FPU_LOAD(32, RTFLOAT32U, FPU_LD_R32_T, g_aFpuLdR32, FPU_R32_IN_TEST_T)
2237
2238#ifdef TSTIEMAIMPL_WITH_GENERATOR
2239static void FpuLdMemGenerate(PRTSTREAM pOut, uint32_t cTests)
2240{
2241 RTStrmPrintf(pOut, "\n\n#define HAVE_FPU_LD_MEM\n");
2242 FpuLdR80Generate(pOut, cTests);
2243 FpuLdR64Generate(pOut, cTests);
2244 FpuLdR32Generate(pOut, cTests);
2245}
2246#endif
2247
2248static void FpuLdMemTest(void)
2249{
2250 FpuLdR80Test();
2251 FpuLdR64Test();
2252 FpuLdR32Test();
2253}
2254
2255
2256int main(int argc, char **argv)
2257{
2258 int rc = RTR3InitExe(argc, &argv, 0);
2259 if (RT_FAILURE(rc))
2260 return RTMsgInitFailure(rc);
2261
2262 /*
2263 * Determin the host CPU.
2264 * If not using the IEMAllAImpl.asm code, this will be set to Intel.
2265 */
2266#if (defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && !defined(IEM_WITHOUT_ASSEMBLY)
2267 g_idxCpuEflFlavour = ASMIsAmdCpu() || ASMIsHygonCpu()
2268 ? IEMTARGETCPU_EFL_BEHAVIOR_AMD
2269 : IEMTARGETCPU_EFL_BEHAVIOR_INTEL;
2270#else
2271 g_idxCpuEflFlavour = IEMTARGETCPU_EFL_BEHAVIOR_INTEL;
2272#endif
2273
2274 /*
2275 * Parse arguments.
2276 */
2277 enum { kModeNotSet, kModeTest, kModeGenerate }
2278 enmMode = kModeNotSet;
2279 bool fInt = true;
2280 bool fFpu = true;
2281 bool fCpuData = true;
2282 bool fCommonData = true;
2283 RTGETOPTDEF const s_aOptions[] =
2284 {
2285 { "--generate", 'g', RTGETOPT_REQ_NOTHING },
2286 { "--test", 't', RTGETOPT_REQ_NOTHING },
2287 { "--all", 'a', RTGETOPT_REQ_NOTHING },
2288 { "--only-fpu", 'f', RTGETOPT_REQ_NOTHING },
2289 { "--only-int", 'i', RTGETOPT_REQ_NOTHING },
2290 { "--only-common", 'm', RTGETOPT_REQ_NOTHING },
2291 { "--only-cpu", 'c', RTGETOPT_REQ_NOTHING },
2292 };
2293
2294 RTGETOPTSTATE State;
2295 rc = RTGetOptInit(&State, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
2296 AssertRCReturn(rc, RTEXITCODE_FAILURE);
2297
2298 RTGETOPTUNION ValueUnion;
2299 while ((rc = RTGetOpt(&State, &ValueUnion)))
2300 {
2301 switch (rc)
2302 {
2303 case 'g':
2304 enmMode = kModeGenerate;
2305 break;
2306 case 't':
2307 enmMode = kModeTest;
2308 break;
2309 case 'a':
2310 fCpuData = true;
2311 fCommonData = true;
2312 fInt = true;
2313 fFpu = true;
2314 break;
2315 case 'f':
2316 fFpu = true;
2317 fInt = false;
2318 break;
2319 case 'i':
2320 fInt = true;
2321 fFpu = false;
2322 break;
2323 case 'm':
2324 fCommonData = true;
2325 fCpuData = false;
2326 break;
2327 case 'c':
2328 fCpuData = true;
2329 fCommonData = false;
2330 break;
2331 case 'h':
2332 RTPrintf("usage: %s <-g|-t> [options]\n"
2333 "\n"
2334 "Mode:\n"
2335 " -g, --generate\n"
2336 " Generate test data.\n"
2337 " -t, --test\n"
2338 " Execute tests.\n"
2339 "\n"
2340 "Options:\n"
2341 " -a, --all\n"
2342 " Include all tests and generates common + CPU test data. (default)\n"
2343 " -i, --only-int\n"
2344 " Only non-FPU tests.\n"
2345 " -f, --only-fpu\n"
2346 " Only FPU tests.\n"
2347 " -m, --only-common\n"
2348 " Only generate common test data.\n"
2349 " -c, --only-cpu\n"
2350 " Only generate CPU specific test data.\n"
2351 , argv[0]);
2352 return RTEXITCODE_SUCCESS;
2353 default:
2354 return RTGetOptPrintError(rc, &ValueUnion);
2355 }
2356 }
2357
2358 /*
2359 * Generate data?
2360 */
2361 if (enmMode == kModeGenerate)
2362 {
2363#ifdef TSTIEMAIMPL_WITH_GENERATOR
2364 char szCpuDesc[256] = {0};
2365 RTMpGetDescription(NIL_RTCPUID, szCpuDesc, sizeof(szCpuDesc));
2366 const char * const pszCpuType = g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD ? "Amd" : "Intel";
2367 const char * const pszCpuSuff = g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD ? "_Amd" : "_Intel";
2368 const char * const pszCpuSuffU = g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD ? "_AMD" : "_INTEL";
2369# if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
2370 const char * const pszBitBucket = "NUL";
2371# else
2372 const char * const pszBitBucket = "/dev/null";
2373# endif
2374
2375 uint32_t cTests = 96;
2376 g_cZeroDstTests = RT_MIN(cTests / 16, 32);
2377 g_cZeroSrcTests = g_cZeroDstTests * 2;
2378
2379 if (fInt)
2380 {
2381 const char *pszDataFile = fCommonData ? "tstIEMAImplData.h" : pszBitBucket;
2382 PRTSTREAM pStrmData = NULL;
2383 rc = RTStrmOpen(pszDataFile, "w", &pStrmData);
2384 if (!pStrmData)
2385 return RTMsgErrorExitFailure("Failed to open %s for writing: %Rrc", pszDataFile, rc);
2386
2387 const char *pszDataCpuFile = !fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
2388 ? "tstIEMAImplData-Amd.h" : "tstIEMAImplData-Intel.h";
2389 PRTSTREAM pStrmDataCpu = NULL;
2390 rc = RTStrmOpen(pszDataCpuFile, "w", &pStrmDataCpu);
2391 if (!pStrmData)
2392 return RTMsgErrorExitFailure("Failed to open %s for writing: %Rrc", pszDataCpuFile, rc);
2393
2394 GenerateHeader(pStrmData, "", szCpuDesc, NULL, "");
2395 GenerateHeader(pStrmDataCpu, "", szCpuDesc, pszCpuType, pszCpuSuff);
2396
2397 BinU8Generate( pStrmData, pStrmDataCpu, pszCpuSuffU, cTests);
2398 BinU16Generate(pStrmData, pStrmDataCpu, pszCpuSuffU, cTests);
2399 BinU32Generate(pStrmData, pStrmDataCpu, pszCpuSuffU, cTests);
2400 BinU64Generate(pStrmData, pStrmDataCpu, pszCpuSuffU, cTests);
2401 ShiftDblGenerate(pStrmDataCpu, pszCpuSuffU, RT_MAX(cTests, 128));
2402 UnaryGenerate(pStrmData, cTests);
2403 ShiftGenerate(pStrmDataCpu, pszCpuSuffU, cTests);
2404 MulDivGenerate(pStrmDataCpu, pszCpuSuffU, cTests);
2405
2406 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile, "", pszCpuSuff,
2407 GenerateFooterAndClose(pStrmData, pszDataFile, "", "",
2408 RTEXITCODE_SUCCESS));
2409 if (rcExit != RTEXITCODE_SUCCESS)
2410 return rcExit;
2411 }
2412
2413 if (fFpu)
2414 {
2415 const char *pszDataFile = fCommonData ? "tstIEMAImplDataFpu.h" : pszBitBucket;
2416 PRTSTREAM pStrmData = NULL;
2417 rc = RTStrmOpen(pszDataFile, "w", &pStrmData);
2418 if (!pStrmData)
2419 return RTMsgErrorExitFailure("Failed to open %s for writing: %Rrc", pszDataFile, rc);
2420
2421 const char *pszDataCpuFile = !fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
2422 ? "tstIEMAImplDataFpu-Amd.h" : "tstIEMAImplDataFpu-Intel.h";
2423 PRTSTREAM pStrmDataCpu = NULL;
2424 rc = RTStrmOpen(pszDataCpuFile, "w", &pStrmDataCpu);
2425 if (!pStrmData)
2426 return RTMsgErrorExitFailure("Failed to open %s for writing: %Rrc", pszDataCpuFile, rc);
2427
2428 GenerateHeader(pStrmData, "Fpu", szCpuDesc, NULL, "");
2429 GenerateHeader(pStrmDataCpu, "Fpu", szCpuDesc, pszCpuType, pszCpuSuff);
2430
2431 FpuLdConstGenerate(pStrmData, cTests);
2432 FpuLdMemGenerate(pStrmData, cTests);
2433
2434 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile, "Fpu", pszCpuSuff,
2435 GenerateFooterAndClose(pStrmData, pszDataFile, "Fpu", "",
2436 RTEXITCODE_SUCCESS));
2437 if (rcExit != RTEXITCODE_SUCCESS)
2438 return rcExit;
2439 }
2440 return RTEXITCODE_SUCCESS;
2441#else
2442 return RTMsgErrorExitFailure("Test data generator not compiled in!");
2443#endif
2444 }
2445
2446 /*
2447 * Do testing. Currrently disabled by default as data needs to be checked
2448 * on both intel and AMD systems first.
2449 */
2450 rc = RTTestCreate("tstIEMAimpl", &g_hTest);
2451 AssertRCReturn(rc, RTEXITCODE_FAILURE);
2452 if (enmMode == kModeTest)
2453 {
2454 RTTestBanner(g_hTest);
2455
2456 /* Allocate guarded memory for use in the tests. */
2457#define ALLOC_GUARDED_VAR(a_puVar) do { \
2458 rc = RTTestGuardedAlloc(g_hTest, sizeof(*a_puVar), sizeof(*a_puVar), false /*fHead*/, (void **)&a_puVar); \
2459 if (RT_FAILURE(rc)) RTTestFailed(g_hTest, "Failed to allocate guarded mem: " #a_puVar); \
2460 } while (0)
2461 ALLOC_GUARDED_VAR(g_pu8);
2462 ALLOC_GUARDED_VAR(g_pu16);
2463 ALLOC_GUARDED_VAR(g_pu32);
2464 ALLOC_GUARDED_VAR(g_pu64);
2465 ALLOC_GUARDED_VAR(g_pu128);
2466 ALLOC_GUARDED_VAR(g_pu8Two);
2467 ALLOC_GUARDED_VAR(g_pu16Two);
2468 ALLOC_GUARDED_VAR(g_pu32Two);
2469 ALLOC_GUARDED_VAR(g_pu64Two);
2470 ALLOC_GUARDED_VAR(g_pu128Two);
2471 ALLOC_GUARDED_VAR(g_pfEfl);
2472 if (RTTestErrorCount(g_hTest) == 0)
2473 {
2474 if (fInt)
2475 {
2476 BinU8Test();
2477 BinU16Test();
2478 BinU32Test();
2479 BinU64Test();
2480 XchgTest();
2481 XaddTest();
2482 CmpXchgTest();
2483 CmpXchg8bTest();
2484 CmpXchg16bTest();
2485 ShiftDblTest();
2486 UnaryTest();
2487 ShiftTest();
2488 MulDivTest();
2489 BswapTest();
2490 }
2491
2492 if (fFpu)
2493 {
2494 FpuLoadConstTest();
2495 FpuLdMemTest();
2496 }
2497 }
2498 return RTTestSummaryAndDestroy(g_hTest);
2499 }
2500 return RTTestSkipAndDestroy(g_hTest, "unfinished testcase");
2501}
Note: See TracBrowser for help on using the repository browser.

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