VirtualBox

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

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

VMM/IEM: Added tests for bswap C workers, discovering weird behaviour for the undocumented 16-bit variant on an AMD 3990x. bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 68.1 KB
Line 
1/* $Id: tstIEMAImpl.cpp 93893 2022-02-22 21:27:58Z 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/initterm.h>
28#include <iprt/message.h>
29#include <iprt/mp.h>
30#include <iprt/rand.h>
31#include <iprt/stream.h>
32#include <iprt/string.h>
33#include <iprt/test.h>
34
35
36/*********************************************************************************************************************************
37* Structures and Typedefs *
38*********************************************************************************************************************************/
39/** @name 8-bit binary (PFNIEMAIMPLBINU8)
40 * @{ */
41typedef struct BINU8_TEST_T
42{
43 uint32_t fEflIn;
44 uint32_t fEflOut;
45 uint8_t uDstIn;
46 uint8_t uDstOut;
47 uint8_t uSrcIn;
48 uint8_t uMisc;
49} BINU8_TEST_T;
50
51typedef struct BINU8_T
52{
53 const char *pszName;
54 PFNIEMAIMPLBINU8 pfn;
55 BINU8_TEST_T const *paTests;
56 uint32_t cTests;
57 uint32_t uExtra;
58} BINU8_T;
59/** @} */
60
61
62/** @name 16-bit binary (PFNIEMAIMPLBINU16)
63 * @{ */
64typedef struct BINU16_TEST_T
65{
66 uint32_t fEflIn;
67 uint32_t fEflOut;
68 uint16_t uDstIn;
69 uint16_t uDstOut;
70 uint16_t uSrcIn;
71 uint16_t uMisc;
72} BINU16_TEST_T;
73
74typedef struct BINU16_T
75{
76 const char *pszName;
77 PFNIEMAIMPLBINU16 pfn;
78 BINU16_TEST_T const *paTests;
79 uint32_t cTests;
80 uint32_t uExtra;
81} BINU16_T;
82/** @} */
83
84
85/** @name 32-bit binary (PFNIEMAIMPLBINU32)
86 * @{ */
87typedef struct BINU32_TEST_T
88{
89 uint32_t fEflIn;
90 uint32_t fEflOut;
91 uint32_t uDstIn;
92 uint32_t uDstOut;
93 uint32_t uSrcIn;
94 uint32_t uMisc;
95} BINU32_TEST_T;
96
97typedef struct BINU32_T
98{
99 const char *pszName;
100 PFNIEMAIMPLBINU32 pfn;
101 BINU32_TEST_T const *paTests;
102 uint32_t cTests;
103 uint32_t uExtra;
104} BINU32_T;
105/** @} */
106
107
108/** @name 64-bit binary (PFNIEMAIMPLBINU64)
109 * @{ */
110typedef struct BINU64_TEST_T
111{
112 uint32_t fEflIn;
113 uint32_t fEflOut;
114 uint64_t uDstIn;
115 uint64_t uDstOut;
116 uint64_t uSrcIn;
117 uint64_t uMisc;
118} BINU64_TEST_T;
119
120typedef struct BINU64_T
121{
122 const char *pszName;
123 PFNIEMAIMPLBINU64 pfn;
124 BINU64_TEST_T const *paTests;
125 uint32_t cTests;
126 uint32_t uExtra;
127} BINU64_T;
128/** @} */
129
130
131/** @name mult/div (PFNIEMAIMPLBINU8, PFNIEMAIMPLBINU16, PFNIEMAIMPLBINU32, PFNIEMAIMPLBINU64)
132 * @{ */
133typedef struct MULDIVU8_TEST_T
134{
135 uint32_t fEflIn;
136 uint32_t fEflOut;
137 uint16_t uDstIn;
138 uint16_t uDstOut;
139 uint8_t uSrcIn;
140 int32_t rc;
141} MULDIVU8_TEST_T;
142
143typedef struct MULDIVU16_TEST_T
144{
145 uint32_t fEflIn;
146 uint32_t fEflOut;
147 uint16_t uDst1In;
148 uint16_t uDst1Out;
149 uint16_t uDst2In;
150 uint16_t uDst2Out;
151 uint16_t uSrcIn;
152 int32_t rc;
153} MULDIVU16_TEST_T;
154
155typedef struct MULDIVU32_TEST_T
156{
157 uint32_t fEflIn;
158 uint32_t fEflOut;
159 uint32_t uDst1In;
160 uint32_t uDst1Out;
161 uint32_t uDst2In;
162 uint32_t uDst2Out;
163 uint32_t uSrcIn;
164 int32_t rc;
165} MULDIVU32_TEST_T;
166
167typedef struct MULDIVU64_TEST_T
168{
169 uint32_t fEflIn;
170 uint32_t fEflOut;
171 uint64_t uDst1In;
172 uint64_t uDst1Out;
173 uint64_t uDst2In;
174 uint64_t uDst2Out;
175 uint64_t uSrcIn;
176 int32_t rc;
177} MULDIVU64_TEST_T;
178/** @} */
179
180
181/*********************************************************************************************************************************
182* Defined Constants And Macros *
183*********************************************************************************************************************************/
184#define ENTRY(a_Name) ENTRY_EX(a_Name, 0)
185#define ENTRY_EX(a_Name, a_uExtra) \
186 { #a_Name, iemAImpl_ ## a_Name, g_aTests_ ## a_Name, RT_ELEMENTS(g_aTests_ ## a_Name), a_uExtra }
187
188
189/*********************************************************************************************************************************
190* Internal Functions *
191*********************************************************************************************************************************/
192static uint32_t RandEFlags(void);
193static uint8_t RandU8(void);
194static uint16_t RandU16(void);
195static uint32_t RandU32(void);
196static uint64_t RandU64(void);
197static RTUINT128U RandU128(void);
198
199
200/*********************************************************************************************************************************
201* Global Variables *
202*********************************************************************************************************************************/
203static RTTEST g_hTest;
204static uint8_t *g_pu8, *g_pu8Two;
205static uint16_t *g_pu16, *g_pu16Two;
206static uint32_t *g_pu32, *g_pu32Two, *g_pfEfl;
207static uint64_t *g_pu64, *g_pu64Two;
208static RTUINT128U *g_pu128, *g_pu128Two;
209
210
211#include "tstIEMAImplData.h"
212
213/*
214 * Test helpers.
215 */
216static const char *EFlagsDiff(uint32_t fActual, uint32_t fExpected)
217{
218 if (fActual == fExpected)
219 return "";
220
221 uint32_t const fXor = fActual ^ fExpected;
222 static char s_szBuf[256];
223 size_t cch = RTStrPrintf(s_szBuf, sizeof(s_szBuf), " - %#x", fXor);
224
225 static struct
226 {
227 const char *pszName;
228 uint32_t fFlag;
229 } const s_aFlags[] =
230 {
231#define EFL_ENTRY(a_Flags) { #a_Flags, X86_EFL_ ## a_Flags }
232 EFL_ENTRY(CF),
233 EFL_ENTRY(PF),
234 EFL_ENTRY(AF),
235 EFL_ENTRY(ZF),
236 EFL_ENTRY(SF),
237 EFL_ENTRY(TF),
238 EFL_ENTRY(IF),
239 EFL_ENTRY(DF),
240 EFL_ENTRY(OF),
241 EFL_ENTRY(IOPL),
242 EFL_ENTRY(NT),
243 EFL_ENTRY(RF),
244 EFL_ENTRY(VM),
245 EFL_ENTRY(AC),
246 EFL_ENTRY(VIF),
247 EFL_ENTRY(VIP),
248 EFL_ENTRY(ID),
249 };
250 for (size_t i = 0; i < RT_ELEMENTS(s_aFlags); i++)
251 if (s_aFlags[i].fFlag & fXor)
252 cch += RTStrPrintf(&s_szBuf[cch], sizeof(s_szBuf) - cch,
253 s_aFlags[i].fFlag & fActual ? "/%s" : "/!%s", s_aFlags[i].pszName);
254 RTStrPrintf(&s_szBuf[cch], sizeof(s_szBuf) - cch, "");
255 return s_szBuf;
256}
257
258
259/*
260 * 8-bit binary operations.
261 */
262
263#ifndef HAVE_BINU8_TESTS
264static const BINU8_TEST_T g_aTests_add_u8[] = { {0} };
265static const BINU8_TEST_T g_aTests_add_u8_locked[] = { {0} };
266static const BINU8_TEST_T g_aTests_adc_u8[] = { {0} };
267static const BINU8_TEST_T g_aTests_adc_u8_locked[] = { {0} };
268static const BINU8_TEST_T g_aTests_sub_u8[] = { {0} };
269static const BINU8_TEST_T g_aTests_sub_u8_locked[] = { {0} };
270static const BINU8_TEST_T g_aTests_sbb_u8[] = { {0} };
271static const BINU8_TEST_T g_aTests_sbb_u8_locked[] = { {0} };
272static const BINU8_TEST_T g_aTests_or_u8[] = { {0} };
273static const BINU8_TEST_T g_aTests_or_u8_locked[] = { {0} };
274static const BINU8_TEST_T g_aTests_xor_u8[] = { {0} };
275static const BINU8_TEST_T g_aTests_xor_u8_locked[] = { {0} };
276static const BINU8_TEST_T g_aTests_and_u8[] = { {0} };
277static const BINU8_TEST_T g_aTests_and_u8_locked[] = { {0} };
278static const BINU8_TEST_T g_aTests_cmp_u8[] = { {0} };
279static const BINU8_TEST_T g_aTests_test_u8[] = { {0} };
280#endif
281
282static const BINU8_T g_aBinU8[] =
283{
284 ENTRY(add_u8),
285 ENTRY(add_u8_locked),
286 ENTRY(adc_u8),
287 ENTRY(adc_u8_locked),
288 ENTRY(sub_u8),
289 ENTRY(sub_u8_locked),
290 ENTRY(sbb_u8),
291 ENTRY(sbb_u8_locked),
292 ENTRY(or_u8),
293 ENTRY(or_u8_locked),
294 ENTRY(xor_u8),
295 ENTRY(xor_u8_locked),
296 ENTRY(and_u8),
297 ENTRY(and_u8_locked),
298 ENTRY(cmp_u8),
299 ENTRY(test_u8),
300};
301
302
303static void BinU8Generate(uint32_t cTests)
304{
305 RTPrintf("\n\n#define HAVE_BINU8_TESTS\n");
306 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aBinU8); iFn++)
307 {
308 RTPrintf("static const BINU8_TEST_T g_aTests_%s[] =\n{\n", g_aBinU8[iFn].pszName);
309 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
310 {
311 BINU8_TEST_T Test;
312 Test.fEflIn = RandEFlags();
313 Test.fEflOut = Test.fEflIn;
314 Test.uDstIn = RandU8();
315 Test.uDstOut = Test.uDstIn;
316 Test.uSrcIn = RandU8();
317 Test.uMisc = 0;
318 g_aBinU8[iFn].pfn(&Test.uDstOut, Test.uSrcIn, &Test.fEflOut);
319 RTPrintf(" { %#08x, %#08x, %#04x, %#04x, %#04x, %#x }, /* #%u */\n",
320 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uSrcIn, Test.uMisc, iTest);
321 }
322 RTPrintf("};\n");
323 }
324}
325
326static void BinU8Test(void)
327{
328 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aBinU8); iFn++)
329 {
330 RTTestSub(g_hTest, g_aBinU8[iFn].pszName);
331
332 BINU8_TEST_T const * const paTests = g_aBinU8[iFn].paTests;
333 uint32_t const cTests = g_aBinU8[iFn].cTests;
334 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
335 {
336 uint32_t fEfl = paTests[iTest].fEflIn;
337 uint8_t uDst = paTests[iTest].uDstIn;
338 g_aBinU8[iFn].pfn(&uDst, paTests[iTest].uSrcIn, &fEfl);
339 if ( uDst != paTests[iTest].uDstOut
340 || fEfl != paTests[iTest].fEflOut)
341 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=%#04x src=%#04x -> efl=%#08x dst=%#04x, expected %#08x & %#04x%s - %s\n",
342 iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn,
343 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut,
344 EFlagsDiff(fEfl, paTests[iTest].fEflOut),
345 uDst == paTests[iTest].uDstOut ? "eflags" : fEfl == paTests[iTest].fEflOut ? "dst" : "both");
346 else
347 {
348 *g_pu8 = paTests[iTest].uDstIn;
349 *g_pfEfl = paTests[iTest].fEflIn;
350 g_aBinU8[iFn].pfn(g_pu8, paTests[iTest].uSrcIn, g_pfEfl);
351 RTTEST_CHECK(g_hTest, *g_pu8 == paTests[iTest].uDstOut);
352 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut);
353 }
354 }
355 }
356}
357
358
359/*
360 * 16-bit binary operations.
361 */
362
363#ifndef HAVE_BINU16_TESTS
364static const BINU16_TEST_T g_aTests_add_u16[] = { {0} };
365static const BINU16_TEST_T g_aTests_add_u16_locked[] = { {0} };
366static const BINU16_TEST_T g_aTests_adc_u16[] = { {0} };
367static const BINU16_TEST_T g_aTests_adc_u16_locked[] = { {0} };
368static const BINU16_TEST_T g_aTests_sub_u16[] = { {0} };
369static const BINU16_TEST_T g_aTests_sub_u16_locked[] = { {0} };
370static const BINU16_TEST_T g_aTests_sbb_u16[] = { {0} };
371static const BINU16_TEST_T g_aTests_sbb_u16_locked[] = { {0} };
372static const BINU16_TEST_T g_aTests_or_u16[] = { {0} };
373static const BINU16_TEST_T g_aTests_or_u16_locked[] = { {0} };
374static const BINU16_TEST_T g_aTests_xor_u16[] = { {0} };
375static const BINU16_TEST_T g_aTests_xor_u16_locked[] = { {0} };
376static const BINU16_TEST_T g_aTests_and_u16[] = { {0} };
377static const BINU16_TEST_T g_aTests_and_u16_locked[] = { {0} };
378static const BINU16_TEST_T g_aTests_cmp_u16[] = { {0} };
379static const BINU16_TEST_T g_aTests_test_u16[] = { {0} };
380static const BINU16_TEST_T g_aTests_bt_u16[] = { {0} };
381static const BINU16_TEST_T g_aTests_btc_u16[] = { {0} };
382static const BINU16_TEST_T g_aTests_btc_u16_locked[] = { {0} };
383static const BINU16_TEST_T g_aTests_btr_u16[] = { {0} };
384static const BINU16_TEST_T g_aTests_btr_u16_locked[] = { {0} };
385static const BINU16_TEST_T g_aTests_bts_u16[] = { {0} };
386static const BINU16_TEST_T g_aTests_bts_u16_locked[] = { {0} };
387static const BINU16_TEST_T g_aTests_bsf_u16[] = { {0} };
388static const BINU16_TEST_T g_aTests_bsr_u16[] = { {0} };
389static const BINU16_TEST_T g_aTests_imul_two_u16[] = { {0} };
390static const BINU16_TEST_T g_aTests_arpl[] = { {0} };
391#endif
392
393static const BINU16_T g_aBinU16[] =
394{
395 ENTRY(add_u16),
396 ENTRY(add_u16_locked),
397 ENTRY(adc_u16),
398 ENTRY(adc_u16_locked),
399 ENTRY(sub_u16),
400 ENTRY(sub_u16_locked),
401 ENTRY(sbb_u16),
402 ENTRY(sbb_u16_locked),
403 ENTRY(or_u16),
404 ENTRY(or_u16_locked),
405 ENTRY(xor_u16),
406 ENTRY(xor_u16_locked),
407 ENTRY(and_u16),
408 ENTRY(and_u16_locked),
409 ENTRY(cmp_u16),
410 ENTRY(test_u16),
411 ENTRY_EX(bt_u16, 1),
412 ENTRY_EX(btc_u16, 1),
413 ENTRY_EX(btc_u16_locked, 1),
414 ENTRY_EX(btr_u16, 1),
415 ENTRY_EX(btr_u16_locked, 1),
416 ENTRY_EX(bts_u16, 1),
417 ENTRY_EX(bts_u16_locked, 1),
418 ENTRY(bsf_u16),
419 ENTRY(bsr_u16),
420 ENTRY(imul_two_u16),
421 ENTRY(arpl),
422};
423
424static void BinU16Generate(uint32_t cTests)
425{
426 RTPrintf("\n\n#define HAVE_BINU16_TESTS\n");
427 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aBinU16); iFn++)
428 {
429 RTPrintf("static const BINU16_TEST_T g_aTests_%s[] =\n{\n", g_aBinU16[iFn].pszName);
430 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
431 {
432 BINU16_TEST_T Test;
433 Test.fEflIn = RandEFlags();
434 Test.fEflOut = Test.fEflIn;
435 Test.uDstIn = RandU16();
436 Test.uDstOut = Test.uDstIn;
437 Test.uSrcIn = RandU16();
438 if (g_aBinU16[iFn].uExtra)
439 Test.uSrcIn &= 0xf; /* Restrict bit index to a word */
440 Test.uMisc = 0;
441 g_aBinU16[iFn].pfn(&Test.uDstOut, Test.uSrcIn, &Test.fEflOut);
442 RTPrintf(" { %#08x, %#08x, %#06x, %#06x, %#06x, %#x }, /* #%u */\n",
443 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uSrcIn, Test.uMisc, iTest);
444 }
445 RTPrintf("};\n");
446 }
447}
448
449static void BinU16Test(void)
450{
451 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aBinU16); iFn++)
452 {
453 RTTestSub(g_hTest, g_aBinU16[iFn].pszName);
454
455 BINU16_TEST_T const * const paTests = g_aBinU16[iFn].paTests;
456 uint32_t const cTests = g_aBinU16[iFn].cTests;
457 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
458 {
459 uint32_t fEfl = paTests[iTest].fEflIn;
460 uint16_t uDst = paTests[iTest].uDstIn;
461 g_aBinU16[iFn].pfn(&uDst, paTests[iTest].uSrcIn, &fEfl);
462 if ( uDst != paTests[iTest].uDstOut
463 || fEfl != paTests[iTest].fEflOut)
464 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=%#06x src=%#06x -> efl=%#08x dst=%#06x, expected %#08x & %#06x%s - %s\n",
465 iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn,
466 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut,
467 EFlagsDiff(fEfl, paTests[iTest].fEflOut),
468 uDst == paTests[iTest].uDstOut ? "eflags" : fEfl == paTests[iTest].fEflOut ? "dst" : "both");
469 else
470 {
471 *g_pu16 = paTests[iTest].uDstIn;
472 *g_pfEfl = paTests[iTest].fEflIn;
473 g_aBinU16[iFn].pfn(g_pu16, paTests[iTest].uSrcIn, g_pfEfl);
474 RTTEST_CHECK(g_hTest, *g_pu16== paTests[iTest].uDstOut);
475 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut);
476 }
477 }
478 }
479}
480
481
482/*
483 * 32-bit binary operations.
484 */
485
486#ifndef HAVE_BINU32_TESTS
487static const BINU32_TEST_T g_aTests_add_u32[] = { {0} };
488static const BINU32_TEST_T g_aTests_add_u32_locked[] = { {0} };
489static const BINU32_TEST_T g_aTests_adc_u32[] = { {0} };
490static const BINU32_TEST_T g_aTests_adc_u32_locked[] = { {0} };
491static const BINU32_TEST_T g_aTests_sub_u32[] = { {0} };
492static const BINU32_TEST_T g_aTests_sub_u32_locked[] = { {0} };
493static const BINU32_TEST_T g_aTests_sbb_u32[] = { {0} };
494static const BINU32_TEST_T g_aTests_sbb_u32_locked[] = { {0} };
495static const BINU32_TEST_T g_aTests_or_u32[] = { {0} };
496static const BINU32_TEST_T g_aTests_or_u32_locked[] = { {0} };
497static const BINU32_TEST_T g_aTests_xor_u32[] = { {0} };
498static const BINU32_TEST_T g_aTests_xor_u32_locked[] = { {0} };
499static const BINU32_TEST_T g_aTests_and_u32[] = { {0} };
500static const BINU32_TEST_T g_aTests_and_u32_locked[] = { {0} };
501static const BINU32_TEST_T g_aTests_cmp_u32[] = { {0} };
502static const BINU32_TEST_T g_aTests_test_u32[] = { {0} };
503static const BINU32_TEST_T g_aTests_bt_u32[] = { {0} };
504static const BINU32_TEST_T g_aTests_btc_u32[] = { {0} };
505static const BINU32_TEST_T g_aTests_btc_u32_locked[] = { {0} };
506static const BINU32_TEST_T g_aTests_btr_u32[] = { {0} };
507static const BINU32_TEST_T g_aTests_btr_u32_locked[] = { {0} };
508static const BINU32_TEST_T g_aTests_bts_u32[] = { {0} };
509static const BINU32_TEST_T g_aTests_bts_u32_locked[] = { {0} };
510static const BINU32_TEST_T g_aTests_bsf_u32[] = { {0} };
511static const BINU32_TEST_T g_aTests_bsr_u32[] = { {0} };
512static const BINU32_TEST_T g_aTests_imul_two_u32[] = { {0} };
513#endif
514
515static const BINU32_T g_aBinU32[] =
516{
517 ENTRY(add_u32),
518 ENTRY(add_u32_locked),
519 ENTRY(adc_u32),
520 ENTRY(adc_u32_locked),
521 ENTRY(sub_u32),
522 ENTRY(sub_u32_locked),
523 ENTRY(sbb_u32),
524 ENTRY(sbb_u32_locked),
525 ENTRY(or_u32),
526 ENTRY(or_u32_locked),
527 ENTRY(xor_u32),
528 ENTRY(xor_u32_locked),
529 ENTRY(and_u32),
530 ENTRY(and_u32_locked),
531 ENTRY(cmp_u32),
532 ENTRY(test_u32),
533 ENTRY_EX(bt_u32, 1),
534 ENTRY_EX(btc_u32, 1),
535 ENTRY_EX(btc_u32_locked, 1),
536 ENTRY_EX(btr_u32, 1),
537 ENTRY_EX(btr_u32_locked, 1),
538 ENTRY_EX(bts_u32, 1),
539 ENTRY_EX(bts_u32_locked, 1),
540 ENTRY(bsf_u32),
541 ENTRY(bsr_u32),
542 ENTRY(imul_two_u32),
543};
544
545static void BinU32Generate(uint32_t cTests)
546{
547 RTPrintf("\n\n#define HAVE_BINU32_TESTS\n");
548 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aBinU32); iFn++)
549 {
550 RTPrintf("static const BINU32_TEST_T g_aTests_%s[] =\n{\n", g_aBinU32[iFn].pszName);
551 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
552 {
553 BINU32_TEST_T Test;
554 Test.fEflIn = RandEFlags();
555 Test.fEflOut = Test.fEflIn;
556 Test.uDstIn = RandU32();
557 Test.uDstOut = Test.uDstIn;
558 Test.uSrcIn = RandU32();
559 if (g_aBinU32[iFn].uExtra)
560 Test.uSrcIn &= 0x1f; /* Restrict bit index to a word */
561 Test.uMisc = 0;
562 g_aBinU32[iFn].pfn(&Test.uDstOut, Test.uSrcIn, &Test.fEflOut);
563 RTPrintf(" { %#08x, %#08x, %#010RX32, %#010RX32, %#010RX32, %#x }, /* #%u */\n",
564 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uSrcIn, Test.uMisc, iTest);
565 }
566 RTPrintf("};\n");
567 }
568}
569
570static void BinU32Test(void)
571{
572 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aBinU32); iFn++)
573 {
574 RTTestSub(g_hTest, g_aBinU32[iFn].pszName);
575
576 BINU32_TEST_T const * const paTests = g_aBinU32[iFn].paTests;
577 uint32_t const cTests = g_aBinU32[iFn].cTests;
578 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
579 {
580 uint32_t fEfl = paTests[iTest].fEflIn;
581 uint32_t uDst = paTests[iTest].uDstIn;
582 g_aBinU32[iFn].pfn(&uDst, paTests[iTest].uSrcIn, &fEfl);
583 if ( uDst != paTests[iTest].uDstOut
584 || fEfl != paTests[iTest].fEflOut)
585 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=%#010RX32 src=%#010RX32 -> efl=%#08x dst=%#010RX32, expected %#08x & %#010RX32%s - %s\n",
586 iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn,
587 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut,
588 EFlagsDiff(fEfl, paTests[iTest].fEflOut),
589 uDst == paTests[iTest].uDstOut ? "eflags" : fEfl == paTests[iTest].fEflOut ? "dst" : "both");
590 else
591 {
592 *g_pu32 = paTests[iTest].uDstIn;
593 *g_pfEfl = paTests[iTest].fEflIn;
594 g_aBinU32[iFn].pfn(g_pu32, paTests[iTest].uSrcIn, g_pfEfl);
595 RTTEST_CHECK(g_hTest, *g_pu32 == paTests[iTest].uDstOut);
596 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut);
597 }
598 }
599 }
600}
601
602
603/*
604 * 64-bit binary operations.
605 */
606
607#ifndef HAVE_BINU64_TESTS
608static const BINU64_TEST_T g_aTests_add_u64[] = { {0} };
609static const BINU64_TEST_T g_aTests_add_u64_locked[] = { {0} };
610static const BINU64_TEST_T g_aTests_adc_u64[] = { {0} };
611static const BINU64_TEST_T g_aTests_adc_u64_locked[] = { {0} };
612static const BINU64_TEST_T g_aTests_sub_u64[] = { {0} };
613static const BINU64_TEST_T g_aTests_sub_u64_locked[] = { {0} };
614static const BINU64_TEST_T g_aTests_sbb_u64[] = { {0} };
615static const BINU64_TEST_T g_aTests_sbb_u64_locked[] = { {0} };
616static const BINU64_TEST_T g_aTests_or_u64[] = { {0} };
617static const BINU64_TEST_T g_aTests_or_u64_locked[] = { {0} };
618static const BINU64_TEST_T g_aTests_xor_u64[] = { {0} };
619static const BINU64_TEST_T g_aTests_xor_u64_locked[] = { {0} };
620static const BINU64_TEST_T g_aTests_and_u64[] = { {0} };
621static const BINU64_TEST_T g_aTests_and_u64_locked[] = { {0} };
622static const BINU64_TEST_T g_aTests_cmp_u64[] = { {0} };
623static const BINU64_TEST_T g_aTests_test_u64[] = { {0} };
624static const BINU64_TEST_T g_aTests_bt_u64[] = { {0} };
625static const BINU64_TEST_T g_aTests_btc_u64[] = { {0} };
626static const BINU64_TEST_T g_aTests_btc_u64_locked[] = { {0} };
627static const BINU64_TEST_T g_aTests_btr_u64[] = { {0} };
628static const BINU64_TEST_T g_aTests_btr_u64_locked[] = { {0} };
629static const BINU64_TEST_T g_aTests_bts_u64[] = { {0} };
630static const BINU64_TEST_T g_aTests_bts_u64_locked[] = { {0} };
631static const BINU64_TEST_T g_aTests_bsf_u64[] = { {0} };
632static const BINU64_TEST_T g_aTests_bsr_u64[] = { {0} };
633static const BINU64_TEST_T g_aTests_imul_two_u64[] = { {0} };
634#endif
635
636static const BINU64_T g_aBinU64[] =
637{
638 ENTRY(add_u64),
639 ENTRY(add_u64_locked),
640 ENTRY(adc_u64),
641 ENTRY(adc_u64_locked),
642 ENTRY(sub_u64),
643 ENTRY(sub_u64_locked),
644 ENTRY(sbb_u64),
645 ENTRY(sbb_u64_locked),
646 ENTRY(or_u64),
647 ENTRY(or_u64_locked),
648 ENTRY(xor_u64),
649 ENTRY(xor_u64_locked),
650 ENTRY(and_u64),
651 ENTRY(and_u64_locked),
652 ENTRY(cmp_u64),
653 ENTRY(test_u64),
654 ENTRY_EX(bt_u64, 1),
655 ENTRY_EX(btc_u64, 1),
656 ENTRY_EX(btc_u64_locked, 1),
657 ENTRY_EX(btr_u64, 1),
658 ENTRY_EX(btr_u64_locked, 1),
659 ENTRY_EX(bts_u64, 1),
660 ENTRY_EX(bts_u64_locked, 1),
661 ENTRY(bsf_u64),
662 ENTRY(bsr_u64),
663 ENTRY(imul_two_u64),
664};
665
666static void BinU64Generate(uint32_t cTests)
667{
668 RTPrintf("\n\n#define HAVE_BINU64_TESTS\n");
669 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aBinU64); iFn++)
670 {
671 RTPrintf("static const BINU64_TEST_T g_aTests_%s[] =\n{\n", g_aBinU64[iFn].pszName);
672 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
673 {
674 BINU64_TEST_T Test;
675 Test.fEflIn = RandEFlags();
676 Test.fEflOut = Test.fEflIn;
677 Test.uDstIn = RandU64();
678 Test.uDstOut = Test.uDstIn;
679 Test.uSrcIn = RandU64();
680 if (g_aBinU64[iFn].uExtra)
681 Test.uSrcIn &= 0x3f; /* Restrict bit index to a word */
682 Test.uMisc = 0;
683 g_aBinU64[iFn].pfn(&Test.uDstOut, Test.uSrcIn, &Test.fEflOut);
684 RTPrintf(" { %#08x, %#08x, %#018RX64, %#018RX64, %#018RX64, %#x }, /* #%u */\n",
685 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uSrcIn, Test.uMisc, iTest);
686 }
687 RTPrintf("};\n");
688 }
689}
690
691static void BinU64Test(void)
692{
693 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aBinU64); iFn++)
694 {
695 RTTestSub(g_hTest, g_aBinU64[iFn].pszName);
696
697 BINU64_TEST_T const * const paTests = g_aBinU64[iFn].paTests;
698 uint32_t const cTests = g_aBinU64[iFn].cTests;
699 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
700 {
701 uint32_t fEfl = paTests[iTest].fEflIn;
702 uint64_t uDst = paTests[iTest].uDstIn;
703 g_aBinU64[iFn].pfn(&uDst, paTests[iTest].uSrcIn, &fEfl);
704 if ( uDst != paTests[iTest].uDstOut
705 || fEfl != paTests[iTest].fEflOut)
706 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=%#018RX64 src=%#018RX64 -> efl=%#08x dst=%#018RX64, expected %#08x & %#018RX64%s - %s\n",
707 iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn,
708 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut,
709 EFlagsDiff(fEfl, paTests[iTest].fEflOut),
710 uDst == paTests[iTest].uDstOut ? "eflags" : fEfl == paTests[iTest].fEflOut ? "dst" : "both");
711 else
712 {
713 *g_pu64 = paTests[iTest].uDstIn;
714 *g_pfEfl = paTests[iTest].fEflIn;
715 g_aBinU64[iFn].pfn(g_pu64, paTests[iTest].uSrcIn, g_pfEfl);
716 RTTEST_CHECK(g_hTest, *g_pu64 == paTests[iTest].uDstOut);
717 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut);
718 }
719 }
720 }
721}
722
723
724/*
725 * XCHG
726 */
727static void XchgTest(void)
728{
729 RTTestSub(g_hTest, "xchg");
730 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU8, (uint8_t *pu8Mem, uint8_t *pu8Reg));
731 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU16,(uint16_t *pu16Mem, uint16_t *pu16Reg));
732 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU32,(uint32_t *pu32Mem, uint32_t *pu32Reg));
733 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU64,(uint64_t *pu64Mem, uint64_t *pu64Reg));
734
735 static struct
736 {
737 uint8_t cb; uint64_t fMask;
738 union
739 {
740 uintptr_t pfn;
741 FNIEMAIMPLXCHGU8 *pfnU8;
742 FNIEMAIMPLXCHGU16 *pfnU16;
743 FNIEMAIMPLXCHGU32 *pfnU32;
744 FNIEMAIMPLXCHGU64 *pfnU64;
745 } u;
746 }
747 s_aXchgWorkers[] =
748 {
749 { 1, UINT8_MAX, { (uintptr_t)iemAImpl_xchg_u8_locked } },
750 { 2, UINT16_MAX, { (uintptr_t)iemAImpl_xchg_u16_locked } },
751 { 4, UINT32_MAX, { (uintptr_t)iemAImpl_xchg_u32_locked } },
752 { 8, UINT64_MAX, { (uintptr_t)iemAImpl_xchg_u64_locked } },
753 { 1, UINT8_MAX, { (uintptr_t)iemAImpl_xchg_u8_unlocked } },
754 { 2, UINT16_MAX, { (uintptr_t)iemAImpl_xchg_u16_unlocked } },
755 { 4, UINT32_MAX, { (uintptr_t)iemAImpl_xchg_u32_unlocked } },
756 { 8, UINT64_MAX, { (uintptr_t)iemAImpl_xchg_u64_unlocked } },
757 };
758 for (size_t i = 0; i < RT_ELEMENTS(s_aXchgWorkers); i++)
759 {
760 RTUINT64U uIn1, uIn2, uMem, uDst;
761 uMem.u = uIn1.u = RTRandU64Ex(0, s_aXchgWorkers[i].fMask);
762 uDst.u = uIn2.u = RTRandU64Ex(0, s_aXchgWorkers[i].fMask);
763 if (uIn1.u == uIn2.u)
764 uDst.u = uIn2.u = ~uIn2.u;
765
766 switch (s_aXchgWorkers[i].cb)
767 {
768 case 1:
769 s_aXchgWorkers[i].u.pfnU8(g_pu8, g_pu8Two);
770 s_aXchgWorkers[i].u.pfnU8(&uMem.au8[0], &uDst.au8[0]);
771 break;
772 case 2:
773 s_aXchgWorkers[i].u.pfnU16(g_pu16, g_pu16Two);
774 s_aXchgWorkers[i].u.pfnU16(&uMem.Words.w0, &uDst.Words.w0);
775 break;
776 case 4:
777 s_aXchgWorkers[i].u.pfnU32(g_pu32, g_pu32Two);
778 s_aXchgWorkers[i].u.pfnU32(&uMem.DWords.dw0, &uDst.DWords.dw0);
779 break;
780 case 8:
781 s_aXchgWorkers[i].u.pfnU64(g_pu64, g_pu64Two);
782 s_aXchgWorkers[i].u.pfnU64(&uMem.u, &uDst.u);
783 break;
784 default: RTTestFailed(g_hTest, "%d\n", s_aXchgWorkers[i].cb); break;
785 }
786
787 if (uMem.u != uIn2.u || uDst.u != uIn1.u)
788 RTTestFailed(g_hTest, "i=%u: %#RX64, %#RX64 -> %#RX64, %#RX64\n", i, uIn1.u, uIn2.u, uMem.u, uDst.u);
789 }
790}
791
792
793/*
794 * XADD
795 */
796static void XaddTest(void)
797{
798#define TEST_XADD(a_cBits, a_Type, a_Fmt) do { \
799 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXADDU ## a_cBits, (a_Type *, a_Type *, uint32_t *)); \
800 static struct \
801 { \
802 const char *pszName; \
803 FNIEMAIMPLXADDU ## a_cBits *pfn; \
804 BINU ## a_cBits ## _TEST_T const *paTests; \
805 uint32_t cTests; \
806 } const s_aFuncs[] = \
807 { \
808 { "xadd_u" # a_cBits, iemAImpl_xadd_u ## a_cBits, \
809 g_aTests_add_u ## a_cBits, RT_ELEMENTS(g_aTests_add_u ## a_cBits) }, \
810 { "xadd_u" # a_cBits "8_locked", iemAImpl_xadd_u ## a_cBits ## _locked, \
811 g_aTests_add_u ## a_cBits, RT_ELEMENTS(g_aTests_add_u ## a_cBits) }, \
812 }; \
813 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++) \
814 { \
815 RTTestSub(g_hTest, s_aFuncs[iFn].pszName); \
816 BINU ## a_cBits ## _TEST_T const * const paTests = s_aFuncs[iFn].paTests; \
817 uint32_t const cTests = s_aFuncs[iFn].cTests; \
818 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
819 { \
820 uint32_t fEfl = paTests[iTest].fEflIn; \
821 a_Type uSrc = paTests[iTest].uSrcIn; \
822 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
823 s_aFuncs[iFn].pfn(g_pu ## a_cBits, &uSrc, &fEfl); \
824 if ( fEfl != paTests[iTest].fEflOut \
825 || *g_pu ## a_cBits != paTests[iTest].uDstOut \
826 || uSrc != paTests[iTest].uDstIn) \
827 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", \
828 s_aFuncs[iFn].pszName, iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn, \
829 fEfl, *g_pu ## a_cBits, uSrc, paTests[iTest].fEflOut, paTests[iTest].uDstOut, paTests[iTest].uDstIn, \
830 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
831 } \
832 } \
833 } while(0)
834 TEST_XADD(8, uint8_t, "%#04x");
835 TEST_XADD(16, uint16_t, "%#06x");
836 TEST_XADD(32, uint32_t, "%#010RX32");
837 TEST_XADD(64, uint64_t, "%#010RX64");
838}
839
840
841/*
842 * CMPXCHG
843 */
844
845static void CmpXchgTest(void)
846{
847#define TEST_CMPXCHG(a_cBits, a_Type, a_Fmt) do {\
848 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLCMPXCHGU ## a_cBits, (a_Type *, a_Type *, a_Type, uint32_t *)); \
849 static struct \
850 { \
851 const char *pszName; \
852 FNIEMAIMPLCMPXCHGU ## a_cBits *pfn; \
853 PFNIEMAIMPLBINU ## a_cBits pfnSub; \
854 BINU ## a_cBits ## _TEST_T const *paTests; \
855 uint32_t cTests; \
856 } const s_aFuncs[] = \
857 { \
858 { "cmpxchg_u" # a_cBits, iemAImpl_cmpxchg_u ## a_cBits, iemAImpl_sub_u ## a_cBits, \
859 g_aTests_cmp_u ## a_cBits, RT_ELEMENTS(g_aTests_cmp_u ## a_cBits) }, \
860 { "cmpxchg_u" # a_cBits "_locked", iemAImpl_cmpxchg_u ## a_cBits ## _locked, iemAImpl_sub_u ## a_cBits, \
861 g_aTests_cmp_u ## a_cBits, RT_ELEMENTS(g_aTests_cmp_u ## a_cBits) }, \
862 }; \
863 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++) \
864 { \
865 RTTestSub(g_hTest, s_aFuncs[iFn].pszName); \
866 BINU ## a_cBits ## _TEST_T const * const paTests = s_aFuncs[iFn].paTests; \
867 uint32_t const cTests = s_aFuncs[iFn].cTests; \
868 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
869 { \
870 /* as is (99% likely to be negative). */ \
871 uint32_t fEfl = paTests[iTest].fEflIn; \
872 a_Type const uNew = paTests[iTest].uSrcIn + 0x42; \
873 a_Type uA = paTests[iTest].uDstIn; \
874 *g_pu ## a_cBits = paTests[iTest].uSrcIn; \
875 a_Type const uExpect = uA != paTests[iTest].uSrcIn ? paTests[iTest].uSrcIn : uNew; \
876 s_aFuncs[iFn].pfn(g_pu ## a_cBits, &uA, uNew, &fEfl); \
877 if ( fEfl != paTests[iTest].fEflOut \
878 || *g_pu ## a_cBits != uExpect \
879 || uA != paTests[iTest].uSrcIn) \
880 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", \
881 s_aFuncs[iFn].pszName, iTest, paTests[iTest].fEflIn, paTests[iTest].uSrcIn, paTests[iTest].uDstIn, \
882 uNew, fEfl, *g_pu ## a_cBits, uA, paTests[iTest].fEflOut, uExpect, paTests[iTest].uSrcIn, \
883 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
884 /* positive */ \
885 uint32_t fEflExpect = paTests[iTest].fEflIn; \
886 uA = paTests[iTest].uDstIn; \
887 s_aFuncs[iFn].pfnSub(&uA, uA, &fEflExpect); \
888 fEfl = paTests[iTest].fEflIn; \
889 uA = paTests[iTest].uDstIn; \
890 *g_pu ## a_cBits = uA; \
891 s_aFuncs[iFn].pfn(g_pu ## a_cBits, &uA, uNew, &fEfl); \
892 if ( fEfl != fEflExpect \
893 || *g_pu ## a_cBits != uNew \
894 || uA != paTests[iTest].uDstIn) \
895 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", \
896 s_aFuncs[iFn].pszName, iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uDstIn, \
897 uNew, fEfl, *g_pu ## a_cBits, uA, fEflExpect, uNew, paTests[iTest].uDstIn, \
898 EFlagsDiff(fEfl, fEflExpect)); \
899 } \
900 } \
901 } while(0)
902 TEST_CMPXCHG(8, uint8_t, "%#04RX8");
903 TEST_CMPXCHG(16, uint16_t, "%#06x");
904 TEST_CMPXCHG(32, uint32_t, "%#010RX32");
905#if ARCH_BITS != 32 /* calling convension issue, skipping as it's an unsupported host */
906 TEST_CMPXCHG(64, uint64_t, "%#010RX64");
907#endif
908}
909
910static void CmpXchg8bTest(void)
911{
912 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLCMPXCHG8B,(uint64_t *, PRTUINT64U, PRTUINT64U, uint32_t *));
913 static struct
914 {
915 const char *pszName;
916 FNIEMAIMPLCMPXCHG8B *pfn;
917 } const s_aFuncs[] =
918 {
919 { "cmpxchg8b", iemAImpl_cmpxchg8b },
920 { "cmpxchg8b_locked", iemAImpl_cmpxchg8b_locked },
921 };
922 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++)
923 {
924 RTTestSub(g_hTest, s_aFuncs[iFn].pszName);
925 for (uint32_t iTest = 0; iTest < 4; iTest += 2)
926 {
927 uint64_t const uOldValue = RandU64();
928 uint64_t const uNewValue = RandU64();
929
930 /* positive test. */
931 RTUINT64U uA, uB;
932 uB.u = uNewValue;
933 uA.u = uOldValue;
934 *g_pu64 = uOldValue;
935 uint32_t fEflIn = RandEFlags();
936 uint32_t fEfl = fEflIn;
937 s_aFuncs[iFn].pfn(g_pu64, &uA, &uB, &fEfl);
938 if ( fEfl != (fEflIn | X86_EFL_ZF)
939 || *g_pu64 != uNewValue
940 || uA.u != uOldValue)
941 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",
942 iTest, fEflIn, uOldValue, uOldValue, uNewValue,
943 fEfl, *g_pu64, uA.u,
944 (fEflIn | X86_EFL_ZF), uNewValue, uOldValue, EFlagsDiff(fEfl, fEflIn | X86_EFL_ZF));
945 RTTEST_CHECK(g_hTest, uB.u == uNewValue);
946
947 /* negative */
948 uint64_t const uExpect = ~uOldValue;
949 *g_pu64 = uExpect;
950 uA.u = uOldValue;
951 uB.u = uNewValue;
952 fEfl = fEflIn = RandEFlags();
953 s_aFuncs[iFn].pfn(g_pu64, &uA, &uB, &fEfl);
954 if ( fEfl != (fEflIn & ~X86_EFL_ZF)
955 || *g_pu64 != uExpect
956 || uA.u != uExpect)
957 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",
958 iTest + 1, fEflIn, uExpect, uOldValue, uNewValue,
959 fEfl, *g_pu64, uA.u,
960 (fEflIn & ~X86_EFL_ZF), uExpect, uExpect, EFlagsDiff(fEfl, fEflIn & ~X86_EFL_ZF));
961 RTTEST_CHECK(g_hTest, uB.u == uNewValue);
962 }
963 }
964}
965
966static void CmpXchg16bTest(void)
967{
968 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLCMPXCHG16B,(PRTUINT128U, PRTUINT128U, PRTUINT128U, uint32_t *));
969 static struct
970 {
971 const char *pszName;
972 FNIEMAIMPLCMPXCHG16B *pfn;
973 } const s_aFuncs[] =
974 {
975 { "cmpxchg16b", iemAImpl_cmpxchg16b },
976 { "cmpxchg16b_locked", iemAImpl_cmpxchg16b_locked },
977#if !defined(RT_ARCH_ARM64)
978 { "cmpxchg16b_fallback", iemAImpl_cmpxchg16b_fallback },
979#endif
980 };
981 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++)
982 {
983#if !defined(IEM_WITHOUT_ASSEMBLY) && defined(RT_ARCH_AMD64)
984 if (!(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_CX16))
985 continue;
986#endif
987 RTTestSub(g_hTest, s_aFuncs[iFn].pszName);
988 for (uint32_t iTest = 0; iTest < 4; iTest += 2)
989 {
990 RTUINT128U const uOldValue = RandU128();
991 RTUINT128U const uNewValue = RandU128();
992
993 /* positive test. */
994 RTUINT128U uA, uB;
995 uB = uNewValue;
996 uA = uOldValue;
997 *g_pu128 = uOldValue;
998 uint32_t fEflIn = RandEFlags();
999 uint32_t fEfl = fEflIn;
1000 s_aFuncs[iFn].pfn(g_pu128, &uA, &uB, &fEfl);
1001 if ( fEfl != (fEflIn | X86_EFL_ZF)
1002 || g_pu128->s.Lo != uNewValue.s.Lo
1003 || g_pu128->s.Hi != uNewValue.s.Hi
1004 || uA.s.Lo != uOldValue.s.Lo
1005 || uA.s.Hi != uOldValue.s.Hi)
1006 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=%#018RX64'%016RX64 cmp=%#018RX64'%016RX64 new=%#018RX64'%016RX64\n"
1007 " -> efl=%#08x dst=%#018RX64'%016RX64 old=%#018RX64'%016RX64,\n"
1008 " wanted %#08x, %#018RX64'%016RX64, %#018RX64'%016RX64%s\n",
1009 iTest, fEflIn, uOldValue.s.Hi, uOldValue.s.Lo, uOldValue.s.Hi, uOldValue.s.Lo, uNewValue.s.Hi, uNewValue.s.Lo,
1010 fEfl, g_pu128->s.Hi, g_pu128->s.Lo, uA.s.Hi, uA.s.Lo,
1011 (fEflIn | X86_EFL_ZF), uNewValue.s.Hi, uNewValue.s.Lo, uOldValue.s.Hi, uOldValue.s.Lo,
1012 EFlagsDiff(fEfl, fEflIn | X86_EFL_ZF));
1013 RTTEST_CHECK(g_hTest, uB.s.Lo == uNewValue.s.Lo && uB.s.Hi == uNewValue.s.Hi);
1014
1015 /* negative */
1016 RTUINT128U const uExpect = RTUINT128_INIT(~uOldValue.s.Hi, ~uOldValue.s.Lo);
1017 *g_pu128 = uExpect;
1018 uA = uOldValue;
1019 uB = uNewValue;
1020 fEfl = fEflIn = RandEFlags();
1021 s_aFuncs[iFn].pfn(g_pu128, &uA, &uB, &fEfl);
1022 if ( fEfl != (fEflIn & ~X86_EFL_ZF)
1023 || g_pu128->s.Lo != uExpect.s.Lo
1024 || g_pu128->s.Hi != uExpect.s.Hi
1025 || uA.s.Lo != uExpect.s.Lo
1026 || uA.s.Hi != uExpect.s.Hi)
1027 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=%#018RX64'%016RX64 cmp=%#018RX64'%016RX64 new=%#018RX64'%016RX64\n"
1028 " -> efl=%#08x dst=%#018RX64'%016RX64 old=%#018RX64'%016RX64,\n"
1029 " wanted %#08x, %#018RX64'%016RX64, %#018RX64'%016RX64%s\n",
1030 iTest + 1, fEflIn, uExpect.s.Hi, uExpect.s.Lo, uOldValue.s.Hi, uOldValue.s.Lo, uNewValue.s.Hi, uNewValue.s.Lo,
1031 fEfl, g_pu128->s.Hi, g_pu128->s.Lo, uA.s.Hi, uA.s.Lo,
1032 (fEflIn & ~X86_EFL_ZF), uExpect.s.Hi, uExpect.s.Lo, uExpect.s.Hi, uExpect.s.Lo,
1033 EFlagsDiff(fEfl, fEflIn & ~X86_EFL_ZF));
1034 RTTEST_CHECK(g_hTest, uB.s.Lo == uNewValue.s.Lo && uB.s.Hi == uNewValue.s.Hi);
1035 }
1036 }
1037}
1038
1039
1040/*
1041 * Double shifts.
1042 *
1043 * Note! We use BINUxx_TEST_T with the shift value in the uMisc field.
1044 */
1045
1046#ifndef HAVE_SHIFT_DBL_TESTS
1047static const BINU16_TEST_T g_aTests_shrd_u16[] = { {0} };
1048static const BINU16_TEST_T g_aTests_shld_u16[] = { {0} };
1049static const BINU32_TEST_T g_aTests_shrd_u32[] = { {0} };
1050static const BINU32_TEST_T g_aTests_shld_u32[] = { {0} };
1051static const BINU64_TEST_T g_aTests_shrd_u64[] = { {0} };
1052static const BINU64_TEST_T g_aTests_shld_u64[] = { {0} };
1053#endif
1054
1055#define TEST_SHIFT_DBL(a_cBits, a_Type, a_Fmt) \
1056static const struct \
1057{ \
1058 const char *pszName; \
1059 PFNIEMAIMPLSHIFTDBLU ## a_cBits pfn; \
1060 BINU ## a_cBits ## _TEST_T const *paTests; \
1061 uint32_t cTests, uExtra; \
1062} g_aShiftDblU ## a_cBits [] = \
1063{ \
1064 ENTRY(shld_u ## a_cBits), \
1065 ENTRY(shrd_u ## a_cBits), \
1066}; \
1067\
1068static void ShiftDblU ## a_cBits ## Generate(uint32_t cTests) \
1069{ \
1070 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aShiftDblU ## a_cBits); iFn++) \
1071 { \
1072 RTPrintf("static const BINU" #a_cBits "_TEST_T g_aTests_%s[] =\n{\n", g_aShiftDblU ## a_cBits[iFn].pszName); \
1073 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1074 { \
1075 BINU ## a_cBits ## _TEST_T Test; \
1076 Test.fEflIn = RandEFlags(); \
1077 Test.fEflOut = Test.fEflIn; \
1078 Test.uDstIn = RandU ## a_cBits(); \
1079 Test.uDstOut = Test.uDstIn; \
1080 Test.uSrcIn = RandU ## a_cBits(); \
1081 Test.uMisc = RandU8() & (a_cBits - 1); \
1082 g_aShiftDblU ## a_cBits[iFn].pfn(&Test.uDstOut, Test.uSrcIn, Test.uMisc, &Test.fEflOut); \
1083 RTPrintf(" { %#08x, %#08x, " a_Fmt ", " a_Fmt ", " a_Fmt ", %2u }, /* #%u */\n", \
1084 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uSrcIn, Test.uMisc, iTest); \
1085 } \
1086 RTPrintf("};\n"); \
1087 } \
1088} \
1089\
1090static void ShiftDblU ## a_cBits ## Test(void) \
1091{ \
1092 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aShiftDblU ## a_cBits); iFn++) \
1093 { \
1094 RTTestSub(g_hTest, g_aShiftDblU ## a_cBits[iFn].pszName); \
1095 BINU ## a_cBits ## _TEST_T const * const paTests = g_aShiftDblU ## a_cBits[iFn].paTests; \
1096 uint32_t const cTests = g_aShiftDblU ## a_cBits[iFn].cTests; \
1097 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1098 { \
1099 uint32_t fEfl = paTests[iTest].fEflIn; \
1100 a_Type uDst = paTests[iTest].uDstIn; \
1101 g_aShiftDblU ## a_cBits[iFn].pfn(&uDst, paTests[iTest].uSrcIn, paTests[iTest].uMisc, &fEfl); \
1102 if ( uDst != paTests[iTest].uDstOut \
1103 || (fEfl /*| X86_EFL_AF*/) != (paTests[iTest].fEflOut /*| X86_EFL_AF*/)) \
1104 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=" a_Fmt " src=" a_Fmt " shift=%-2u -> efl=%#08x dst=" a_Fmt ", expected %#08x & " a_Fmt "%s\n", \
1105 iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn, (unsigned)paTests[iTest].uMisc, \
1106 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut, \
1107 EFlagsDiff(fEfl /*| X86_EFL_AF*/, paTests[iTest].fEflOut /*| X86_EFL_AF*/)); \
1108 else \
1109 { \
1110 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
1111 *g_pfEfl = paTests[iTest].fEflIn; \
1112 g_aShiftDblU ## a_cBits[iFn].pfn(g_pu ## a_cBits, paTests[iTest].uSrcIn, paTests[iTest].uMisc, g_pfEfl); \
1113 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDstOut); \
1114 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut); \
1115 } \
1116 } \
1117 } \
1118}
1119TEST_SHIFT_DBL(16, uint16_t, "%#06RX16")
1120TEST_SHIFT_DBL(32, uint32_t, "%#010RX32")
1121TEST_SHIFT_DBL(64, uint64_t, "%#018RX64")
1122
1123static void ShiftDblGenerate(uint32_t cTests)
1124{
1125 RTPrintf("\n\n#define HAVE_SHIFT_DBL_TESTS\n");
1126 ShiftDblU16Generate(cTests);
1127 ShiftDblU32Generate(cTests);
1128 ShiftDblU64Generate(cTests);
1129}
1130
1131static void ShiftDblTest(void)
1132{
1133 ShiftDblU16Test();
1134 ShiftDblU32Test();
1135 ShiftDblU64Test();
1136}
1137
1138
1139/*
1140 * Unary operators.
1141 *
1142 * Note! We use BINUxx_TEST_T ignoreing uSrcIn and uMisc.
1143 */
1144
1145#ifndef HAVE_UNARY_TESTS
1146# define DUMMY_UNARY_TESTS(a_cBits, a_Type) \
1147 static const a_Type g_aTests_inc_u ## a_cBits[] = { {0} }; \
1148 static const a_Type g_aTests_inc_u ## a_cBits ## _locked[] = { {0} }; \
1149 static const a_Type g_aTests_dec_u ## a_cBits[] = { {0} }; \
1150 static const a_Type g_aTests_dec_u ## a_cBits ## _locked[] = { {0} }; \
1151 static const a_Type g_aTests_not_u ## a_cBits[] = { {0} }; \
1152 static const a_Type g_aTests_not_u ## a_cBits ## _locked[] = { {0} }; \
1153 static const a_Type g_aTests_neg_u ## a_cBits[] = { {0} }; \
1154 static const a_Type g_aTests_neg_u ## a_cBits ## _locked[] = { {0} }
1155DUMMY_UNARY_TESTS(8, BINU8_TEST_T);
1156DUMMY_UNARY_TESTS(16, BINU16_TEST_T);
1157DUMMY_UNARY_TESTS(32, BINU32_TEST_T);
1158DUMMY_UNARY_TESTS(64, BINU64_TEST_T);
1159#endif
1160
1161#define TEST_UNARY(a_cBits, a_Type, a_Fmt, a_TestType) \
1162static const struct \
1163{ \
1164 const char *pszName; \
1165 PFNIEMAIMPLUNARYU ## a_cBits pfn; \
1166 a_TestType const *paTests; \
1167 uint32_t cTests, uExtra; \
1168} g_aUnaryU ## a_cBits [] = \
1169{ \
1170 ENTRY(inc_u ## a_cBits), \
1171 ENTRY(inc_u ## a_cBits ## _locked), \
1172 ENTRY(dec_u ## a_cBits), \
1173 ENTRY(dec_u ## a_cBits ## _locked), \
1174 ENTRY(not_u ## a_cBits), \
1175 ENTRY(not_u ## a_cBits ## _locked), \
1176 ENTRY(neg_u ## a_cBits), \
1177 ENTRY(neg_u ## a_cBits ## _locked), \
1178}; \
1179\
1180static void UnaryU ## a_cBits ## Generate(uint32_t cTests) \
1181{ \
1182 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aUnaryU ## a_cBits); iFn++) \
1183 { \
1184 RTPrintf("static const BINU" #a_cBits "_TEST_T g_aTests_%s[] =\n{\n", g_aUnaryU ## a_cBits[iFn].pszName); \
1185 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1186 { \
1187 a_TestType Test; \
1188 Test.fEflIn = RandEFlags(); \
1189 Test.fEflOut = Test.fEflIn; \
1190 Test.uDstIn = RandU ## a_cBits(); \
1191 Test.uDstOut = Test.uDstIn; \
1192 Test.uSrcIn = 0; \
1193 Test.uMisc = 0; \
1194 g_aUnaryU ## a_cBits[iFn].pfn(&Test.uDstOut, &Test.fEflOut); \
1195 RTPrintf(" { %#08x, %#08x, " a_Fmt ", " a_Fmt ", 0, 0 }, /* #%u */\n", \
1196 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, iTest); \
1197 } \
1198 RTPrintf("};\n"); \
1199 } \
1200} \
1201\
1202static void UnaryU ## a_cBits ## Test(void) \
1203{ \
1204 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aUnaryU ## a_cBits); iFn++) \
1205 { \
1206 RTTestSub(g_hTest, g_aUnaryU ## a_cBits[iFn].pszName); \
1207 a_TestType const * const paTests = g_aUnaryU ## a_cBits[iFn].paTests; \
1208 uint32_t const cTests = g_aUnaryU ## a_cBits[iFn].cTests; \
1209 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1210 { \
1211 uint32_t fEfl = paTests[iTest].fEflIn; \
1212 a_Type uDst = paTests[iTest].uDstIn; \
1213 g_aUnaryU ## a_cBits[iFn].pfn(&uDst, &fEfl); \
1214 if ( uDst != paTests[iTest].uDstOut \
1215 || fEfl != paTests[iTest].fEflOut) \
1216 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=" a_Fmt " -> efl=%#08x dst=" a_Fmt ", expected %#08x & " a_Fmt "%s\n", \
1217 iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, \
1218 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut, \
1219 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
1220 else \
1221 { \
1222 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
1223 *g_pfEfl = paTests[iTest].fEflIn; \
1224 g_aUnaryU ## a_cBits[iFn].pfn(g_pu ## a_cBits, g_pfEfl); \
1225 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDstOut); \
1226 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut); \
1227 } \
1228 } \
1229 } \
1230}
1231TEST_UNARY(8, uint8_t, "%#04RX8", BINU8_TEST_T)
1232TEST_UNARY(16, uint16_t, "%#06RX16", BINU16_TEST_T)
1233TEST_UNARY(32, uint32_t, "%#010RX32", BINU32_TEST_T)
1234TEST_UNARY(64, uint64_t, "%#018RX64", BINU64_TEST_T)
1235
1236static void UnaryGenerate(uint32_t cTests)
1237{
1238 RTPrintf("\n\n#define HAVE_UNARY_TESTS\n");
1239 UnaryU8Generate(cTests);
1240 UnaryU16Generate(cTests);
1241 UnaryU32Generate(cTests);
1242 UnaryU64Generate(cTests);
1243}
1244
1245static void UnaryTest(void)
1246{
1247 UnaryU8Test();
1248 UnaryU16Test();
1249 UnaryU32Test();
1250 UnaryU64Test();
1251}
1252
1253
1254/*
1255 * Shifts.
1256 *
1257 * Note! We use BINUxx_TEST_T with the shift count in uMisc and uSrcIn unused.
1258 */
1259
1260#ifndef HAVE_SHIFT_TESTS
1261# define DUMMY_SHIFT_TESTS(a_cBits, a_Type) \
1262 static const a_Type g_aTests_rol_u ## a_cBits[] = { {0} }; \
1263 static const a_Type g_aTests_ror_u ## a_cBits[] = { {0} }; \
1264 static const a_Type g_aTests_rcl_u ## a_cBits[] = { {0} }; \
1265 static const a_Type g_aTests_rcr_u ## a_cBits[] = { {0} }; \
1266 static const a_Type g_aTests_shl_u ## a_cBits[] = { {0} }; \
1267 static const a_Type g_aTests_shr_u ## a_cBits[] = { {0} }; \
1268 static const a_Type g_aTests_sar_u ## a_cBits[] = { {0} }
1269DUMMY_SHIFT_TESTS(8, BINU8_TEST_T);
1270DUMMY_SHIFT_TESTS(16, BINU16_TEST_T);
1271DUMMY_SHIFT_TESTS(32, BINU32_TEST_T);
1272DUMMY_SHIFT_TESTS(64, BINU64_TEST_T);
1273#endif
1274
1275#define TEST_SHIFT(a_cBits, a_Type, a_Fmt, a_TestType) \
1276static const struct \
1277{ \
1278 const char *pszName; \
1279 PFNIEMAIMPLSHIFTU ## a_cBits pfn; \
1280 a_TestType const *paTests; \
1281 uint32_t cTests, uExtra; \
1282} g_aShiftU ## a_cBits [] = \
1283{ \
1284 ENTRY(rol_u ## a_cBits), \
1285 ENTRY(ror_u ## a_cBits), \
1286 ENTRY(rcl_u ## a_cBits), \
1287 ENTRY(rcr_u ## a_cBits), \
1288 ENTRY(shl_u ## a_cBits), \
1289 ENTRY(shr_u ## a_cBits), \
1290 ENTRY(sar_u ## a_cBits), \
1291}; \
1292\
1293static void ShiftU ## a_cBits ## Generate(uint32_t cTests) \
1294{ \
1295 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aShiftU ## a_cBits); iFn++) \
1296 { \
1297 RTPrintf("static const BINU" #a_cBits "_TEST_T g_aTests_%s[] =\n{\n", g_aShiftU ## a_cBits[iFn].pszName); \
1298 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1299 { \
1300 a_TestType Test; \
1301 Test.fEflIn = RandEFlags(); \
1302 Test.fEflOut = Test.fEflIn; \
1303 Test.uDstIn = RandU ## a_cBits(); \
1304 Test.uDstOut = Test.uDstIn; \
1305 Test.uSrcIn = 0; \
1306 Test.uMisc = RandU8() & (a_cBits - 1); \
1307 g_aShiftU ## a_cBits[iFn].pfn(&Test.uDstOut, Test.uMisc, &Test.fEflOut); \
1308 RTPrintf(" { %#08x, %#08x, " a_Fmt ", " a_Fmt ", 0, %-2u }, /* #%u */\n", \
1309 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uMisc, iTest); \
1310 } \
1311 RTPrintf("};\n"); \
1312 } \
1313} \
1314\
1315static void ShiftU ## a_cBits ## Test(void) \
1316{ \
1317 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aShiftU ## a_cBits); iFn++) \
1318 { \
1319 RTTestSub(g_hTest, g_aShiftU ## a_cBits[iFn].pszName); \
1320 a_TestType const * const paTests = g_aShiftU ## a_cBits[iFn].paTests; \
1321 uint32_t const cTests = g_aShiftU ## a_cBits[iFn].cTests; \
1322 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1323 { \
1324 uint32_t fEfl = paTests[iTest].fEflIn; \
1325 a_Type uDst = paTests[iTest].uDstIn; \
1326 g_aShiftU ## a_cBits[iFn].pfn(&uDst, paTests[iTest].uMisc, &fEfl); \
1327 if ( uDst != paTests[iTest].uDstOut \
1328 || fEfl != paTests[iTest].fEflOut) \
1329 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=" a_Fmt " shift=%2u -> efl=%#08x dst=" a_Fmt ", expected %#08x & " a_Fmt "%s\n", \
1330 iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uMisc, \
1331 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut, \
1332 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
1333 else \
1334 { \
1335 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
1336 *g_pfEfl = paTests[iTest].fEflIn; \
1337 g_aShiftU ## a_cBits[iFn].pfn(g_pu ## a_cBits, paTests[iTest].uMisc, g_pfEfl); \
1338 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDstOut); \
1339 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut); \
1340 } \
1341 } \
1342 } \
1343}
1344TEST_SHIFT(8, uint8_t, "%#04RX8", BINU8_TEST_T)
1345TEST_SHIFT(16, uint16_t, "%#06RX16", BINU16_TEST_T)
1346TEST_SHIFT(32, uint32_t, "%#010RX32", BINU32_TEST_T)
1347TEST_SHIFT(64, uint64_t, "%#018RX64", BINU64_TEST_T)
1348
1349static void ShiftGenerate(uint32_t cTests)
1350{
1351 RTPrintf("\n\n#define HAVE_SHIFT_TESTS\n");
1352 ShiftU8Generate(cTests);
1353 ShiftU16Generate(cTests);
1354 ShiftU32Generate(cTests);
1355 ShiftU64Generate(cTests);
1356}
1357
1358static void ShiftTest(void)
1359{
1360 ShiftU8Test();
1361 ShiftU16Test();
1362 ShiftU32Test();
1363 ShiftU64Test();
1364}
1365
1366
1367/*
1368 * Multiplication and division.
1369 *
1370 * Note! The 8-bit functions has a different format, so we need to duplicate things.
1371 * Note! Currently ignoring undefined bits.
1372 */
1373
1374#ifndef HAVE_MULDIV_TESTS
1375# define DUMMY_MULDIV_TESTS(a_cBits, a_Type) \
1376 static const a_Type g_aTests_mul_u ## a_cBits[] = { {0} }; \
1377 static const a_Type g_aTests_imul_u ## a_cBits[] = { {0} }; \
1378 static const a_Type g_aTests_div_u ## a_cBits[] = { {0} }; \
1379 static const a_Type g_aTests_idiv_u ## a_cBits[] = { {0} }
1380DUMMY_MULDIV_TESTS(8, MULDIVU8_TEST_T);
1381DUMMY_MULDIV_TESTS(16, MULDIVU16_TEST_T);
1382DUMMY_MULDIV_TESTS(32, MULDIVU32_TEST_T);
1383DUMMY_MULDIV_TESTS(64, MULDIVU64_TEST_T);
1384#endif
1385
1386/* U8 */
1387static const struct
1388{
1389 const char *pszName;
1390 PFNIEMAIMPLMULDIVU8 pfn;
1391 MULDIVU8_TEST_T const *paTests;
1392 uint32_t cTests, uExtra;
1393} g_aMulDivU8[] =
1394{
1395 ENTRY_EX(mul_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF),
1396 ENTRY_EX(imul_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF),
1397 ENTRY_EX(div_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF),
1398 ENTRY_EX(idiv_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF),
1399};
1400
1401static void MulDivU8Generate(uint32_t cTests)
1402{
1403 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aMulDivU8); iFn++)
1404 {
1405 RTPrintf("static const MULDIVU8_TEST_T g_aTests_%s[] =\n{\n", g_aMulDivU8[iFn].pszName);
1406 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
1407 {
1408 MULDIVU8_TEST_T Test;
1409 Test.fEflIn = RandEFlags();
1410 Test.fEflOut = Test.fEflIn;
1411 Test.uDstIn = RandU16();
1412 Test.uDstOut = Test.uDstIn;
1413 Test.uSrcIn = RandU8();
1414 Test.rc = g_aMulDivU8[iFn].pfn(&Test.uDstOut, Test.uSrcIn, &Test.fEflOut);
1415 RTPrintf(" { %#08x, %#08x, %#06RX16, %#06RX16, %#04RX8, %d }, /* #%u */\n",
1416 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uSrcIn, Test.rc, iTest);
1417 }
1418 RTPrintf("};\n");
1419 }
1420}
1421
1422static void MulDivU8Test(void)
1423{
1424 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aMulDivU8); iFn++)
1425 {
1426 RTTestSub(g_hTest, g_aMulDivU8[iFn].pszName);
1427 MULDIVU8_TEST_T const * const paTests = g_aMulDivU8[iFn].paTests;
1428 uint32_t const cTests = g_aMulDivU8[iFn].cTests;
1429 uint32_t const fEflIgn = g_aMulDivU8[iFn].uExtra;
1430 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
1431 {
1432 uint32_t fEfl = paTests[iTest].fEflIn;
1433 uint16_t uDst = paTests[iTest].uDstIn;
1434 int rc = g_aMulDivU8[iFn].pfn(&uDst, paTests[iTest].uSrcIn, &fEfl);
1435 if ( uDst != paTests[iTest].uDstOut
1436 || (fEfl | fEflIgn) != (paTests[iTest].fEflOut | fEflIgn)
1437 || rc != paTests[iTest].rc)
1438 RTTestFailed(g_hTest, "#%02u: efl=%#08x dst=%#06RX16 src=%#04RX8\n"
1439 " -> efl=%#08x dst=%#06RX16 rc=%d\n"
1440 "expected %#08x %#06RX16 %d%s\n",
1441 iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn,
1442 fEfl, uDst, rc, paTests[iTest].fEflOut, paTests[iTest].uDstOut, paTests[iTest].rc,
1443 EFlagsDiff(fEfl | fEflIgn, paTests[iTest].fEflOut | fEflIgn));
1444 else
1445 {
1446 *g_pu16 = paTests[iTest].uDstIn;
1447 *g_pfEfl = paTests[iTest].fEflIn;
1448 rc = g_aMulDivU8[iFn].pfn(g_pu16, paTests[iTest].uSrcIn, g_pfEfl);
1449 RTTEST_CHECK(g_hTest, *g_pu16 == paTests[iTest].uDstOut);
1450 RTTEST_CHECK(g_hTest, (*g_pfEfl | fEflIgn) == (paTests[iTest].fEflOut | fEflIgn));
1451 RTTEST_CHECK(g_hTest, rc == paTests[iTest].rc);
1452 }
1453 }
1454 }
1455}
1456
1457#define TEST_MULDIV(a_cBits, a_Type, a_Fmt, a_TestType) \
1458static const struct \
1459{ \
1460 const char *pszName; \
1461 PFNIEMAIMPLMULDIVU ## a_cBits pfn; \
1462 a_TestType const *paTests; \
1463 uint32_t cTests, uExtra; \
1464} g_aMulDivU ## a_cBits [] = \
1465{ \
1466 ENTRY_EX(mul_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF), \
1467 ENTRY_EX(imul_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF), \
1468 ENTRY_EX(div_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF), \
1469 ENTRY_EX(idiv_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF), \
1470}; \
1471\
1472static void MulDivU ## a_cBits ## Generate(uint32_t cTests) \
1473{ \
1474 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aMulDivU ## a_cBits); iFn++) \
1475 { \
1476 RTPrintf("static const MULDIVU" #a_cBits "_TEST_T g_aTests_%s[] =\n{\n", g_aMulDivU ## a_cBits[iFn].pszName); \
1477 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1478 { \
1479 a_TestType Test; \
1480 Test.fEflIn = RandEFlags(); \
1481 Test.fEflOut = Test.fEflIn; \
1482 Test.uDst1In = RandU ## a_cBits(); \
1483 Test.uDst1Out = Test.uDst1In; \
1484 Test.uDst2In = RandU ## a_cBits(); \
1485 Test.uDst2Out = Test.uDst2In; \
1486 Test.uSrcIn = RandU ## a_cBits(); \
1487 Test.rc = g_aMulDivU ## a_cBits[iFn].pfn(&Test.uDst1Out, &Test.uDst2Out, Test.uSrcIn, &Test.fEflOut); \
1488 RTPrintf(" { %#08x, %#08x, " a_Fmt ", " a_Fmt ", " a_Fmt ", " a_Fmt ", " a_Fmt ", %d }, /* #%u */\n", \
1489 Test.fEflIn, Test.fEflOut, Test.uDst1In, Test.uDst1Out, Test.uDst2In, Test.uDst2Out, Test.uSrcIn, \
1490 Test.rc, iTest); \
1491 } \
1492 RTPrintf("};\n"); \
1493 } \
1494} \
1495\
1496static void MulDivU ## a_cBits ## Test(void) \
1497{ \
1498 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aMulDivU ## a_cBits); iFn++) \
1499 { \
1500 RTTestSub(g_hTest, g_aMulDivU ## a_cBits[iFn].pszName); \
1501 a_TestType const * const paTests = g_aMulDivU ## a_cBits[iFn].paTests; \
1502 uint32_t const cTests = g_aMulDivU ## a_cBits[iFn].cTests; \
1503 uint32_t const fEflIgn = g_aMulDivU ## a_cBits[iFn].uExtra; \
1504 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1505 { \
1506 uint32_t fEfl = paTests[iTest].fEflIn; \
1507 a_Type uDst1 = paTests[iTest].uDst1In; \
1508 a_Type uDst2 = paTests[iTest].uDst2In; \
1509 int rc = g_aMulDivU ## a_cBits[iFn].pfn(&uDst1, &uDst2, paTests[iTest].uSrcIn, &fEfl); \
1510 if ( uDst1 != paTests[iTest].uDst1Out \
1511 || uDst2 != paTests[iTest].uDst2Out \
1512 || (fEfl | fEflIgn) != (paTests[iTest].fEflOut | fEflIgn)\
1513 || rc != paTests[iTest].rc) \
1514 RTTestFailed(g_hTest, "#%02u: efl=%#08x dst1=" a_Fmt " dst2=" a_Fmt " src=" a_Fmt "\n" \
1515 " -> efl=%#08x dst1=" a_Fmt " dst2=" a_Fmt " rc=%d\n" \
1516 "expected %#08x " a_Fmt " " a_Fmt " %d%s -%s%s%s\n", \
1517 iTest, paTests[iTest].fEflIn, paTests[iTest].uDst1In, paTests[iTest].uDst2In, paTests[iTest].uSrcIn, \
1518 fEfl, uDst1, uDst2, rc, \
1519 paTests[iTest].fEflOut, paTests[iTest].uDst1Out, paTests[iTest].uDst2Out, paTests[iTest].rc, \
1520 EFlagsDiff(fEfl | fEflIgn, paTests[iTest].fEflOut | fEflIgn), \
1521 uDst1 != paTests[iTest].uDst1Out ? " dst1" : "", uDst2 != paTests[iTest].uDst2Out ? " dst2" : "", \
1522 (fEfl | fEflIgn) != (paTests[iTest].fEflOut | fEflIgn) ? " eflags" : ""); \
1523 else \
1524 { \
1525 *g_pu ## a_cBits = paTests[iTest].uDst1In; \
1526 *g_pu ## a_cBits ## Two = paTests[iTest].uDst2In; \
1527 *g_pfEfl = paTests[iTest].fEflIn; \
1528 rc = g_aMulDivU ## a_cBits[iFn].pfn(g_pu ## a_cBits, g_pu ## a_cBits ## Two, paTests[iTest].uSrcIn, g_pfEfl); \
1529 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDst1Out); \
1530 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits ## Two == paTests[iTest].uDst2Out); \
1531 RTTEST_CHECK(g_hTest, (*g_pfEfl | fEflIgn) == (paTests[iTest].fEflOut | fEflIgn)); \
1532 RTTEST_CHECK(g_hTest, rc == paTests[iTest].rc); \
1533 } \
1534 } \
1535 } \
1536}
1537TEST_MULDIV(16, uint16_t, "%#06RX16", MULDIVU16_TEST_T)
1538TEST_MULDIV(32, uint32_t, "%#010RX32", MULDIVU32_TEST_T)
1539TEST_MULDIV(64, uint64_t, "%#018RX64", MULDIVU64_TEST_T)
1540
1541static void MulDivGenerate(uint32_t cTests)
1542{
1543 RTPrintf("\n\n#define HAVE_MULDIV_TESTS\n");
1544 MulDivU8Generate(cTests);
1545 MulDivU16Generate(cTests);
1546 MulDivU32Generate(cTests);
1547 MulDivU64Generate(cTests);
1548}
1549
1550static void MulDivTest(void)
1551{
1552 MulDivU8Test();
1553 MulDivU16Test();
1554 MulDivU32Test();
1555 MulDivU64Test();
1556}
1557
1558
1559/*
1560 * BSWAP
1561 */
1562static void BswapTest(void)
1563{
1564 RTTestSub(g_hTest, "bswap_u16");
1565 *g_pu32 = UINT32_C(0x12345678);
1566 iemAImpl_bswap_u16(g_pu32);
1567#if 0
1568 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0x12347856), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
1569#else
1570 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0x12340000), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
1571#endif
1572 *g_pu32 = UINT32_C(0xffff1122);
1573 iemAImpl_bswap_u16(g_pu32);
1574#if 0
1575 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0xffff2211), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
1576#else
1577 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0xffff0000), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
1578#endif
1579
1580 RTTestSub(g_hTest, "bswap_u32");
1581 *g_pu32 = UINT32_C(0x12345678);
1582 iemAImpl_bswap_u32(g_pu32);
1583 RTTEST_CHECK(g_hTest, *g_pu32 == UINT32_C(0x78563412));
1584
1585 RTTestSub(g_hTest, "bswap_u64");
1586 *g_pu64 = UINT64_C(0x0123456789abcdef);
1587 iemAImpl_bswap_u64(g_pu64);
1588 RTTEST_CHECK(g_hTest, *g_pu64 == UINT64_C(0xefcdab8967452301));
1589}
1590
1591
1592/*
1593 * Random helpers.
1594 */
1595
1596static uint32_t RandEFlags(void)
1597{
1598 uint32_t fEfl = RTRandU32();
1599 return (fEfl & X86_EFL_LIVE_MASK) | X86_EFL_RA1_MASK;
1600}
1601
1602static uint8_t RandU8(void)
1603{
1604 return RTRandU32Ex(0, 0xff);
1605}
1606
1607
1608static uint16_t RandU16(void)
1609{
1610 return RTRandU32Ex(0, 0xffff);
1611}
1612
1613
1614static uint32_t RandU32(void)
1615{
1616 return RTRandU32();
1617}
1618
1619
1620static uint64_t RandU64(void)
1621{
1622 return RTRandU64();
1623}
1624
1625
1626static RTUINT128U RandU128(void)
1627{
1628 RTUINT128U Ret;
1629 Ret.s.Hi = RTRandU64();
1630 Ret.s.Lo = RTRandU64();
1631 return Ret;
1632}
1633
1634
1635int main(int argc, char **argv)
1636{
1637 int rc = RTR3InitExe(argc, &argv, 0);
1638 if (RT_FAILURE(rc))
1639 return RTMsgInitFailure(rc);
1640
1641 /*
1642 * Generate data?
1643 */
1644 if (argc > 2)
1645 {
1646 char szCpuDesc[256] = {0};
1647 RTMpGetDescription(NIL_RTCPUID, szCpuDesc, sizeof(szCpuDesc));
1648
1649 RTPrintf("/* $Id: tstIEMAImpl.cpp 93893 2022-02-22 21:27:58Z vboxsync $ */\n"
1650 "/** @file\n"
1651 " * IEM Assembly Instruction Helper Testcase Data - %s.\n"
1652 " */\n"
1653 "\n"
1654 "/*\n"
1655 " * Copyright (C) 2022 Oracle Corporation\n"
1656 " *\n"
1657 " * This file is part of VirtualBox Open Source Edition (OSE), as\n"
1658 " * available from http://www.virtualbox.org. This file is free software;\n"
1659 " * you can redistribute it and/or modify it under the terms of the GNU\n"
1660 " * General Public License (GPL) as published by the Free Software\n"
1661 " * Foundation, in version 2 as it comes in the \"COPYING\" file of the\n"
1662 " * VirtualBox OSE distribution. VirtualBox OSE is distributed in the\n"
1663 " * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.\n"
1664 " */\n"
1665 "\n"
1666 , szCpuDesc);
1667 uint32_t cTests = 64;
1668 BinU8Generate(cTests);
1669 BinU16Generate(cTests);
1670 BinU32Generate(cTests);
1671 BinU64Generate(cTests);
1672 ShiftDblGenerate(cTests);
1673 UnaryGenerate(cTests);
1674 ShiftGenerate(cTests);
1675 MulDivGenerate(cTests);
1676 return RTEXITCODE_SUCCESS;
1677 }
1678
1679 /*
1680 * Do testing. Currrently disabled by default as data needs to be checked
1681 * on both intel and AMD systems first.
1682 */
1683 rc = RTTestCreate("tstIEMAimpl", &g_hTest);
1684 AssertRCReturn(rc, RTEXITCODE_FAILURE);
1685 if (argc > 1)
1686 {
1687 /* Allocate guarded memory for use in the tests. */
1688#define ALLOC_GUARDED_VAR(a_puVar) do { \
1689 rc = RTTestGuardedAlloc(g_hTest, sizeof(*a_puVar), sizeof(*a_puVar), false /*fHead*/, (void **)&a_puVar); \
1690 if (RT_FAILURE(rc)) RTTestFailed(g_hTest, "Failed to allocate guarded mem: " #a_puVar); \
1691 } while (0)
1692 ALLOC_GUARDED_VAR(g_pu8);
1693 ALLOC_GUARDED_VAR(g_pu16);
1694 ALLOC_GUARDED_VAR(g_pu32);
1695 ALLOC_GUARDED_VAR(g_pu64);
1696 ALLOC_GUARDED_VAR(g_pu128);
1697 ALLOC_GUARDED_VAR(g_pu8Two);
1698 ALLOC_GUARDED_VAR(g_pu16Two);
1699 ALLOC_GUARDED_VAR(g_pu32Two);
1700 ALLOC_GUARDED_VAR(g_pu64Two);
1701 ALLOC_GUARDED_VAR(g_pu128Two);
1702 ALLOC_GUARDED_VAR(g_pfEfl);
1703 if (RTTestErrorCount(g_hTest) == 0)
1704 {
1705 BinU8Test();
1706 BinU16Test();
1707 BinU32Test();
1708 BinU64Test();
1709 XchgTest();
1710 XaddTest();
1711 CmpXchgTest();
1712 CmpXchg8bTest();
1713 CmpXchg16bTest();
1714 ShiftDblTest();
1715 UnaryTest();
1716 ShiftTest();
1717 MulDivTest();
1718 BswapTest();
1719 }
1720 return RTTestSummaryAndDestroy(g_hTest);
1721 }
1722 return RTTestSkipAndDestroy(g_hTest, "unfinished testcase");
1723}
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