VirtualBox

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

Last change on this file since 101298 was 100840, checked in by vboxsync, 18 months ago

VMM/IEM: More conversion from IEM_MC_MEM_MAP to IEM_MC_MEM_MAP_XXX. Correct 32-bit size BT instruction to not clear high bits. bugref:10369

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 460.6 KB
Line 
1/* $Id: tstIEMAImpl.cpp 100840 2023-08-09 17:52:37Z vboxsync $ */
2/** @file
3 * IEM Assembly Instruction Helper Testcase.
4 */
5
6/*
7 * Copyright (C) 2022-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include "../include/IEMInternal.h"
33
34#include <iprt/errcore.h>
35#include <VBox/log.h>
36#include <iprt/assert.h>
37#include <iprt/ctype.h>
38#include <iprt/getopt.h>
39#include <iprt/initterm.h>
40#include <iprt/message.h>
41#include <iprt/mp.h>
42#include <iprt/rand.h>
43#include <iprt/stream.h>
44#include <iprt/string.h>
45#include <iprt/test.h>
46#include <VBox/version.h>
47
48#include "tstIEMAImpl.h"
49
50
51/*********************************************************************************************************************************
52* Defined Constants And Macros *
53*********************************************************************************************************************************/
54#define ENTRY(a_Name) ENTRY_EX(a_Name, 0)
55#define ENTRY_EX(a_Name, a_uExtra) \
56 { RT_XSTR(a_Name), iemAImpl_ ## a_Name, NULL, \
57 g_aTests_ ## a_Name, &g_cTests_ ## a_Name, \
58 a_uExtra, IEMTARGETCPU_EFL_BEHAVIOR_NATIVE /* means same for all here */ }
59
60#define ENTRY_PFN_CAST(a_Name, a_pfnType) ENTRY_PFN_CAST_EX(a_Name, a_pfnType, 0)
61#define ENTRY_PFN_CAST_EX(a_Name, a_pfnType, a_uExtra) \
62 { RT_XSTR(a_Name), (a_pfnType)iemAImpl_ ## a_Name, NULL, \
63 g_aTests_ ## a_Name, &g_cTests_ ## a_Name, \
64 a_uExtra, IEMTARGETCPU_EFL_BEHAVIOR_NATIVE /* means same for all here */ }
65
66#define ENTRY_BIN(a_Name) ENTRY_EX_BIN(a_Name, 0)
67#define ENTRY_EX_BIN(a_Name, a_uExtra) \
68 { RT_XSTR(a_Name), iemAImpl_ ## a_Name, NULL, \
69 g_aTests_ ## a_Name, &g_cbTests_ ## a_Name, \
70 a_uExtra, IEMTARGETCPU_EFL_BEHAVIOR_NATIVE /* means same for all here */ }
71
72#define ENTRY_BIN_AVX(a_Name) ENTRY_BIN_AVX_EX(a_Name, 0)
73#ifndef IEM_WITHOUT_ASSEMBLY
74# define ENTRY_BIN_AVX_EX(a_Name, a_uExtra) \
75 { RT_XSTR(a_Name), iemAImpl_ ## a_Name, NULL, \
76 g_aTests_ ## a_Name, &g_cbTests_ ## a_Name, \
77 a_uExtra, IEMTARGETCPU_EFL_BEHAVIOR_NATIVE /* means same for all here */ }
78#else
79# define ENTRY_BIN_AVX_EX(a_Name, a_uExtra) \
80 { RT_XSTR(a_Name), iemAImpl_ ## a_Name ## _fallback, NULL, \
81 g_aTests_ ## a_Name, &g_cbTests_ ## a_Name, \
82 a_uExtra, IEMTARGETCPU_EFL_BEHAVIOR_NATIVE /* means same for all here */ }
83#endif
84
85#define ENTRY_BIN_SSE_OPT(a_Name) ENTRY_BIN_SSE_OPT_EX(a_Name, 0)
86#ifndef IEM_WITHOUT_ASSEMBLY
87# define ENTRY_BIN_SSE_OPT_EX(a_Name, a_uExtra) \
88 { RT_XSTR(a_Name), iemAImpl_ ## a_Name, NULL, \
89 g_aTests_ ## a_Name, &g_cbTests_ ## a_Name, \
90 a_uExtra, IEMTARGETCPU_EFL_BEHAVIOR_NATIVE /* means same for all here */ }
91#else
92# define ENTRY_BIN_SSE_OPT_EX(a_Name, a_uExtra) \
93 { RT_XSTR(a_Name), iemAImpl_ ## a_Name ## _fallback, NULL, \
94 g_aTests_ ## a_Name, &g_cbTests_ ## a_Name, \
95 a_uExtra, IEMTARGETCPU_EFL_BEHAVIOR_NATIVE /* means same for all here */ }
96#endif
97
98
99#define ENTRY_INTEL(a_Name, a_fEflUndef) ENTRY_INTEL_EX(a_Name, a_fEflUndef, 0)
100#define ENTRY_INTEL_EX(a_Name, a_fEflUndef, a_uExtra) \
101 { RT_XSTR(a_Name) "_intel", iemAImpl_ ## a_Name ## _intel, iemAImpl_ ## a_Name, \
102 g_aTests_ ## a_Name ## _intel, &g_cTests_ ## a_Name ## _intel, \
103 a_uExtra, IEMTARGETCPU_EFL_BEHAVIOR_INTEL }
104
105#define ENTRY_AMD(a_Name, a_fEflUndef) ENTRY_AMD_EX(a_Name, a_fEflUndef, 0)
106#define ENTRY_AMD_EX(a_Name, a_fEflUndef, a_uExtra) \
107 { RT_XSTR(a_Name) "_amd", iemAImpl_ ## a_Name ## _amd, iemAImpl_ ## a_Name, \
108 g_aTests_ ## a_Name ## _amd, &g_cTests_ ## a_Name ## _amd, \
109 a_uExtra, IEMTARGETCPU_EFL_BEHAVIOR_AMD }
110
111#define TYPEDEF_SUBTEST_TYPE(a_TypeName, a_TestType, a_FunctionPtrType) \
112 typedef struct a_TypeName \
113 { \
114 const char *pszName; \
115 a_FunctionPtrType pfn; \
116 a_FunctionPtrType pfnNative; \
117 a_TestType const *paTests; \
118 uint32_t const *pcTests; \
119 uint32_t uExtra; \
120 uint8_t idxCpuEflFlavour; \
121 } a_TypeName
122
123#define COUNT_VARIATIONS(a_SubTest) \
124 (1 + ((a_SubTest).idxCpuEflFlavour == g_idxCpuEflFlavour && (a_SubTest).pfnNative) )
125
126
127/*********************************************************************************************************************************
128* Global Variables *
129*********************************************************************************************************************************/
130static RTTEST g_hTest;
131static uint8_t g_idxCpuEflFlavour = IEMTARGETCPU_EFL_BEHAVIOR_INTEL;
132#ifdef TSTIEMAIMPL_WITH_GENERATOR
133static uint32_t g_cZeroDstTests = 2;
134static uint32_t g_cZeroSrcTests = 4;
135#endif
136static uint8_t *g_pu8, *g_pu8Two;
137static uint16_t *g_pu16, *g_pu16Two;
138static uint32_t *g_pu32, *g_pu32Two, *g_pfEfl;
139static uint64_t *g_pu64, *g_pu64Two;
140static RTUINT128U *g_pu128, *g_pu128Two;
141
142static char g_aszBuf[32][256];
143static unsigned g_idxBuf = 0;
144
145static uint32_t g_cIncludeTestPatterns;
146static uint32_t g_cExcludeTestPatterns;
147static const char *g_apszIncludeTestPatterns[64];
148static const char *g_apszExcludeTestPatterns[64];
149
150static unsigned g_cVerbosity = 0;
151
152
153/*********************************************************************************************************************************
154* Internal Functions *
155*********************************************************************************************************************************/
156static const char *FormatR80(PCRTFLOAT80U pr80);
157static const char *FormatR64(PCRTFLOAT64U pr64);
158static const char *FormatR32(PCRTFLOAT32U pr32);
159
160
161/*
162 * Random helpers.
163 */
164
165static uint32_t RandEFlags(void)
166{
167 uint32_t fEfl = RTRandU32();
168 return (fEfl & X86_EFL_LIVE_MASK) | X86_EFL_RA1_MASK;
169}
170
171#ifdef TSTIEMAIMPL_WITH_GENERATOR
172
173static uint8_t RandU8(void)
174{
175 return RTRandU32Ex(0, 0xff);
176}
177
178
179static uint16_t RandU16(void)
180{
181 return RTRandU32Ex(0, 0xffff);
182}
183
184
185static uint32_t RandU32(void)
186{
187 return RTRandU32();
188}
189
190#endif
191
192static uint64_t RandU64(void)
193{
194 return RTRandU64();
195}
196
197
198static RTUINT128U RandU128(void)
199{
200 RTUINT128U Ret;
201 Ret.s.Hi = RTRandU64();
202 Ret.s.Lo = RTRandU64();
203 return Ret;
204}
205
206#ifdef TSTIEMAIMPL_WITH_GENERATOR
207
208static uint8_t RandU8Dst(uint32_t iTest)
209{
210 if (iTest < g_cZeroDstTests)
211 return 0;
212 return RandU8();
213}
214
215
216static uint8_t RandU8Src(uint32_t iTest)
217{
218 if (iTest < g_cZeroSrcTests)
219 return 0;
220 return RandU8();
221}
222
223
224static uint16_t RandU16Dst(uint32_t iTest)
225{
226 if (iTest < g_cZeroDstTests)
227 return 0;
228 return RandU16();
229}
230
231
232static uint16_t RandU16Src(uint32_t iTest)
233{
234 if (iTest < g_cZeroSrcTests)
235 return 0;
236 return RandU16();
237}
238
239
240static uint32_t RandU32Dst(uint32_t iTest)
241{
242 if (iTest < g_cZeroDstTests)
243 return 0;
244 return RandU32();
245}
246
247
248static uint32_t RandU32Src(uint32_t iTest)
249{
250 if (iTest < g_cZeroSrcTests)
251 return 0;
252 return RandU32();
253}
254
255
256static uint64_t RandU64Dst(uint32_t iTest)
257{
258 if (iTest < g_cZeroDstTests)
259 return 0;
260 return RandU64();
261}
262
263
264static uint64_t RandU64Src(uint32_t iTest)
265{
266 if (iTest < g_cZeroSrcTests)
267 return 0;
268 return RandU64();
269}
270
271
272/** 2nd operand for and FPU instruction, pairing with RandR80Src1. */
273static int16_t RandI16Src2(uint32_t iTest)
274{
275 if (iTest < 18 * 4)
276 switch (iTest % 4)
277 {
278 case 0: return 0;
279 case 1: return INT16_MAX;
280 case 2: return INT16_MIN;
281 case 3: break;
282 }
283 return (int16_t)RandU16();
284}
285
286
287/** 2nd operand for and FPU instruction, pairing with RandR80Src1. */
288static int32_t RandI32Src2(uint32_t iTest)
289{
290 if (iTest < 18 * 4)
291 switch (iTest % 4)
292 {
293 case 0: return 0;
294 case 1: return INT32_MAX;
295 case 2: return INT32_MIN;
296 case 3: break;
297 }
298 return (int32_t)RandU32();
299}
300
301
302static int64_t RandI64Src(uint32_t iTest)
303{
304 RT_NOREF(iTest);
305 return (int64_t)RandU64();
306}
307
308
309static uint16_t RandFcw(void)
310{
311 return RandU16() & ~X86_FCW_ZERO_MASK;
312}
313
314
315static uint16_t RandFsw(void)
316{
317 AssertCompile((X86_FSW_C_MASK | X86_FSW_XCPT_ES_MASK | X86_FSW_TOP_MASK | X86_FSW_B) == 0xffff);
318 return RandU16();
319}
320
321
322static uint32_t RandMxcsr(void)
323{
324 return RandU32() & ~X86_MXCSR_ZERO_MASK;
325}
326
327
328static void SafeR80FractionShift(PRTFLOAT80U pr80, uint8_t cShift)
329{
330 if (pr80->sj64.uFraction >= RT_BIT_64(cShift))
331 pr80->sj64.uFraction >>= cShift;
332 else
333 pr80->sj64.uFraction = (cShift % 19) + 1;
334}
335
336
337
338static RTFLOAT80U RandR80Ex(uint8_t bType, unsigned cTarget = 80, bool fIntTarget = false)
339{
340 Assert(cTarget == (!fIntTarget ? 80U : 16U) || cTarget == 64U || cTarget == 32U || (cTarget == 59U && fIntTarget));
341
342 RTFLOAT80U r80;
343 r80.au64[0] = RandU64();
344 r80.au16[4] = RandU16();
345
346 /*
347 * Adjust the random stuff according to bType.
348 */
349 bType &= 0x1f;
350 if (bType == 0 || bType == 1 || bType == 2 || bType == 3)
351 {
352 /* Zero (0), Pseudo-Infinity (1), Infinity (2), Indefinite (3). We only keep fSign here. */
353 r80.sj64.uExponent = bType == 0 ? 0 : 0x7fff;
354 r80.sj64.uFraction = bType <= 2 ? 0 : RT_BIT_64(62);
355 r80.sj64.fInteger = bType >= 2 ? 1 : 0;
356 AssertMsg(bType != 0 || RTFLOAT80U_IS_ZERO(&r80), ("%s\n", FormatR80(&r80)));
357 AssertMsg(bType != 1 || RTFLOAT80U_IS_PSEUDO_INF(&r80), ("%s\n", FormatR80(&r80)));
358 Assert( bType != 1 || RTFLOAT80U_IS_387_INVALID(&r80));
359 AssertMsg(bType != 2 || RTFLOAT80U_IS_INF(&r80), ("%s\n", FormatR80(&r80)));
360 AssertMsg(bType != 3 || RTFLOAT80U_IS_INDEFINITE(&r80), ("%s\n", FormatR80(&r80)));
361 }
362 else if (bType == 4 || bType == 5 || bType == 6 || bType == 7)
363 {
364 /* Denormals (4,5) and Pseudo denormals (6,7) */
365 if (bType & 1)
366 SafeR80FractionShift(&r80, r80.sj64.uExponent % 62);
367 else if (r80.sj64.uFraction == 0 && bType < 6)
368 r80.sj64.uFraction = RTRandU64Ex(1, RT_BIT_64(RTFLOAT80U_FRACTION_BITS) - 1);
369 r80.sj64.uExponent = 0;
370 r80.sj64.fInteger = bType >= 6;
371 AssertMsg(bType >= 6 || RTFLOAT80U_IS_DENORMAL(&r80), ("%s bType=%#x\n", FormatR80(&r80), bType));
372 AssertMsg(bType < 6 || RTFLOAT80U_IS_PSEUDO_DENORMAL(&r80), ("%s bType=%#x\n", FormatR80(&r80), bType));
373 }
374 else if (bType == 8 || bType == 9)
375 {
376 /* Pseudo NaN. */
377 if (bType & 1)
378 SafeR80FractionShift(&r80, r80.sj64.uExponent % 62);
379 else if (r80.sj64.uFraction == 0 && !r80.sj64.fInteger)
380 r80.sj64.uFraction = RTRandU64Ex(1, RT_BIT_64(RTFLOAT80U_FRACTION_BITS) - 1);
381 r80.sj64.uExponent = 0x7fff;
382 if (r80.sj64.fInteger)
383 r80.sj64.uFraction |= RT_BIT_64(62);
384 else
385 r80.sj64.uFraction &= ~RT_BIT_64(62);
386 r80.sj64.fInteger = 0;
387 AssertMsg(RTFLOAT80U_IS_PSEUDO_NAN(&r80), ("%s bType=%#x\n", FormatR80(&r80), bType));
388 AssertMsg(RTFLOAT80U_IS_NAN(&r80), ("%s bType=%#x\n", FormatR80(&r80), bType));
389 Assert(RTFLOAT80U_IS_387_INVALID(&r80));
390 }
391 else if (bType == 10 || bType == 11 || bType == 12 || bType == 13)
392 {
393 /* Quiet and signalling NaNs. */
394 if (bType & 1)
395 SafeR80FractionShift(&r80, r80.sj64.uExponent % 62);
396 else if (r80.sj64.uFraction == 0)
397 r80.sj64.uFraction = RTRandU64Ex(1, RT_BIT_64(RTFLOAT80U_FRACTION_BITS) - 1);
398 r80.sj64.uExponent = 0x7fff;
399 if (bType < 12)
400 r80.sj64.uFraction |= RT_BIT_64(62); /* quiet */
401 else
402 r80.sj64.uFraction &= ~RT_BIT_64(62); /* signaling */
403 r80.sj64.fInteger = 1;
404 AssertMsg(bType >= 12 || RTFLOAT80U_IS_QUIET_NAN(&r80), ("%s\n", FormatR80(&r80)));
405 AssertMsg(bType < 12 || RTFLOAT80U_IS_SIGNALLING_NAN(&r80), ("%s\n", FormatR80(&r80)));
406 AssertMsg(RTFLOAT80U_IS_SIGNALLING_NAN(&r80) || RTFLOAT80U_IS_QUIET_NAN(&r80), ("%s\n", FormatR80(&r80)));
407 AssertMsg(RTFLOAT80U_IS_QUIET_OR_SIGNALLING_NAN(&r80), ("%s\n", FormatR80(&r80)));
408 AssertMsg(RTFLOAT80U_IS_NAN(&r80), ("%s\n", FormatR80(&r80)));
409 }
410 else if (bType == 14 || bType == 15)
411 {
412 /* Unnormals */
413 if (bType & 1)
414 SafeR80FractionShift(&r80, RandU8() % 62);
415 r80.sj64.fInteger = 0;
416 if (r80.sj64.uExponent == RTFLOAT80U_EXP_MAX || r80.sj64.uExponent == 0)
417 r80.sj64.uExponent = (uint16_t)RTRandU32Ex(1, RTFLOAT80U_EXP_MAX - 1);
418 AssertMsg(RTFLOAT80U_IS_UNNORMAL(&r80), ("%s\n", FormatR80(&r80)));
419 Assert(RTFLOAT80U_IS_387_INVALID(&r80));
420 }
421 else if (bType < 26)
422 {
423 /* Make sure we have lots of normalized values. */
424 if (!fIntTarget)
425 {
426 const unsigned uMinExp = cTarget == 64 ? RTFLOAT80U_EXP_BIAS - RTFLOAT64U_EXP_BIAS
427 : cTarget == 32 ? RTFLOAT80U_EXP_BIAS - RTFLOAT32U_EXP_BIAS : 0;
428 const unsigned uMaxExp = cTarget == 64 ? uMinExp + RTFLOAT64U_EXP_MAX
429 : cTarget == 32 ? uMinExp + RTFLOAT32U_EXP_MAX : RTFLOAT80U_EXP_MAX;
430 r80.sj64.fInteger = 1;
431 if (r80.sj64.uExponent <= uMinExp)
432 r80.sj64.uExponent = uMinExp + 1;
433 else if (r80.sj64.uExponent >= uMaxExp)
434 r80.sj64.uExponent = uMaxExp - 1;
435
436 if (bType == 16)
437 { /* All 1s is useful to testing rounding. Also try trigger special
438 behaviour by sometimes rounding out of range, while we're at it. */
439 r80.sj64.uFraction = RT_BIT_64(63) - 1;
440 uint8_t bExp = RandU8();
441 if ((bExp & 3) == 0)
442 r80.sj64.uExponent = uMaxExp - 1;
443 else if ((bExp & 3) == 1)
444 r80.sj64.uExponent = uMinExp + 1;
445 else if ((bExp & 3) == 2)
446 r80.sj64.uExponent = uMinExp - (bExp & 15); /* (small numbers are mapped to subnormal values) */
447 }
448 }
449 else
450 {
451 /* integer target: */
452 const unsigned uMinExp = RTFLOAT80U_EXP_BIAS;
453 const unsigned uMaxExp = RTFLOAT80U_EXP_BIAS + cTarget - 2;
454 r80.sj64.fInteger = 1;
455 if (r80.sj64.uExponent < uMinExp)
456 r80.sj64.uExponent = uMinExp;
457 else if (r80.sj64.uExponent > uMaxExp)
458 r80.sj64.uExponent = uMaxExp;
459
460 if (bType == 16)
461 { /* All 1s is useful to testing rounding. Also try trigger special
462 behaviour by sometimes rounding out of range, while we're at it. */
463 r80.sj64.uFraction = RT_BIT_64(63) - 1;
464 uint8_t bExp = RandU8();
465 if ((bExp & 3) == 0)
466 r80.sj64.uExponent = uMaxExp;
467 else if ((bExp & 3) == 1)
468 r80.sj64.uFraction &= ~(RT_BIT_64(cTarget - 1 - r80.sj64.uExponent) - 1); /* no rounding */
469 }
470 }
471
472 AssertMsg(RTFLOAT80U_IS_NORMAL(&r80), ("%s\n", FormatR80(&r80)));
473 }
474 return r80;
475}
476
477
478static RTFLOAT80U RandR80(unsigned cTarget = 80, bool fIntTarget = false)
479{
480 /*
481 * Make it more likely that we get a good selection of special values.
482 */
483 return RandR80Ex(RandU8(), cTarget, fIntTarget);
484
485}
486
487
488static RTFLOAT80U RandR80Src(uint32_t iTest, unsigned cTarget = 80, bool fIntTarget = false)
489{
490 /* Make sure we cover all the basic types first before going for random selection: */
491 if (iTest <= 18)
492 return RandR80Ex(18 - iTest, cTarget, fIntTarget); /* Starting with 3 normals. */
493 return RandR80(cTarget, fIntTarget);
494}
495
496
497/**
498 * Helper for RandR80Src1 and RandR80Src2 that converts bType from a 0..11 range
499 * to a 0..17, covering all basic value types.
500 */
501static uint8_t RandR80Src12RemapType(uint8_t bType)
502{
503 switch (bType)
504 {
505 case 0: return 18; /* normal */
506 case 1: return 16; /* normal extreme rounding */
507 case 2: return 14; /* unnormal */
508 case 3: return 12; /* Signalling NaN */
509 case 4: return 10; /* Quiet NaN */
510 case 5: return 8; /* PseudoNaN */
511 case 6: return 6; /* Pseudo Denormal */
512 case 7: return 4; /* Denormal */
513 case 8: return 3; /* Indefinite */
514 case 9: return 2; /* Infinity */
515 case 10: return 1; /* Pseudo-Infinity */
516 case 11: return 0; /* Zero */
517 default: AssertFailedReturn(18);
518 }
519}
520
521
522/**
523 * This works in tandem with RandR80Src2 to make sure we cover all operand
524 * type mixes first before we venture into regular random testing.
525 *
526 * There are 11 basic variations, when we leave out the five odd ones using
527 * SafeR80FractionShift. Because of the special normalized value targetting at
528 * rounding, we make it an even 12. So 144 combinations for two operands.
529 */
530static RTFLOAT80U RandR80Src1(uint32_t iTest, unsigned cPartnerBits = 80, bool fPartnerInt = false)
531{
532 if (cPartnerBits == 80)
533 {
534 Assert(!fPartnerInt);
535 if (iTest < 12 * 12)
536 return RandR80Ex(RandR80Src12RemapType(iTest / 12));
537 }
538 else if ((cPartnerBits == 64 || cPartnerBits == 32) && !fPartnerInt)
539 {
540 if (iTest < 12 * 10)
541 return RandR80Ex(RandR80Src12RemapType(iTest / 10));
542 }
543 else if (iTest < 18 * 4 && fPartnerInt)
544 return RandR80Ex(iTest / 4);
545 return RandR80();
546}
547
548
549/** Partner to RandR80Src1. */
550static RTFLOAT80U RandR80Src2(uint32_t iTest)
551{
552 if (iTest < 12 * 12)
553 return RandR80Ex(RandR80Src12RemapType(iTest % 12));
554 return RandR80();
555}
556
557
558static void SafeR64FractionShift(PRTFLOAT64U pr64, uint8_t cShift)
559{
560 if (pr64->s64.uFraction >= RT_BIT_64(cShift))
561 pr64->s64.uFraction >>= cShift;
562 else
563 pr64->s64.uFraction = (cShift % 19) + 1;
564}
565
566
567static RTFLOAT64U RandR64Ex(uint8_t bType)
568{
569 RTFLOAT64U r64;
570 r64.u = RandU64();
571
572 /*
573 * Make it more likely that we get a good selection of special values.
574 * On average 6 out of 16 calls should return a special value.
575 */
576 bType &= 0xf;
577 if (bType == 0 || bType == 1)
578 {
579 /* 0 or Infinity. We only keep fSign here. */
580 r64.s.uExponent = bType == 0 ? 0 : 0x7ff;
581 r64.s.uFractionHigh = 0;
582 r64.s.uFractionLow = 0;
583 AssertMsg(bType != 0 || RTFLOAT64U_IS_ZERO(&r64), ("%s bType=%#x\n", FormatR64(&r64), bType));
584 AssertMsg(bType != 1 || RTFLOAT64U_IS_INF(&r64), ("%s bType=%#x\n", FormatR64(&r64), bType));
585 }
586 else if (bType == 2 || bType == 3)
587 {
588 /* Subnormals */
589 if (bType == 3)
590 SafeR64FractionShift(&r64, r64.s64.uExponent % 51);
591 else if (r64.s64.uFraction == 0)
592 r64.s64.uFraction = RTRandU64Ex(1, RT_BIT_64(RTFLOAT64U_FRACTION_BITS) - 1);
593 r64.s64.uExponent = 0;
594 AssertMsg(RTFLOAT64U_IS_SUBNORMAL(&r64), ("%s bType=%#x\n", FormatR64(&r64), bType));
595 }
596 else if (bType == 4 || bType == 5 || bType == 6 || bType == 7)
597 {
598 /* NaNs */
599 if (bType & 1)
600 SafeR64FractionShift(&r64, r64.s64.uExponent % 51);
601 else if (r64.s64.uFraction == 0)
602 r64.s64.uFraction = RTRandU64Ex(1, RT_BIT_64(RTFLOAT64U_FRACTION_BITS) - 1);
603 r64.s64.uExponent = 0x7ff;
604 if (bType < 6)
605 r64.s64.uFraction |= RT_BIT_64(RTFLOAT64U_FRACTION_BITS - 1); /* quiet */
606 else
607 r64.s64.uFraction &= ~RT_BIT_64(RTFLOAT64U_FRACTION_BITS - 1); /* signalling */
608 AssertMsg(bType >= 6 || RTFLOAT64U_IS_QUIET_NAN(&r64), ("%s bType=%#x\n", FormatR64(&r64), bType));
609 AssertMsg(bType < 6 || RTFLOAT64U_IS_SIGNALLING_NAN(&r64), ("%s bType=%#x\n", FormatR64(&r64), bType));
610 AssertMsg(RTFLOAT64U_IS_NAN(&r64), ("%s bType=%#x\n", FormatR64(&r64), bType));
611 }
612 else if (bType < 12)
613 {
614 /* Make sure we have lots of normalized values. */
615 if (r64.s.uExponent == 0)
616 r64.s.uExponent = 1;
617 else if (r64.s.uExponent == 0x7ff)
618 r64.s.uExponent = 0x7fe;
619 AssertMsg(RTFLOAT64U_IS_NORMAL(&r64), ("%s bType=%#x\n", FormatR64(&r64), bType));
620 }
621 return r64;
622}
623
624
625static RTFLOAT64U RandR64Src(uint32_t iTest)
626{
627 if (iTest < 16)
628 return RandR64Ex(iTest);
629 return RandR64Ex(RandU8());
630}
631
632
633/** Pairing with a 80-bit floating point arg. */
634static RTFLOAT64U RandR64Src2(uint32_t iTest)
635{
636 if (iTest < 12 * 10)
637 return RandR64Ex(9 - iTest % 10); /* start with normal values */
638 return RandR64Ex(RandU8());
639}
640
641
642static void SafeR32FractionShift(PRTFLOAT32U pr32, uint8_t cShift)
643{
644 if (pr32->s.uFraction >= RT_BIT_32(cShift))
645 pr32->s.uFraction >>= cShift;
646 else
647 pr32->s.uFraction = (cShift % 19) + 1;
648}
649
650
651static RTFLOAT32U RandR32Ex(uint8_t bType)
652{
653 RTFLOAT32U r32;
654 r32.u = RandU32();
655
656 /*
657 * Make it more likely that we get a good selection of special values.
658 * On average 6 out of 16 calls should return a special value.
659 */
660 bType &= 0xf;
661 if (bType == 0 || bType == 1)
662 {
663 /* 0 or Infinity. We only keep fSign here. */
664 r32.s.uExponent = bType == 0 ? 0 : 0xff;
665 r32.s.uFraction = 0;
666 AssertMsg(bType != 0 || RTFLOAT32U_IS_ZERO(&r32), ("%s\n", FormatR32(&r32)));
667 AssertMsg(bType != 1 || RTFLOAT32U_IS_INF(&r32), ("%s\n", FormatR32(&r32)));
668 }
669 else if (bType == 2 || bType == 3)
670 {
671 /* Subnormals */
672 if (bType == 3)
673 SafeR32FractionShift(&r32, r32.s.uExponent % 22);
674 else if (r32.s.uFraction == 0)
675 r32.s.uFraction = RTRandU32Ex(1, RT_BIT_32(RTFLOAT32U_FRACTION_BITS) - 1);
676 r32.s.uExponent = 0;
677 AssertMsg(RTFLOAT32U_IS_SUBNORMAL(&r32), ("%s bType=%#x\n", FormatR32(&r32), bType));
678 }
679 else if (bType == 4 || bType == 5 || bType == 6 || bType == 7)
680 {
681 /* NaNs */
682 if (bType & 1)
683 SafeR32FractionShift(&r32, r32.s.uExponent % 22);
684 else if (r32.s.uFraction == 0)
685 r32.s.uFraction = RTRandU32Ex(1, RT_BIT_32(RTFLOAT32U_FRACTION_BITS) - 1);
686 r32.s.uExponent = 0xff;
687 if (bType < 6)
688 r32.s.uFraction |= RT_BIT_32(RTFLOAT32U_FRACTION_BITS - 1); /* quiet */
689 else
690 r32.s.uFraction &= ~RT_BIT_32(RTFLOAT32U_FRACTION_BITS - 1); /* signalling */
691 AssertMsg(bType >= 6 || RTFLOAT32U_IS_QUIET_NAN(&r32), ("%s bType=%#x\n", FormatR32(&r32), bType));
692 AssertMsg(bType < 6 || RTFLOAT32U_IS_SIGNALLING_NAN(&r32), ("%s bType=%#x\n", FormatR32(&r32), bType));
693 AssertMsg(RTFLOAT32U_IS_NAN(&r32), ("%s bType=%#x\n", FormatR32(&r32), bType));
694 }
695 else if (bType < 12)
696 {
697 /* Make sure we have lots of normalized values. */
698 if (r32.s.uExponent == 0)
699 r32.s.uExponent = 1;
700 else if (r32.s.uExponent == 0xff)
701 r32.s.uExponent = 0xfe;
702 AssertMsg(RTFLOAT32U_IS_NORMAL(&r32), ("%s bType=%#x\n", FormatR32(&r32), bType));
703 }
704 return r32;
705}
706
707
708static RTFLOAT32U RandR32Src(uint32_t iTest)
709{
710 if (iTest < 16)
711 return RandR32Ex(iTest);
712 return RandR32Ex(RandU8());
713}
714
715
716/** Pairing with a 80-bit floating point arg. */
717static RTFLOAT32U RandR32Src2(uint32_t iTest)
718{
719 if (iTest < 12 * 10)
720 return RandR32Ex(9 - iTest % 10); /* start with normal values */
721 return RandR32Ex(RandU8());
722}
723
724
725static RTPBCD80U RandD80Src(uint32_t iTest)
726{
727 if (iTest < 3)
728 {
729 RTPBCD80U d80Zero = RTPBCD80U_INIT_ZERO(!(iTest & 1));
730 return d80Zero;
731 }
732 if (iTest < 5)
733 {
734 RTPBCD80U d80Ind = RTPBCD80U_INIT_INDEFINITE();
735 return d80Ind;
736 }
737
738 RTPBCD80U d80;
739 uint8_t b = RandU8();
740 d80.s.fSign = b & 1;
741
742 if ((iTest & 7) >= 6)
743 {
744 /* Illegal */
745 d80.s.uPad = (iTest & 7) == 7 ? b >> 1 : 0;
746 for (size_t iPair = 0; iPair < RT_ELEMENTS(d80.s.abPairs); iPair++)
747 d80.s.abPairs[iPair] = RandU8();
748 }
749 else
750 {
751 /* Normal */
752 d80.s.uPad = 0;
753 for (size_t iPair = 0; iPair < RT_ELEMENTS(d80.s.abPairs); iPair++)
754 {
755 uint8_t const uLo = (uint8_t)RTRandU32Ex(0, 9);
756 uint8_t const uHi = (uint8_t)RTRandU32Ex(0, 9);
757 d80.s.abPairs[iPair] = RTPBCD80U_MAKE_PAIR(uHi, uLo);
758 }
759 }
760 return d80;
761}
762
763
764static const char *GenFormatR80(PCRTFLOAT80U plrd)
765{
766 if (RTFLOAT80U_IS_ZERO(plrd))
767 return plrd->s.fSign ? "RTFLOAT80U_INIT_ZERO(1)" : "RTFLOAT80U_INIT_ZERO(0)";
768 if (RTFLOAT80U_IS_INF(plrd))
769 return plrd->s.fSign ? "RTFLOAT80U_INIT_INF(1)" : "RTFLOAT80U_INIT_INF(0)";
770 if (RTFLOAT80U_IS_INDEFINITE(plrd))
771 return plrd->s.fSign ? "RTFLOAT80U_INIT_IND(1)" : "RTFLOAT80U_INIT_IND(0)";
772 if (RTFLOAT80U_IS_QUIET_NAN(plrd) && (plrd->s.uMantissa & (RT_BIT_64(62) - 1)) == 1)
773 return plrd->s.fSign ? "RTFLOAT80U_INIT_QNAN(1)" : "RTFLOAT80U_INIT_QNAN(0)";
774 if (RTFLOAT80U_IS_SIGNALLING_NAN(plrd) && (plrd->s.uMantissa & (RT_BIT_64(62) - 1)) == 1)
775 return plrd->s.fSign ? "RTFLOAT80U_INIT_SNAN(1)" : "RTFLOAT80U_INIT_SNAN(0)";
776
777 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
778 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "RTFLOAT80U_INIT_C(%d,%#RX64,%u)",
779 plrd->s.fSign, plrd->s.uMantissa, plrd->s.uExponent);
780 return pszBuf;
781}
782
783static const char *GenFormatR64(PCRTFLOAT64U prd)
784{
785 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
786 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "RTFLOAT64U_INIT_C(%d,%#RX64,%u)",
787 prd->s.fSign, RT_MAKE_U64(prd->s.uFractionLow, prd->s.uFractionHigh), prd->s.uExponent);
788 return pszBuf;
789}
790
791
792static const char *GenFormatR32(PCRTFLOAT32U pr)
793{
794 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
795 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "RTFLOAT32U_INIT_C(%d,%#RX32,%u)", pr->s.fSign, pr->s.uFraction, pr->s.uExponent);
796 return pszBuf;
797}
798
799
800static const char *GenFormatD80(PCRTPBCD80U pd80)
801{
802 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
803 size_t off;
804 if (pd80->s.uPad == 0)
805 off = RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "RTPBCD80U_INIT_C(%d", pd80->s.fSign);
806 else
807 off = RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "RTPBCD80U_INIT_EX_C(%#x,%d", pd80->s.uPad, pd80->s.fSign);
808 size_t iPair = RT_ELEMENTS(pd80->s.abPairs);
809 while (iPair-- > 0)
810 off += RTStrPrintf(&pszBuf[off], sizeof(g_aszBuf[0]) - off, ",%d,%d",
811 RTPBCD80U_HI_DIGIT(pd80->s.abPairs[iPair]),
812 RTPBCD80U_LO_DIGIT(pd80->s.abPairs[iPair]));
813 pszBuf[off++] = ')';
814 pszBuf[off++] = '\0';
815 return pszBuf;
816}
817
818
819static const char *GenFormatI64(int64_t i64)
820{
821 if (i64 == INT64_MIN) /* This one is problematic */
822 return "INT64_MIN";
823 if (i64 == INT64_MAX)
824 return "INT64_MAX";
825 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
826 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "INT64_C(%RI64)", i64);
827 return pszBuf;
828}
829
830#if 0 /* unused */
831static const char *GenFormatI64(int64_t const *pi64)
832{
833 return GenFormatI64(*pi64);
834}
835#endif
836
837static const char *GenFormatI32(int32_t i32)
838{
839 if (i32 == INT32_MIN) /* This one is problematic */
840 return "INT32_MIN";
841 if (i32 == INT32_MAX)
842 return "INT32_MAX";
843 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
844 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "INT32_C(%RI32)", i32);
845 return pszBuf;
846}
847
848
849const char *GenFormatI32(int32_t const *pi32)
850{
851 return GenFormatI32(*pi32);
852}
853
854
855const char *GenFormatI16(int16_t i16)
856{
857 if (i16 == INT16_MIN) /* This one is problematic */
858 return "INT16_MIN";
859 if (i16 == INT16_MAX)
860 return "INT16_MAX";
861 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
862 RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), "INT16_C(%RI16)", i16);
863 return pszBuf;
864}
865
866
867const char *GenFormatI16(int16_t const *pi16)
868{
869 return GenFormatI16(*pi16);
870}
871
872
873static void GenerateHeader(PRTSTREAM pOut, const char *pszCpuDesc, const char *pszCpuType)
874{
875 /* We want to tag the generated source code with the revision that produced it. */
876 static char s_szRev[] = "$Revision: 100840 $";
877 const char *pszRev = RTStrStripL(strchr(s_szRev, ':') + 1);
878 size_t cchRev = 0;
879 while (RT_C_IS_DIGIT(pszRev[cchRev]))
880 cchRev++;
881
882 RTStrmPrintf(pOut,
883 "/* $Id: tstIEMAImpl.cpp 100840 2023-08-09 17:52:37Z vboxsync $ */\n"
884 "/** @file\n"
885 " * IEM Assembly Instruction Helper Testcase Data%s%s - r%.*s on %s.\n"
886 " */\n"
887 "\n"
888 "/*\n"
889 " * Copyright (C) 2022-" VBOX_C_YEAR " Oracle and/or its affiliates.\n"
890 " *\n"
891 " * This file is part of VirtualBox base platform packages, as\n"
892 " * available from https://www.virtualbox.org.\n"
893 " *\n"
894 " * This program is free software; you can redistribute it and/or\n"
895 " * modify it under the terms of the GNU General Public License\n"
896 " * as published by the Free Software Foundation, in version 3 of the\n"
897 " * License.\n"
898 " *\n"
899 " * This program is distributed in the hope that it will be useful, but\n"
900 " * WITHOUT ANY WARRANTY; without even the implied warranty of\n"
901 " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
902 " * General Public License for more details.\n"
903 " *\n"
904 " * You should have received a copy of the GNU General Public License\n"
905 " * along with this program; if not, see <https://www.gnu.org/licenses>.\n"
906 " *\n"
907 " * SPDX-License-Identifier: GPL-3.0-only\n"
908 " */\n"
909 "\n"
910 "#include \"tstIEMAImpl.h\"\n"
911 "\n"
912 ,
913 pszCpuType ? " " : "", pszCpuType ? pszCpuType : "", cchRev, pszRev, pszCpuDesc);
914}
915
916
917static PRTSTREAM GenerateOpenWithHdr(const char *pszFilename, const char *pszCpuDesc, const char *pszCpuType)
918{
919 PRTSTREAM pOut = NULL;
920 int rc = RTStrmOpen(pszFilename, "w", &pOut);
921 if (RT_SUCCESS(rc))
922 {
923 GenerateHeader(pOut, pszCpuDesc, pszCpuType);
924 return pOut;
925 }
926 RTMsgError("Failed to open %s for writing: %Rrc", pszFilename, rc);
927 return NULL;
928}
929
930
931static RTEXITCODE GenerateFooterAndClose(PRTSTREAM pOut, const char *pszFilename, RTEXITCODE rcExit)
932{
933 RTStrmPrintf(pOut,
934 "\n"
935 "/* end of file */\n");
936 int rc = RTStrmClose(pOut);
937 if (RT_SUCCESS(rc))
938 return rcExit;
939 return RTMsgErrorExitFailure("RTStrmClose failed on %s: %Rrc", pszFilename, rc);
940}
941
942
943static void GenerateArrayStart(PRTSTREAM pOut, const char *pszName, const char *pszType)
944{
945 RTStrmPrintf(pOut, "%s const g_aTests_%s[] =\n{\n", pszType, pszName);
946}
947
948
949static void GenerateArrayEnd(PRTSTREAM pOut, const char *pszName)
950{
951 RTStrmPrintf(pOut,
952 "};\n"
953 "uint32_t const g_cTests_%s = RT_ELEMENTS(g_aTests_%s);\n"
954 "\n",
955 pszName, pszName);
956}
957
958#endif /* TSTIEMAIMPL_WITH_GENERATOR */
959
960
961/*
962 * Test helpers.
963 */
964static bool IsTestEnabled(const char *pszName)
965{
966 /* Process excludes first: */
967 uint32_t i = g_cExcludeTestPatterns;
968 while (i-- > 0)
969 if (RTStrSimplePatternMultiMatch(g_apszExcludeTestPatterns[i], RTSTR_MAX, pszName, RTSTR_MAX, NULL))
970 return false;
971
972 /* If no include patterns, everything is included: */
973 i = g_cIncludeTestPatterns;
974 if (!i)
975 return true;
976
977 /* Otherwise only tests in the include patters gets tested: */
978 while (i-- > 0)
979 if (RTStrSimplePatternMultiMatch(g_apszIncludeTestPatterns[i], RTSTR_MAX, pszName, RTSTR_MAX, NULL))
980 return true;
981
982 return false;
983}
984
985
986static bool SubTestAndCheckIfEnabled(const char *pszName)
987{
988 RTTestSub(g_hTest, pszName);
989 if (IsTestEnabled(pszName))
990 return true;
991 RTTestSkipped(g_hTest, g_cVerbosity > 0 ? "excluded" : NULL);
992 return false;
993}
994
995
996static const char *EFlagsDiff(uint32_t fActual, uint32_t fExpected)
997{
998 if (fActual == fExpected)
999 return "";
1000
1001 uint32_t const fXor = fActual ^ fExpected;
1002 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
1003 size_t cch = RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), " - %#x", fXor);
1004
1005 static struct
1006 {
1007 const char *pszName;
1008 uint32_t fFlag;
1009 } const s_aFlags[] =
1010 {
1011#define EFL_ENTRY(a_Flags) { #a_Flags, X86_EFL_ ## a_Flags }
1012 EFL_ENTRY(CF),
1013 EFL_ENTRY(PF),
1014 EFL_ENTRY(AF),
1015 EFL_ENTRY(ZF),
1016 EFL_ENTRY(SF),
1017 EFL_ENTRY(TF),
1018 EFL_ENTRY(IF),
1019 EFL_ENTRY(DF),
1020 EFL_ENTRY(OF),
1021 EFL_ENTRY(IOPL),
1022 EFL_ENTRY(NT),
1023 EFL_ENTRY(RF),
1024 EFL_ENTRY(VM),
1025 EFL_ENTRY(AC),
1026 EFL_ENTRY(VIF),
1027 EFL_ENTRY(VIP),
1028 EFL_ENTRY(ID),
1029 };
1030 for (size_t i = 0; i < RT_ELEMENTS(s_aFlags); i++)
1031 if (s_aFlags[i].fFlag & fXor)
1032 cch += RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch,
1033 s_aFlags[i].fFlag & fActual ? "/%s" : "/!%s", s_aFlags[i].pszName);
1034 RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, "");
1035 return pszBuf;
1036}
1037
1038
1039static const char *FswDiff(uint16_t fActual, uint16_t fExpected)
1040{
1041 if (fActual == fExpected)
1042 return "";
1043
1044 uint16_t const fXor = fActual ^ fExpected;
1045 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
1046 size_t cch = RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), " - %#x", fXor);
1047
1048 static struct
1049 {
1050 const char *pszName;
1051 uint32_t fFlag;
1052 } const s_aFlags[] =
1053 {
1054#define FSW_ENTRY(a_Flags) { #a_Flags, X86_FSW_ ## a_Flags }
1055 FSW_ENTRY(IE),
1056 FSW_ENTRY(DE),
1057 FSW_ENTRY(ZE),
1058 FSW_ENTRY(OE),
1059 FSW_ENTRY(UE),
1060 FSW_ENTRY(PE),
1061 FSW_ENTRY(SF),
1062 FSW_ENTRY(ES),
1063 FSW_ENTRY(C0),
1064 FSW_ENTRY(C1),
1065 FSW_ENTRY(C2),
1066 FSW_ENTRY(C3),
1067 FSW_ENTRY(B),
1068 };
1069 for (size_t i = 0; i < RT_ELEMENTS(s_aFlags); i++)
1070 if (s_aFlags[i].fFlag & fXor)
1071 cch += RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch,
1072 s_aFlags[i].fFlag & fActual ? "/%s" : "/!%s", s_aFlags[i].pszName);
1073 if (fXor & X86_FSW_TOP_MASK)
1074 cch += RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, "/TOP%u!%u",
1075 X86_FSW_TOP_GET(fActual), X86_FSW_TOP_GET(fExpected));
1076#if 0 /* For debugging fprem & fprem1 */
1077 cch += RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, " - Q=%d (vs %d)",
1078 X86_FSW_CX_TO_QUOTIENT(fActual), X86_FSW_CX_TO_QUOTIENT(fExpected));
1079#endif
1080 RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, "");
1081 return pszBuf;
1082}
1083
1084
1085static const char *MxcsrDiff(uint32_t fActual, uint32_t fExpected)
1086{
1087 if (fActual == fExpected)
1088 return "";
1089
1090 uint16_t const fXor = fActual ^ fExpected;
1091 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
1092 size_t cch = RTStrPrintf(pszBuf, sizeof(g_aszBuf[0]), " - %#x", fXor);
1093
1094 static struct
1095 {
1096 const char *pszName;
1097 uint32_t fFlag;
1098 } const s_aFlags[] =
1099 {
1100#define MXCSR_ENTRY(a_Flags) { #a_Flags, X86_MXCSR_ ## a_Flags }
1101 MXCSR_ENTRY(IE),
1102 MXCSR_ENTRY(DE),
1103 MXCSR_ENTRY(ZE),
1104 MXCSR_ENTRY(OE),
1105 MXCSR_ENTRY(UE),
1106 MXCSR_ENTRY(PE),
1107
1108 MXCSR_ENTRY(IM),
1109 MXCSR_ENTRY(DM),
1110 MXCSR_ENTRY(ZM),
1111 MXCSR_ENTRY(OM),
1112 MXCSR_ENTRY(UM),
1113 MXCSR_ENTRY(PM),
1114
1115 MXCSR_ENTRY(DAZ),
1116 MXCSR_ENTRY(FZ),
1117#undef MXCSR_ENTRY
1118 };
1119 for (size_t i = 0; i < RT_ELEMENTS(s_aFlags); i++)
1120 if (s_aFlags[i].fFlag & fXor)
1121 cch += RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch,
1122 s_aFlags[i].fFlag & fActual ? "/%s" : "/!%s", s_aFlags[i].pszName);
1123 RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, "");
1124 return pszBuf;
1125}
1126
1127
1128static const char *FormatFcw(uint16_t fFcw)
1129{
1130 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
1131
1132 const char *pszPC = NULL; /* (msc+gcc are too stupid) */
1133 switch (fFcw & X86_FCW_PC_MASK)
1134 {
1135 case X86_FCW_PC_24: pszPC = "PC24"; break;
1136 case X86_FCW_PC_RSVD: pszPC = "PCRSVD!"; break;
1137 case X86_FCW_PC_53: pszPC = "PC53"; break;
1138 case X86_FCW_PC_64: pszPC = "PC64"; break;
1139 }
1140
1141 const char *pszRC = NULL; /* (msc+gcc are too stupid) */
1142 switch (fFcw & X86_FCW_RC_MASK)
1143 {
1144 case X86_FCW_RC_NEAREST: pszRC = "NEAR"; break;
1145 case X86_FCW_RC_DOWN: pszRC = "DOWN"; break;
1146 case X86_FCW_RC_UP: pszRC = "UP"; break;
1147 case X86_FCW_RC_ZERO: pszRC = "ZERO"; break;
1148 }
1149 size_t cch = RTStrPrintf(&pszBuf[0], sizeof(g_aszBuf[0]), "%s %s", pszPC, pszRC);
1150
1151 static struct
1152 {
1153 const char *pszName;
1154 uint32_t fFlag;
1155 } const s_aFlags[] =
1156 {
1157#define FCW_ENTRY(a_Flags) { #a_Flags, X86_FCW_ ## a_Flags }
1158 FCW_ENTRY(IM),
1159 FCW_ENTRY(DM),
1160 FCW_ENTRY(ZM),
1161 FCW_ENTRY(OM),
1162 FCW_ENTRY(UM),
1163 FCW_ENTRY(PM),
1164 { "6M", 64 },
1165 };
1166 for (size_t i = 0; i < RT_ELEMENTS(s_aFlags); i++)
1167 if (fFcw & s_aFlags[i].fFlag)
1168 cch += RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, " %s", s_aFlags[i].pszName);
1169
1170 RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, "");
1171 return pszBuf;
1172}
1173
1174
1175static const char *FormatMxcsr(uint32_t fMxcsr)
1176{
1177 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
1178
1179 const char *pszRC = NULL; /* (msc+gcc are too stupid) */
1180 switch (fMxcsr & X86_MXCSR_RC_MASK)
1181 {
1182 case X86_MXCSR_RC_NEAREST: pszRC = "NEAR"; break;
1183 case X86_MXCSR_RC_DOWN: pszRC = "DOWN"; break;
1184 case X86_MXCSR_RC_UP: pszRC = "UP"; break;
1185 case X86_MXCSR_RC_ZERO: pszRC = "ZERO"; break;
1186 }
1187
1188 const char *pszDAZ = fMxcsr & X86_MXCSR_DAZ ? " DAZ" : "";
1189 const char *pszFZ = fMxcsr & X86_MXCSR_FZ ? " FZ" : "";
1190 size_t cch = RTStrPrintf(&pszBuf[0], sizeof(g_aszBuf[0]), "%s%s%s", pszRC, pszDAZ, pszFZ);
1191
1192 static struct
1193 {
1194 const char *pszName;
1195 uint32_t fFlag;
1196 } const s_aFlags[] =
1197 {
1198#define MXCSR_ENTRY(a_Flags) { #a_Flags, X86_MXCSR_ ## a_Flags }
1199 MXCSR_ENTRY(IE),
1200 MXCSR_ENTRY(DE),
1201 MXCSR_ENTRY(ZE),
1202 MXCSR_ENTRY(OE),
1203 MXCSR_ENTRY(UE),
1204 MXCSR_ENTRY(PE),
1205
1206 MXCSR_ENTRY(IM),
1207 MXCSR_ENTRY(DM),
1208 MXCSR_ENTRY(ZM),
1209 MXCSR_ENTRY(OM),
1210 MXCSR_ENTRY(UM),
1211 MXCSR_ENTRY(PM),
1212 { "6M", 64 },
1213 };
1214 for (size_t i = 0; i < RT_ELEMENTS(s_aFlags); i++)
1215 if (fMxcsr & s_aFlags[i].fFlag)
1216 cch += RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, " %s", s_aFlags[i].pszName);
1217
1218 RTStrPrintf(&pszBuf[cch], sizeof(g_aszBuf[0]) - cch, "");
1219 return pszBuf;
1220}
1221
1222
1223static const char *FormatR80(PCRTFLOAT80U pr80)
1224{
1225 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
1226 RTStrFormatR80(pszBuf, sizeof(g_aszBuf[0]), pr80, 0, 0, RTSTR_F_SPECIAL);
1227 return pszBuf;
1228}
1229
1230
1231static const char *FormatR64(PCRTFLOAT64U pr64)
1232{
1233 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
1234 RTStrFormatR64(pszBuf, sizeof(g_aszBuf[0]), pr64, 0, 0, RTSTR_F_SPECIAL);
1235 return pszBuf;
1236}
1237
1238
1239static const char *FormatR32(PCRTFLOAT32U pr32)
1240{
1241 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
1242 RTStrFormatR32(pszBuf, sizeof(g_aszBuf[0]), pr32, 0, 0, RTSTR_F_SPECIAL);
1243 return pszBuf;
1244}
1245
1246
1247static const char *FormatD80(PCRTPBCD80U pd80)
1248{
1249 /* There is only one indefinite endcoding (same as for 80-bit
1250 floating point), so get it out of the way first: */
1251 if (RTPBCD80U_IS_INDEFINITE(pd80))
1252 return "Ind";
1253
1254 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
1255 size_t off = 0;
1256 pszBuf[off++] = pd80->s.fSign ? '-' : '+';
1257 unsigned cBadDigits = 0;
1258 size_t iPair = RT_ELEMENTS(pd80->s.abPairs);
1259 while (iPair-- > 0)
1260 {
1261 static const char s_szDigits[] = "0123456789abcdef";
1262 static const uint8_t s_bBadDigits[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 };
1263 pszBuf[off++] = s_szDigits[RTPBCD80U_HI_DIGIT(pd80->s.abPairs[iPair])];
1264 pszBuf[off++] = s_szDigits[RTPBCD80U_LO_DIGIT(pd80->s.abPairs[iPair])];
1265 cBadDigits += s_bBadDigits[RTPBCD80U_HI_DIGIT(pd80->s.abPairs[iPair])]
1266 + s_bBadDigits[RTPBCD80U_LO_DIGIT(pd80->s.abPairs[iPair])];
1267 }
1268 if (cBadDigits || pd80->s.uPad != 0)
1269 off += RTStrPrintf(&pszBuf[off], sizeof(g_aszBuf[0]) - off, "[%u,%#x]", cBadDigits, pd80->s.uPad);
1270 pszBuf[off] = '\0';
1271 return pszBuf;
1272}
1273
1274
1275#if 0
1276static const char *FormatI64(int64_t const *piVal)
1277{
1278 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
1279 RTStrFormatU64(pszBuf, sizeof(g_aszBuf[0]), *piVal, 16, 0, 0, RTSTR_F_SPECIAL | RTSTR_F_VALSIGNED);
1280 return pszBuf;
1281}
1282#endif
1283
1284
1285static const char *FormatI32(int32_t const *piVal)
1286{
1287 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
1288 RTStrFormatU32(pszBuf, sizeof(g_aszBuf[0]), *piVal, 16, 0, 0, RTSTR_F_SPECIAL | RTSTR_F_VALSIGNED);
1289 return pszBuf;
1290}
1291
1292
1293static const char *FormatI16(int16_t const *piVal)
1294{
1295 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
1296 RTStrFormatU16(pszBuf, sizeof(g_aszBuf[0]), *piVal, 16, 0, 0, RTSTR_F_SPECIAL | RTSTR_F_VALSIGNED);
1297 return pszBuf;
1298}
1299
1300
1301static const char *FormatU128(PCRTUINT128U puVal)
1302{
1303 char *pszBuf = g_aszBuf[g_idxBuf++ % RT_ELEMENTS(g_aszBuf)];
1304 RTStrFormatU128(pszBuf, sizeof(g_aszBuf[0]), puVal, 16, 0, 0, RTSTR_F_SPECIAL);
1305 return pszBuf;
1306}
1307
1308
1309/*
1310 * Binary operations.
1311 */
1312TYPEDEF_SUBTEST_TYPE(BINU8_T, BINU8_TEST_T, PFNIEMAIMPLBINU8);
1313TYPEDEF_SUBTEST_TYPE(BINU16_T, BINU16_TEST_T, PFNIEMAIMPLBINU16);
1314TYPEDEF_SUBTEST_TYPE(BINU32_T, BINU32_TEST_T, PFNIEMAIMPLBINU32);
1315TYPEDEF_SUBTEST_TYPE(BINU64_T, BINU64_TEST_T, PFNIEMAIMPLBINU64);
1316
1317#ifdef TSTIEMAIMPL_WITH_GENERATOR
1318# define GEN_BINARY_TESTS(a_cBits, a_Fmt, a_TestType) \
1319static void BinU ## a_cBits ## Generate(PRTSTREAM pOut, PRTSTREAM pOutCpu, uint32_t cTests) \
1320{ \
1321 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aBinU ## a_cBits); iFn++) \
1322 { \
1323 PFNIEMAIMPLBINU ## a_cBits const pfn = g_aBinU ## a_cBits[iFn].pfnNative \
1324 ? g_aBinU ## a_cBits[iFn].pfnNative : g_aBinU ## a_cBits[iFn].pfn; \
1325 PRTSTREAM pOutFn = pOut; \
1326 if (g_aBinU ## a_cBits[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE) \
1327 { \
1328 if (g_aBinU ## a_cBits[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour) \
1329 continue; \
1330 pOutFn = pOutCpu; \
1331 } \
1332 \
1333 GenerateArrayStart(pOutFn, g_aBinU ## a_cBits[iFn].pszName, #a_TestType); \
1334 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1335 { \
1336 a_TestType Test; \
1337 Test.fEflIn = RandEFlags(); \
1338 Test.fEflOut = Test.fEflIn; \
1339 Test.uDstIn = RandU ## a_cBits ## Dst(iTest); \
1340 Test.uDstOut = Test.uDstIn; \
1341 Test.uSrcIn = RandU ## a_cBits ## Src(iTest); \
1342 if (g_aBinU ## a_cBits[iFn].uExtra) \
1343 Test.uSrcIn &= a_cBits - 1; /* Restrict bit index according to operand width */ \
1344 Test.uMisc = 0; \
1345 pfn(&Test.uDstOut, Test.uSrcIn, &Test.fEflOut); \
1346 RTStrmPrintf(pOutFn, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", " a_Fmt ", %#x }, /* #%u */\n", \
1347 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uSrcIn, Test.uMisc, iTest); \
1348 } \
1349 GenerateArrayEnd(pOutFn, g_aBinU ## a_cBits[iFn].pszName); \
1350 } \
1351}
1352#else
1353# define GEN_BINARY_TESTS(a_cBits, a_Fmt, a_TestType)
1354#endif
1355
1356#define TEST_BINARY_OPS(a_cBits, a_uType, a_Fmt, a_TestType, a_aSubTests) \
1357GEN_BINARY_TESTS(a_cBits, a_Fmt, a_TestType) \
1358\
1359static void BinU ## a_cBits ## Test(void) \
1360{ \
1361 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
1362 { \
1363 if (!SubTestAndCheckIfEnabled(a_aSubTests[iFn].pszName)) continue; \
1364 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
1365 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
1366 PFNIEMAIMPLBINU ## a_cBits pfn = a_aSubTests[iFn].pfn; \
1367 uint32_t const cVars = COUNT_VARIATIONS(a_aSubTests[iFn]); \
1368 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
1369 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
1370 { \
1371 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1372 { \
1373 uint32_t fEfl = paTests[iTest].fEflIn; \
1374 a_uType uDst = paTests[iTest].uDstIn; \
1375 pfn(&uDst, paTests[iTest].uSrcIn, &fEfl); \
1376 if ( uDst != paTests[iTest].uDstOut \
1377 || fEfl != paTests[iTest].fEflOut) \
1378 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", \
1379 iTest, !iVar ? "" : "/n", paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn, \
1380 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut, \
1381 EFlagsDiff(fEfl, paTests[iTest].fEflOut), \
1382 uDst == paTests[iTest].uDstOut ? "eflags" : fEfl == paTests[iTest].fEflOut ? "dst" : "both"); \
1383 else \
1384 { \
1385 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
1386 *g_pfEfl = paTests[iTest].fEflIn; \
1387 pfn(g_pu ## a_cBits, paTests[iTest].uSrcIn, g_pfEfl); \
1388 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDstOut); \
1389 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut); \
1390 } \
1391 } \
1392 pfn = a_aSubTests[iFn].pfnNative; \
1393 } \
1394 } \
1395}
1396
1397
1398/*
1399 * 8-bit binary operations.
1400 */
1401static const BINU8_T g_aBinU8[] =
1402{
1403 ENTRY(add_u8),
1404 ENTRY(add_u8_locked),
1405 ENTRY(adc_u8),
1406 ENTRY(adc_u8_locked),
1407 ENTRY(sub_u8),
1408 ENTRY(sub_u8_locked),
1409 ENTRY(sbb_u8),
1410 ENTRY(sbb_u8_locked),
1411 ENTRY(or_u8),
1412 ENTRY(or_u8_locked),
1413 ENTRY(xor_u8),
1414 ENTRY(xor_u8_locked),
1415 ENTRY(and_u8),
1416 ENTRY(and_u8_locked),
1417 ENTRY_PFN_CAST(cmp_u8, PFNIEMAIMPLBINU8),
1418 ENTRY_PFN_CAST(test_u8, PFNIEMAIMPLBINU8),
1419};
1420TEST_BINARY_OPS(8, uint8_t, "%#04x", BINU8_TEST_T, g_aBinU8)
1421
1422
1423/*
1424 * 16-bit binary operations.
1425 */
1426static const BINU16_T g_aBinU16[] =
1427{
1428 ENTRY(add_u16),
1429 ENTRY(add_u16_locked),
1430 ENTRY(adc_u16),
1431 ENTRY(adc_u16_locked),
1432 ENTRY(sub_u16),
1433 ENTRY(sub_u16_locked),
1434 ENTRY(sbb_u16),
1435 ENTRY(sbb_u16_locked),
1436 ENTRY(or_u16),
1437 ENTRY(or_u16_locked),
1438 ENTRY(xor_u16),
1439 ENTRY(xor_u16_locked),
1440 ENTRY(and_u16),
1441 ENTRY(and_u16_locked),
1442 ENTRY_PFN_CAST(cmp_u16, PFNIEMAIMPLBINU16),
1443 ENTRY_PFN_CAST(test_u16, PFNIEMAIMPLBINU16),
1444 ENTRY_PFN_CAST_EX(bt_u16, PFNIEMAIMPLBINU16, 1),
1445 ENTRY_EX(btc_u16, 1),
1446 ENTRY_EX(btc_u16_locked, 1),
1447 ENTRY_EX(btr_u16, 1),
1448 ENTRY_EX(btr_u16_locked, 1),
1449 ENTRY_EX(bts_u16, 1),
1450 ENTRY_EX(bts_u16_locked, 1),
1451 ENTRY_AMD( bsf_u16, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1452 ENTRY_INTEL(bsf_u16, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1453 ENTRY_AMD( bsr_u16, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1454 ENTRY_INTEL(bsr_u16, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1455 ENTRY_AMD( imul_two_u16, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
1456 ENTRY_INTEL(imul_two_u16, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
1457 ENTRY(arpl),
1458};
1459TEST_BINARY_OPS(16, uint16_t, "%#06x", BINU16_TEST_T, g_aBinU16)
1460
1461
1462/*
1463 * 32-bit binary operations.
1464 */
1465static const BINU32_T g_aBinU32[] =
1466{
1467 ENTRY(add_u32),
1468 ENTRY(add_u32_locked),
1469 ENTRY(adc_u32),
1470 ENTRY(adc_u32_locked),
1471 ENTRY(sub_u32),
1472 ENTRY(sub_u32_locked),
1473 ENTRY(sbb_u32),
1474 ENTRY(sbb_u32_locked),
1475 ENTRY(or_u32),
1476 ENTRY(or_u32_locked),
1477 ENTRY(xor_u32),
1478 ENTRY(xor_u32_locked),
1479 ENTRY(and_u32),
1480 ENTRY(and_u32_locked),
1481 ENTRY_PFN_CAST(cmp_u32, PFNIEMAIMPLBINU32),
1482 ENTRY_PFN_CAST(test_u32, PFNIEMAIMPLBINU32),
1483 ENTRY_PFN_CAST_EX(bt_u32, PFNIEMAIMPLBINU32, 1),
1484 ENTRY_EX(btc_u32, 1),
1485 ENTRY_EX(btc_u32_locked, 1),
1486 ENTRY_EX(btr_u32, 1),
1487 ENTRY_EX(btr_u32_locked, 1),
1488 ENTRY_EX(bts_u32, 1),
1489 ENTRY_EX(bts_u32_locked, 1),
1490 ENTRY_AMD( bsf_u32, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1491 ENTRY_INTEL(bsf_u32, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1492 ENTRY_AMD( bsr_u32, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1493 ENTRY_INTEL(bsr_u32, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1494 ENTRY_AMD( imul_two_u32, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
1495 ENTRY_INTEL(imul_two_u32, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
1496};
1497TEST_BINARY_OPS(32, uint32_t, "%#010RX32", BINU32_TEST_T, g_aBinU32)
1498
1499
1500/*
1501 * 64-bit binary operations.
1502 */
1503static const BINU64_T g_aBinU64[] =
1504{
1505 ENTRY(add_u64),
1506 ENTRY(add_u64_locked),
1507 ENTRY(adc_u64),
1508 ENTRY(adc_u64_locked),
1509 ENTRY(sub_u64),
1510 ENTRY(sub_u64_locked),
1511 ENTRY(sbb_u64),
1512 ENTRY(sbb_u64_locked),
1513 ENTRY(or_u64),
1514 ENTRY(or_u64_locked),
1515 ENTRY(xor_u64),
1516 ENTRY(xor_u64_locked),
1517 ENTRY(and_u64),
1518 ENTRY(and_u64_locked),
1519 ENTRY_PFN_CAST(cmp_u64, PFNIEMAIMPLBINU64),
1520 ENTRY_PFN_CAST(test_u64, PFNIEMAIMPLBINU64),
1521 ENTRY_PFN_CAST_EX(bt_u64, PFNIEMAIMPLBINU64, 1),
1522 ENTRY_EX(btc_u64, 1),
1523 ENTRY_EX(btc_u64_locked, 1),
1524 ENTRY_EX(btr_u64, 1),
1525 ENTRY_EX(btr_u64_locked, 1),
1526 ENTRY_EX(bts_u64, 1),
1527 ENTRY_EX(bts_u64_locked, 1),
1528 ENTRY_AMD( bsf_u64, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1529 ENTRY_INTEL(bsf_u64, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1530 ENTRY_AMD( bsr_u64, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1531 ENTRY_INTEL(bsr_u64, X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF),
1532 ENTRY_AMD( imul_two_u64, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
1533 ENTRY_INTEL(imul_two_u64, X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF),
1534};
1535TEST_BINARY_OPS(64, uint64_t, "%#018RX64", BINU64_TEST_T, g_aBinU64)
1536
1537
1538/*
1539 * XCHG
1540 */
1541static void XchgTest(void)
1542{
1543 if (!SubTestAndCheckIfEnabled("xchg"))
1544 return;
1545 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU8, (uint8_t *pu8Mem, uint8_t *pu8Reg));
1546 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU16,(uint16_t *pu16Mem, uint16_t *pu16Reg));
1547 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU32,(uint32_t *pu32Mem, uint32_t *pu32Reg));
1548 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXCHGU64,(uint64_t *pu64Mem, uint64_t *pu64Reg));
1549
1550 static struct
1551 {
1552 uint8_t cb; uint64_t fMask;
1553 union
1554 {
1555 uintptr_t pfn;
1556 FNIEMAIMPLXCHGU8 *pfnU8;
1557 FNIEMAIMPLXCHGU16 *pfnU16;
1558 FNIEMAIMPLXCHGU32 *pfnU32;
1559 FNIEMAIMPLXCHGU64 *pfnU64;
1560 } u;
1561 }
1562 s_aXchgWorkers[] =
1563 {
1564 { 1, UINT8_MAX, { (uintptr_t)iemAImpl_xchg_u8_locked } },
1565 { 2, UINT16_MAX, { (uintptr_t)iemAImpl_xchg_u16_locked } },
1566 { 4, UINT32_MAX, { (uintptr_t)iemAImpl_xchg_u32_locked } },
1567 { 8, UINT64_MAX, { (uintptr_t)iemAImpl_xchg_u64_locked } },
1568 { 1, UINT8_MAX, { (uintptr_t)iemAImpl_xchg_u8_unlocked } },
1569 { 2, UINT16_MAX, { (uintptr_t)iemAImpl_xchg_u16_unlocked } },
1570 { 4, UINT32_MAX, { (uintptr_t)iemAImpl_xchg_u32_unlocked } },
1571 { 8, UINT64_MAX, { (uintptr_t)iemAImpl_xchg_u64_unlocked } },
1572 };
1573 for (size_t i = 0; i < RT_ELEMENTS(s_aXchgWorkers); i++)
1574 {
1575 RTUINT64U uIn1, uIn2, uMem, uDst;
1576 uMem.u = uIn1.u = RTRandU64Ex(0, s_aXchgWorkers[i].fMask);
1577 uDst.u = uIn2.u = RTRandU64Ex(0, s_aXchgWorkers[i].fMask);
1578 if (uIn1.u == uIn2.u)
1579 uDst.u = uIn2.u = ~uIn2.u;
1580
1581 switch (s_aXchgWorkers[i].cb)
1582 {
1583 case 1:
1584 s_aXchgWorkers[i].u.pfnU8(g_pu8, g_pu8Two);
1585 s_aXchgWorkers[i].u.pfnU8(&uMem.au8[0], &uDst.au8[0]);
1586 break;
1587 case 2:
1588 s_aXchgWorkers[i].u.pfnU16(g_pu16, g_pu16Two);
1589 s_aXchgWorkers[i].u.pfnU16(&uMem.Words.w0, &uDst.Words.w0);
1590 break;
1591 case 4:
1592 s_aXchgWorkers[i].u.pfnU32(g_pu32, g_pu32Two);
1593 s_aXchgWorkers[i].u.pfnU32(&uMem.DWords.dw0, &uDst.DWords.dw0);
1594 break;
1595 case 8:
1596 s_aXchgWorkers[i].u.pfnU64(g_pu64, g_pu64Two);
1597 s_aXchgWorkers[i].u.pfnU64(&uMem.u, &uDst.u);
1598 break;
1599 default: RTTestFailed(g_hTest, "%d\n", s_aXchgWorkers[i].cb); break;
1600 }
1601
1602 if (uMem.u != uIn2.u || uDst.u != uIn1.u)
1603 RTTestFailed(g_hTest, "i=%u: %#RX64, %#RX64 -> %#RX64, %#RX64\n", i, uIn1.u, uIn2.u, uMem.u, uDst.u);
1604 }
1605}
1606
1607
1608/*
1609 * XADD
1610 */
1611static void XaddTest(void)
1612{
1613#define TEST_XADD(a_cBits, a_Type, a_Fmt) do { \
1614 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLXADDU ## a_cBits, (a_Type *, a_Type *, uint32_t *)); \
1615 static struct \
1616 { \
1617 const char *pszName; \
1618 FNIEMAIMPLXADDU ## a_cBits *pfn; \
1619 BINU ## a_cBits ## _TEST_T const *paTests; \
1620 uint32_t const *pcTests; \
1621 } const s_aFuncs[] = \
1622 { \
1623 { "xadd_u" # a_cBits, iemAImpl_xadd_u ## a_cBits, \
1624 g_aTests_add_u ## a_cBits, &g_cTests_add_u ## a_cBits }, \
1625 { "xadd_u" # a_cBits "8_locked", iemAImpl_xadd_u ## a_cBits ## _locked, \
1626 g_aTests_add_u ## a_cBits, &g_cTests_add_u ## a_cBits }, \
1627 }; \
1628 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++) \
1629 { \
1630 if (!SubTestAndCheckIfEnabled(s_aFuncs[iFn].pszName)) continue; \
1631 uint32_t const cTests = *s_aFuncs[iFn].pcTests; \
1632 BINU ## a_cBits ## _TEST_T const * const paTests = s_aFuncs[iFn].paTests; \
1633 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
1634 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
1635 { \
1636 uint32_t fEfl = paTests[iTest].fEflIn; \
1637 a_Type uSrc = paTests[iTest].uSrcIn; \
1638 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
1639 s_aFuncs[iFn].pfn(g_pu ## a_cBits, &uSrc, &fEfl); \
1640 if ( fEfl != paTests[iTest].fEflOut \
1641 || *g_pu ## a_cBits != paTests[iTest].uDstOut \
1642 || uSrc != paTests[iTest].uDstIn) \
1643 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", \
1644 s_aFuncs[iFn].pszName, iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn, \
1645 fEfl, *g_pu ## a_cBits, uSrc, paTests[iTest].fEflOut, paTests[iTest].uDstOut, paTests[iTest].uDstIn, \
1646 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
1647 } \
1648 } \
1649 } while(0)
1650 TEST_XADD(8, uint8_t, "%#04x");
1651 TEST_XADD(16, uint16_t, "%#06x");
1652 TEST_XADD(32, uint32_t, "%#010RX32");
1653 TEST_XADD(64, uint64_t, "%#010RX64");
1654}
1655
1656
1657/*
1658 * CMPXCHG
1659 */
1660
1661static void CmpXchgTest(void)
1662{
1663#define TEST_CMPXCHG(a_cBits, a_Type, a_Fmt) do {\
1664 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLCMPXCHGU ## a_cBits, (a_Type *, a_Type *, a_Type, uint32_t *)); \
1665 static struct \
1666 { \
1667 const char *pszName; \
1668 FNIEMAIMPLCMPXCHGU ## a_cBits *pfn; \
1669 PFNIEMAIMPLBINU ## a_cBits pfnSub; \
1670 BINU ## a_cBits ## _TEST_T const *paTests; \
1671 uint32_t const *pcTests; \
1672 } const s_aFuncs[] = \
1673 { \
1674 { "cmpxchg_u" # a_cBits, iemAImpl_cmpxchg_u ## a_cBits, iemAImpl_sub_u ## a_cBits, \
1675 g_aTests_cmp_u ## a_cBits, &g_cTests_cmp_u ## a_cBits }, \
1676 { "cmpxchg_u" # a_cBits "_locked", iemAImpl_cmpxchg_u ## a_cBits ## _locked, iemAImpl_sub_u ## a_cBits, \
1677 g_aTests_cmp_u ## a_cBits, &g_cTests_cmp_u ## a_cBits }, \
1678 }; \
1679 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++) \
1680 { \
1681 if (!SubTestAndCheckIfEnabled(s_aFuncs[iFn].pszName)) continue; \
1682 BINU ## a_cBits ## _TEST_T const * const paTests = s_aFuncs[iFn].paTests; \
1683 uint32_t const cTests = *s_aFuncs[iFn].pcTests; \
1684 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
1685 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
1686 { \
1687 /* as is (99% likely to be negative). */ \
1688 uint32_t fEfl = paTests[iTest].fEflIn; \
1689 a_Type const uNew = paTests[iTest].uSrcIn + 0x42; \
1690 a_Type uA = paTests[iTest].uDstIn; \
1691 *g_pu ## a_cBits = paTests[iTest].uSrcIn; \
1692 a_Type const uExpect = uA != paTests[iTest].uSrcIn ? paTests[iTest].uSrcIn : uNew; \
1693 s_aFuncs[iFn].pfn(g_pu ## a_cBits, &uA, uNew, &fEfl); \
1694 if ( fEfl != paTests[iTest].fEflOut \
1695 || *g_pu ## a_cBits != uExpect \
1696 || uA != paTests[iTest].uSrcIn) \
1697 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", \
1698 s_aFuncs[iFn].pszName, iTest, paTests[iTest].fEflIn, paTests[iTest].uSrcIn, paTests[iTest].uDstIn, \
1699 uNew, fEfl, *g_pu ## a_cBits, uA, paTests[iTest].fEflOut, uExpect, paTests[iTest].uSrcIn, \
1700 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
1701 /* positive */ \
1702 uint32_t fEflExpect = paTests[iTest].fEflIn; \
1703 uA = paTests[iTest].uDstIn; \
1704 s_aFuncs[iFn].pfnSub(&uA, uA, &fEflExpect); \
1705 fEfl = paTests[iTest].fEflIn; \
1706 uA = paTests[iTest].uDstIn; \
1707 *g_pu ## a_cBits = uA; \
1708 s_aFuncs[iFn].pfn(g_pu ## a_cBits, &uA, uNew, &fEfl); \
1709 if ( fEfl != fEflExpect \
1710 || *g_pu ## a_cBits != uNew \
1711 || uA != paTests[iTest].uDstIn) \
1712 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", \
1713 s_aFuncs[iFn].pszName, iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uDstIn, \
1714 uNew, fEfl, *g_pu ## a_cBits, uA, fEflExpect, uNew, paTests[iTest].uDstIn, \
1715 EFlagsDiff(fEfl, fEflExpect)); \
1716 } \
1717 } \
1718 } while(0)
1719 TEST_CMPXCHG(8, uint8_t, "%#04RX8");
1720 TEST_CMPXCHG(16, uint16_t, "%#06x");
1721 TEST_CMPXCHG(32, uint32_t, "%#010RX32");
1722#if ARCH_BITS != 32 /* calling convension issue, skipping as it's an unsupported host */
1723 TEST_CMPXCHG(64, uint64_t, "%#010RX64");
1724#endif
1725}
1726
1727static void CmpXchg8bTest(void)
1728{
1729 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLCMPXCHG8B,(uint64_t *, PRTUINT64U, PRTUINT64U, uint32_t *));
1730 static struct
1731 {
1732 const char *pszName;
1733 FNIEMAIMPLCMPXCHG8B *pfn;
1734 } const s_aFuncs[] =
1735 {
1736 { "cmpxchg8b", iemAImpl_cmpxchg8b },
1737 { "cmpxchg8b_locked", iemAImpl_cmpxchg8b_locked },
1738 };
1739 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++)
1740 {
1741 if (!SubTestAndCheckIfEnabled(s_aFuncs[iFn].pszName))
1742 continue;
1743 for (uint32_t iTest = 0; iTest < 4; iTest += 2)
1744 {
1745 uint64_t const uOldValue = RandU64();
1746 uint64_t const uNewValue = RandU64();
1747
1748 /* positive test. */
1749 RTUINT64U uA, uB;
1750 uB.u = uNewValue;
1751 uA.u = uOldValue;
1752 *g_pu64 = uOldValue;
1753 uint32_t fEflIn = RandEFlags();
1754 uint32_t fEfl = fEflIn;
1755 s_aFuncs[iFn].pfn(g_pu64, &uA, &uB, &fEfl);
1756 if ( fEfl != (fEflIn | X86_EFL_ZF)
1757 || *g_pu64 != uNewValue
1758 || uA.u != uOldValue)
1759 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",
1760 iTest, fEflIn, uOldValue, uOldValue, uNewValue,
1761 fEfl, *g_pu64, uA.u,
1762 (fEflIn | X86_EFL_ZF), uNewValue, uOldValue, EFlagsDiff(fEfl, fEflIn | X86_EFL_ZF));
1763 RTTEST_CHECK(g_hTest, uB.u == uNewValue);
1764
1765 /* negative */
1766 uint64_t const uExpect = ~uOldValue;
1767 *g_pu64 = uExpect;
1768 uA.u = uOldValue;
1769 uB.u = uNewValue;
1770 fEfl = fEflIn = RandEFlags();
1771 s_aFuncs[iFn].pfn(g_pu64, &uA, &uB, &fEfl);
1772 if ( fEfl != (fEflIn & ~X86_EFL_ZF)
1773 || *g_pu64 != uExpect
1774 || uA.u != uExpect)
1775 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",
1776 iTest + 1, fEflIn, uExpect, uOldValue, uNewValue,
1777 fEfl, *g_pu64, uA.u,
1778 (fEflIn & ~X86_EFL_ZF), uExpect, uExpect, EFlagsDiff(fEfl, fEflIn & ~X86_EFL_ZF));
1779 RTTEST_CHECK(g_hTest, uB.u == uNewValue);
1780 }
1781 }
1782}
1783
1784static void CmpXchg16bTest(void)
1785{
1786 typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLCMPXCHG16B,(PRTUINT128U, PRTUINT128U, PRTUINT128U, uint32_t *));
1787 static struct
1788 {
1789 const char *pszName;
1790 FNIEMAIMPLCMPXCHG16B *pfn;
1791 } const s_aFuncs[] =
1792 {
1793 { "cmpxchg16b", iemAImpl_cmpxchg16b },
1794 { "cmpxchg16b_locked", iemAImpl_cmpxchg16b_locked },
1795#if !defined(RT_ARCH_ARM64)
1796 { "cmpxchg16b_fallback", iemAImpl_cmpxchg16b_fallback },
1797#endif
1798 };
1799 for (size_t iFn = 0; iFn < RT_ELEMENTS(s_aFuncs); iFn++)
1800 {
1801 if (!SubTestAndCheckIfEnabled(s_aFuncs[iFn].pszName))
1802 continue;
1803#if !defined(IEM_WITHOUT_ASSEMBLY) && defined(RT_ARCH_AMD64)
1804 if (!(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_CX16))
1805 {
1806 RTTestSkipped(g_hTest, "no hardware cmpxchg16b");
1807 continue;
1808 }
1809#endif
1810 for (uint32_t iTest = 0; iTest < 4; iTest += 2)
1811 {
1812 RTUINT128U const uOldValue = RandU128();
1813 RTUINT128U const uNewValue = RandU128();
1814
1815 /* positive test. */
1816 RTUINT128U uA, uB;
1817 uB = uNewValue;
1818 uA = uOldValue;
1819 *g_pu128 = uOldValue;
1820 uint32_t fEflIn = RandEFlags();
1821 uint32_t fEfl = fEflIn;
1822 s_aFuncs[iFn].pfn(g_pu128, &uA, &uB, &fEfl);
1823 if ( fEfl != (fEflIn | X86_EFL_ZF)
1824 || g_pu128->s.Lo != uNewValue.s.Lo
1825 || g_pu128->s.Hi != uNewValue.s.Hi
1826 || uA.s.Lo != uOldValue.s.Lo
1827 || uA.s.Hi != uOldValue.s.Hi)
1828 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=%#018RX64'%016RX64 cmp=%#018RX64'%016RX64 new=%#018RX64'%016RX64\n"
1829 " -> efl=%#08x dst=%#018RX64'%016RX64 old=%#018RX64'%016RX64,\n"
1830 " wanted %#08x, %#018RX64'%016RX64, %#018RX64'%016RX64%s\n",
1831 iTest, fEflIn, uOldValue.s.Hi, uOldValue.s.Lo, uOldValue.s.Hi, uOldValue.s.Lo, uNewValue.s.Hi, uNewValue.s.Lo,
1832 fEfl, g_pu128->s.Hi, g_pu128->s.Lo, uA.s.Hi, uA.s.Lo,
1833 (fEflIn | X86_EFL_ZF), uNewValue.s.Hi, uNewValue.s.Lo, uOldValue.s.Hi, uOldValue.s.Lo,
1834 EFlagsDiff(fEfl, fEflIn | X86_EFL_ZF));
1835 RTTEST_CHECK(g_hTest, uB.s.Lo == uNewValue.s.Lo && uB.s.Hi == uNewValue.s.Hi);
1836
1837 /* negative */
1838 RTUINT128U const uExpect = RTUINT128_INIT(~uOldValue.s.Hi, ~uOldValue.s.Lo);
1839 *g_pu128 = uExpect;
1840 uA = uOldValue;
1841 uB = uNewValue;
1842 fEfl = fEflIn = RandEFlags();
1843 s_aFuncs[iFn].pfn(g_pu128, &uA, &uB, &fEfl);
1844 if ( fEfl != (fEflIn & ~X86_EFL_ZF)
1845 || g_pu128->s.Lo != uExpect.s.Lo
1846 || g_pu128->s.Hi != uExpect.s.Hi
1847 || uA.s.Lo != uExpect.s.Lo
1848 || uA.s.Hi != uExpect.s.Hi)
1849 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=%#018RX64'%016RX64 cmp=%#018RX64'%016RX64 new=%#018RX64'%016RX64\n"
1850 " -> efl=%#08x dst=%#018RX64'%016RX64 old=%#018RX64'%016RX64,\n"
1851 " wanted %#08x, %#018RX64'%016RX64, %#018RX64'%016RX64%s\n",
1852 iTest + 1, fEflIn, uExpect.s.Hi, uExpect.s.Lo, uOldValue.s.Hi, uOldValue.s.Lo, uNewValue.s.Hi, uNewValue.s.Lo,
1853 fEfl, g_pu128->s.Hi, g_pu128->s.Lo, uA.s.Hi, uA.s.Lo,
1854 (fEflIn & ~X86_EFL_ZF), uExpect.s.Hi, uExpect.s.Lo, uExpect.s.Hi, uExpect.s.Lo,
1855 EFlagsDiff(fEfl, fEflIn & ~X86_EFL_ZF));
1856 RTTEST_CHECK(g_hTest, uB.s.Lo == uNewValue.s.Lo && uB.s.Hi == uNewValue.s.Hi);
1857 }
1858 }
1859}
1860
1861
1862/*
1863 * Double shifts.
1864 *
1865 * Note! We use BINUxx_TEST_T with the shift value in the uMisc field.
1866 */
1867#ifdef TSTIEMAIMPL_WITH_GENERATOR
1868# define GEN_SHIFT_DBL(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
1869static void ShiftDblU ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
1870{ \
1871 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
1872 { \
1873 if ( a_aSubTests[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE \
1874 && a_aSubTests[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour) \
1875 continue; \
1876 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
1877 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1878 { \
1879 a_TestType Test; \
1880 Test.fEflIn = RandEFlags(); \
1881 Test.fEflOut = Test.fEflIn; \
1882 Test.uDstIn = RandU ## a_cBits ## Dst(iTest); \
1883 Test.uDstOut = Test.uDstIn; \
1884 Test.uSrcIn = RandU ## a_cBits ## Src(iTest); \
1885 Test.uMisc = RandU8() & (a_cBits * 4 - 1); /* need to go way beyond the a_cBits limit */ \
1886 a_aSubTests[iFn].pfnNative(&Test.uDstOut, Test.uSrcIn, Test.uMisc, &Test.fEflOut); \
1887 RTStrmPrintf(pOut, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", " a_Fmt ", %2u }, /* #%u */\n", \
1888 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uSrcIn, Test.uMisc, iTest); \
1889 } \
1890 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
1891 } \
1892}
1893#else
1894# define GEN_SHIFT_DBL(a_cBits, a_Fmt, a_TestType, a_aSubTests)
1895#endif
1896
1897#define TEST_SHIFT_DBL(a_cBits, a_Type, a_Fmt, a_TestType, a_SubTestType, a_aSubTests) \
1898TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLSHIFTDBLU ## a_cBits); \
1899\
1900static a_SubTestType const a_aSubTests[] = \
1901{ \
1902 ENTRY_AMD(shld_u ## a_cBits, X86_EFL_OF | X86_EFL_CF), \
1903 ENTRY_INTEL(shld_u ## a_cBits, X86_EFL_OF | X86_EFL_CF), \
1904 ENTRY_AMD(shrd_u ## a_cBits, X86_EFL_OF | X86_EFL_CF), \
1905 ENTRY_INTEL(shrd_u ## a_cBits, X86_EFL_OF | X86_EFL_CF), \
1906}; \
1907\
1908GEN_SHIFT_DBL(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
1909\
1910static void ShiftDblU ## a_cBits ## Test(void) \
1911{ \
1912 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
1913 { \
1914 if (!SubTestAndCheckIfEnabled(a_aSubTests[iFn].pszName)) continue; \
1915 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
1916 PFNIEMAIMPLSHIFTDBLU ## a_cBits pfn = a_aSubTests[iFn].pfn; \
1917 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
1918 uint32_t const cVars = COUNT_VARIATIONS(a_aSubTests[iFn]); \
1919 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
1920 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
1921 { \
1922 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1923 { \
1924 uint32_t fEfl = paTests[iTest].fEflIn; \
1925 a_Type uDst = paTests[iTest].uDstIn; \
1926 pfn(&uDst, paTests[iTest].uSrcIn, paTests[iTest].uMisc, &fEfl); \
1927 if ( uDst != paTests[iTest].uDstOut \
1928 || fEfl != paTests[iTest].fEflOut) \
1929 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", \
1930 iTest, iVar == 0 ? "" : "/n", paTests[iTest].fEflIn, \
1931 paTests[iTest].uDstIn, paTests[iTest].uSrcIn, (unsigned)paTests[iTest].uMisc, \
1932 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut, \
1933 EFlagsDiff(fEfl, paTests[iTest].fEflOut), uDst == paTests[iTest].uDstOut ? "" : " dst!"); \
1934 else \
1935 { \
1936 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
1937 *g_pfEfl = paTests[iTest].fEflIn; \
1938 pfn(g_pu ## a_cBits, paTests[iTest].uSrcIn, paTests[iTest].uMisc, g_pfEfl); \
1939 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDstOut); \
1940 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut); \
1941 } \
1942 } \
1943 pfn = a_aSubTests[iFn].pfnNative; \
1944 } \
1945 } \
1946}
1947TEST_SHIFT_DBL(16, uint16_t, "%#06RX16", BINU16_TEST_T, SHIFT_DBL_U16_T, g_aShiftDblU16)
1948TEST_SHIFT_DBL(32, uint32_t, "%#010RX32", BINU32_TEST_T, SHIFT_DBL_U32_T, g_aShiftDblU32)
1949TEST_SHIFT_DBL(64, uint64_t, "%#018RX64", BINU64_TEST_T, SHIFT_DBL_U64_T, g_aShiftDblU64)
1950
1951#ifdef TSTIEMAIMPL_WITH_GENERATOR
1952static void ShiftDblGenerate(PRTSTREAM pOut, uint32_t cTests)
1953{
1954 ShiftDblU16Generate(pOut, cTests);
1955 ShiftDblU32Generate(pOut, cTests);
1956 ShiftDblU64Generate(pOut, cTests);
1957}
1958#endif
1959
1960static void ShiftDblTest(void)
1961{
1962 ShiftDblU16Test();
1963 ShiftDblU32Test();
1964 ShiftDblU64Test();
1965}
1966
1967
1968/*
1969 * Unary operators.
1970 *
1971 * Note! We use BINUxx_TEST_T ignoreing uSrcIn and uMisc.
1972 */
1973#ifdef TSTIEMAIMPL_WITH_GENERATOR
1974# define GEN_UNARY(a_cBits, a_Type, a_Fmt, a_TestType, a_SubTestType) \
1975static void UnaryU ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
1976{ \
1977 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aUnaryU ## a_cBits); iFn++) \
1978 { \
1979 GenerateArrayStart(pOut, g_aUnaryU ## a_cBits[iFn].pszName, #a_TestType); \
1980 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
1981 { \
1982 a_TestType Test; \
1983 Test.fEflIn = RandEFlags(); \
1984 Test.fEflOut = Test.fEflIn; \
1985 Test.uDstIn = RandU ## a_cBits(); \
1986 Test.uDstOut = Test.uDstIn; \
1987 Test.uSrcIn = 0; \
1988 Test.uMisc = 0; \
1989 g_aUnaryU ## a_cBits[iFn].pfn(&Test.uDstOut, &Test.fEflOut); \
1990 RTStrmPrintf(pOut, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", 0, 0 }, /* #%u */\n", \
1991 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, iTest); \
1992 } \
1993 GenerateArrayEnd(pOut, g_aUnaryU ## a_cBits[iFn].pszName); \
1994 } \
1995}
1996#else
1997# define GEN_UNARY(a_cBits, a_Type, a_Fmt, a_TestType, a_SubTestType)
1998#endif
1999
2000#define TEST_UNARY(a_cBits, a_Type, a_Fmt, a_TestType, a_SubTestType) \
2001TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLUNARYU ## a_cBits); \
2002static a_SubTestType const g_aUnaryU ## a_cBits [] = \
2003{ \
2004 ENTRY(inc_u ## a_cBits), \
2005 ENTRY(inc_u ## a_cBits ## _locked), \
2006 ENTRY(dec_u ## a_cBits), \
2007 ENTRY(dec_u ## a_cBits ## _locked), \
2008 ENTRY(not_u ## a_cBits), \
2009 ENTRY(not_u ## a_cBits ## _locked), \
2010 ENTRY(neg_u ## a_cBits), \
2011 ENTRY(neg_u ## a_cBits ## _locked), \
2012}; \
2013\
2014GEN_UNARY(a_cBits, a_Type, a_Fmt, a_TestType, a_SubTestType) \
2015\
2016static void UnaryU ## a_cBits ## Test(void) \
2017{ \
2018 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aUnaryU ## a_cBits); iFn++) \
2019 { \
2020 if (!SubTestAndCheckIfEnabled(g_aUnaryU ## a_cBits[iFn].pszName)) continue; \
2021 a_TestType const * const paTests = g_aUnaryU ## a_cBits[iFn].paTests; \
2022 uint32_t const cTests = *g_aUnaryU ## a_cBits[iFn].pcTests; \
2023 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
2024 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
2025 { \
2026 uint32_t fEfl = paTests[iTest].fEflIn; \
2027 a_Type uDst = paTests[iTest].uDstIn; \
2028 g_aUnaryU ## a_cBits[iFn].pfn(&uDst, &fEfl); \
2029 if ( uDst != paTests[iTest].uDstOut \
2030 || fEfl != paTests[iTest].fEflOut) \
2031 RTTestFailed(g_hTest, "#%u: efl=%#08x dst=" a_Fmt " -> efl=%#08x dst=" a_Fmt ", expected %#08x & " a_Fmt "%s\n", \
2032 iTest, paTests[iTest].fEflIn, paTests[iTest].uDstIn, \
2033 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut, \
2034 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
2035 else \
2036 { \
2037 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
2038 *g_pfEfl = paTests[iTest].fEflIn; \
2039 g_aUnaryU ## a_cBits[iFn].pfn(g_pu ## a_cBits, g_pfEfl); \
2040 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDstOut); \
2041 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut); \
2042 } \
2043 } \
2044 } \
2045}
2046TEST_UNARY(8, uint8_t, "%#04RX8", BINU8_TEST_T, INT_UNARY_U8_T)
2047TEST_UNARY(16, uint16_t, "%#06RX16", BINU16_TEST_T, INT_UNARY_U16_T)
2048TEST_UNARY(32, uint32_t, "%#010RX32", BINU32_TEST_T, INT_UNARY_U32_T)
2049TEST_UNARY(64, uint64_t, "%#018RX64", BINU64_TEST_T, INT_UNARY_U64_T)
2050
2051#ifdef TSTIEMAIMPL_WITH_GENERATOR
2052static void UnaryGenerate(PRTSTREAM pOut, uint32_t cTests)
2053{
2054 UnaryU8Generate(pOut, cTests);
2055 UnaryU16Generate(pOut, cTests);
2056 UnaryU32Generate(pOut, cTests);
2057 UnaryU64Generate(pOut, cTests);
2058}
2059#endif
2060
2061static void UnaryTest(void)
2062{
2063 UnaryU8Test();
2064 UnaryU16Test();
2065 UnaryU32Test();
2066 UnaryU64Test();
2067}
2068
2069
2070/*
2071 * Shifts.
2072 *
2073 * Note! We use BINUxx_TEST_T with the shift count in uMisc and uSrcIn unused.
2074 */
2075#ifdef TSTIEMAIMPL_WITH_GENERATOR
2076# define GEN_SHIFT(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
2077static void ShiftU ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
2078{ \
2079 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2080 { \
2081 if ( a_aSubTests[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE \
2082 && a_aSubTests[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour) \
2083 continue; \
2084 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
2085 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
2086 { \
2087 a_TestType Test; \
2088 Test.fEflIn = RandEFlags(); \
2089 Test.fEflOut = Test.fEflIn; \
2090 Test.uDstIn = RandU ## a_cBits ## Dst(iTest); \
2091 Test.uDstOut = Test.uDstIn; \
2092 Test.uSrcIn = 0; \
2093 Test.uMisc = RandU8() & (a_cBits * 4 - 1); /* need to go way beyond the a_cBits limit */ \
2094 a_aSubTests[iFn].pfnNative(&Test.uDstOut, Test.uMisc, &Test.fEflOut); \
2095 RTStrmPrintf(pOut, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", 0, %-2u }, /* #%u */\n", \
2096 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uMisc, iTest); \
2097 \
2098 Test.fEflIn = (~Test.fEflIn & X86_EFL_LIVE_MASK) | X86_EFL_RA1_MASK; \
2099 Test.fEflOut = Test.fEflIn; \
2100 Test.uDstOut = Test.uDstIn; \
2101 a_aSubTests[iFn].pfnNative(&Test.uDstOut, Test.uMisc, &Test.fEflOut); \
2102 RTStrmPrintf(pOut, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", 0, %-2u }, /* #%u b */\n", \
2103 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uMisc, iTest); \
2104 } \
2105 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
2106 } \
2107}
2108#else
2109# define GEN_SHIFT(a_cBits, a_Fmt, a_TestType, a_aSubTests)
2110#endif
2111
2112#define TEST_SHIFT(a_cBits, a_Type, a_Fmt, a_TestType, a_SubTestType, a_aSubTests) \
2113TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLSHIFTU ## a_cBits); \
2114static a_SubTestType const a_aSubTests[] = \
2115{ \
2116 ENTRY_AMD( rol_u ## a_cBits, X86_EFL_OF), \
2117 ENTRY_INTEL(rol_u ## a_cBits, X86_EFL_OF), \
2118 ENTRY_AMD( ror_u ## a_cBits, X86_EFL_OF), \
2119 ENTRY_INTEL(ror_u ## a_cBits, X86_EFL_OF), \
2120 ENTRY_AMD( rcl_u ## a_cBits, X86_EFL_OF), \
2121 ENTRY_INTEL(rcl_u ## a_cBits, X86_EFL_OF), \
2122 ENTRY_AMD( rcr_u ## a_cBits, X86_EFL_OF), \
2123 ENTRY_INTEL(rcr_u ## a_cBits, X86_EFL_OF), \
2124 ENTRY_AMD( shl_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
2125 ENTRY_INTEL(shl_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
2126 ENTRY_AMD( shr_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
2127 ENTRY_INTEL(shr_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
2128 ENTRY_AMD( sar_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
2129 ENTRY_INTEL(sar_u ## a_cBits, X86_EFL_OF | X86_EFL_AF), \
2130}; \
2131\
2132GEN_SHIFT(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
2133\
2134static void ShiftU ## a_cBits ## Test(void) \
2135{ \
2136 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2137 { \
2138 if (!SubTestAndCheckIfEnabled(a_aSubTests[iFn].pszName)) continue; \
2139 PFNIEMAIMPLSHIFTU ## a_cBits pfn = a_aSubTests[iFn].pfn; \
2140 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
2141 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
2142 uint32_t const cVars = COUNT_VARIATIONS(a_aSubTests[iFn]); \
2143 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
2144 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
2145 { \
2146 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
2147 { \
2148 uint32_t fEfl = paTests[iTest].fEflIn; \
2149 a_Type uDst = paTests[iTest].uDstIn; \
2150 pfn(&uDst, paTests[iTest].uMisc, &fEfl); \
2151 if ( uDst != paTests[iTest].uDstOut \
2152 || fEfl != paTests[iTest].fEflOut ) \
2153 RTTestFailed(g_hTest, "#%u%s: efl=%#08x dst=" a_Fmt " shift=%2u -> efl=%#08x dst=" a_Fmt ", expected %#08x & " a_Fmt "%s\n", \
2154 iTest, iVar == 0 ? "" : "/n", \
2155 paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uMisc, \
2156 fEfl, uDst, paTests[iTest].fEflOut, paTests[iTest].uDstOut, \
2157 EFlagsDiff(fEfl, paTests[iTest].fEflOut)); \
2158 else \
2159 { \
2160 *g_pu ## a_cBits = paTests[iTest].uDstIn; \
2161 *g_pfEfl = paTests[iTest].fEflIn; \
2162 pfn(g_pu ## a_cBits, paTests[iTest].uMisc, g_pfEfl); \
2163 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDstOut); \
2164 RTTEST_CHECK(g_hTest, *g_pfEfl == paTests[iTest].fEflOut); \
2165 } \
2166 } \
2167 pfn = a_aSubTests[iFn].pfnNative; \
2168 } \
2169 } \
2170}
2171TEST_SHIFT(8, uint8_t, "%#04RX8", BINU8_TEST_T, INT_BINARY_U8_T, g_aShiftU8)
2172TEST_SHIFT(16, uint16_t, "%#06RX16", BINU16_TEST_T, INT_BINARY_U16_T, g_aShiftU16)
2173TEST_SHIFT(32, uint32_t, "%#010RX32", BINU32_TEST_T, INT_BINARY_U32_T, g_aShiftU32)
2174TEST_SHIFT(64, uint64_t, "%#018RX64", BINU64_TEST_T, INT_BINARY_U64_T, g_aShiftU64)
2175
2176#ifdef TSTIEMAIMPL_WITH_GENERATOR
2177static void ShiftGenerate(PRTSTREAM pOut, uint32_t cTests)
2178{
2179 ShiftU8Generate(pOut, cTests);
2180 ShiftU16Generate(pOut, cTests);
2181 ShiftU32Generate(pOut, cTests);
2182 ShiftU64Generate(pOut, cTests);
2183}
2184#endif
2185
2186static void ShiftTest(void)
2187{
2188 ShiftU8Test();
2189 ShiftU16Test();
2190 ShiftU32Test();
2191 ShiftU64Test();
2192}
2193
2194
2195/*
2196 * Multiplication and division.
2197 *
2198 * Note! The 8-bit functions has a different format, so we need to duplicate things.
2199 * Note! Currently ignoring undefined bits.
2200 */
2201
2202/* U8 */
2203TYPEDEF_SUBTEST_TYPE(INT_MULDIV_U8_T, MULDIVU8_TEST_T, PFNIEMAIMPLMULDIVU8);
2204static INT_MULDIV_U8_T const g_aMulDivU8[] =
2205{
2206 ENTRY_AMD_EX(mul_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF,
2207 X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF),
2208 ENTRY_INTEL_EX(mul_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0),
2209 ENTRY_AMD_EX(imul_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF,
2210 X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF),
2211 ENTRY_INTEL_EX(imul_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0),
2212 ENTRY_AMD_EX(div_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0),
2213 ENTRY_INTEL_EX(div_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0),
2214 ENTRY_AMD_EX(idiv_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0),
2215 ENTRY_INTEL_EX(idiv_u8, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF | X86_EFL_CF | X86_EFL_OF, 0),
2216};
2217
2218#ifdef TSTIEMAIMPL_WITH_GENERATOR
2219static void MulDivU8Generate(PRTSTREAM pOut, uint32_t cTests)
2220{
2221 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aMulDivU8); iFn++)
2222 {
2223 if ( g_aMulDivU8[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE
2224 && g_aMulDivU8[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour)
2225 continue;
2226 GenerateArrayStart(pOut, g_aMulDivU8[iFn].pszName, "MULDIVU8_TEST_T"); \
2227 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
2228 {
2229 MULDIVU8_TEST_T Test;
2230 Test.fEflIn = RandEFlags();
2231 Test.fEflOut = Test.fEflIn;
2232 Test.uDstIn = RandU16Dst(iTest);
2233 Test.uDstOut = Test.uDstIn;
2234 Test.uSrcIn = RandU8Src(iTest);
2235 Test.rc = g_aMulDivU8[iFn].pfnNative(&Test.uDstOut, Test.uSrcIn, &Test.fEflOut);
2236 RTStrmPrintf(pOut, " { %#08x, %#08x, %#06RX16, %#06RX16, %#04RX8, %d }, /* #%u */\n",
2237 Test.fEflIn, Test.fEflOut, Test.uDstIn, Test.uDstOut, Test.uSrcIn, Test.rc, iTest);
2238 }
2239 GenerateArrayEnd(pOut, g_aMulDivU8[iFn].pszName);
2240 }
2241}
2242#endif
2243
2244static void MulDivU8Test(void)
2245{
2246 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aMulDivU8); iFn++)
2247 {
2248 if (!SubTestAndCheckIfEnabled(g_aMulDivU8[iFn].pszName)) continue; \
2249 MULDIVU8_TEST_T const * const paTests = g_aMulDivU8[iFn].paTests;
2250 uint32_t const cTests = *g_aMulDivU8[iFn].pcTests;
2251 uint32_t const fEflIgn = g_aMulDivU8[iFn].uExtra;
2252 PFNIEMAIMPLMULDIVU8 pfn = g_aMulDivU8[iFn].pfn;
2253 uint32_t const cVars = COUNT_VARIATIONS(g_aMulDivU8[iFn]); \
2254 if (!cTests) RTTestSkipped(g_hTest, "no tests");
2255 for (uint32_t iVar = 0; iVar < cVars; iVar++)
2256 {
2257 for (uint32_t iTest = 0; iTest < cTests; iTest++ )
2258 {
2259 uint32_t fEfl = paTests[iTest].fEflIn;
2260 uint16_t uDst = paTests[iTest].uDstIn;
2261 int rc = g_aMulDivU8[iFn].pfn(&uDst, paTests[iTest].uSrcIn, &fEfl);
2262 if ( uDst != paTests[iTest].uDstOut
2263 || (fEfl | fEflIgn) != (paTests[iTest].fEflOut | fEflIgn)
2264 || rc != paTests[iTest].rc)
2265 RTTestFailed(g_hTest, "#%02u%s: efl=%#08x dst=%#06RX16 src=%#04RX8\n"
2266 " %s-> efl=%#08x dst=%#06RX16 rc=%d\n"
2267 "%sexpected %#08x %#06RX16 %d%s\n",
2268 iTest, iVar ? "/n" : "", paTests[iTest].fEflIn, paTests[iTest].uDstIn, paTests[iTest].uSrcIn,
2269 iVar ? " " : "", fEfl, uDst, rc,
2270 iVar ? " " : "", paTests[iTest].fEflOut, paTests[iTest].uDstOut, paTests[iTest].rc,
2271 EFlagsDiff(fEfl | fEflIgn, paTests[iTest].fEflOut | fEflIgn));
2272 else
2273 {
2274 *g_pu16 = paTests[iTest].uDstIn;
2275 *g_pfEfl = paTests[iTest].fEflIn;
2276 rc = g_aMulDivU8[iFn].pfn(g_pu16, paTests[iTest].uSrcIn, g_pfEfl);
2277 RTTEST_CHECK(g_hTest, *g_pu16 == paTests[iTest].uDstOut);
2278 RTTEST_CHECK(g_hTest, (*g_pfEfl | fEflIgn) == (paTests[iTest].fEflOut | fEflIgn));
2279 RTTEST_CHECK(g_hTest, rc == paTests[iTest].rc);
2280 }
2281 }
2282 pfn = g_aMulDivU8[iFn].pfnNative;
2283 }
2284 }
2285}
2286
2287#ifdef TSTIEMAIMPL_WITH_GENERATOR
2288# define GEN_MULDIV(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
2289void MulDivU ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
2290{ \
2291 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2292 { \
2293 if ( a_aSubTests[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE \
2294 && a_aSubTests[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour) \
2295 continue; \
2296 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
2297 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
2298 { \
2299 a_TestType Test; \
2300 Test.fEflIn = RandEFlags(); \
2301 Test.fEflOut = Test.fEflIn; \
2302 Test.uDst1In = RandU ## a_cBits ## Dst(iTest); \
2303 Test.uDst1Out = Test.uDst1In; \
2304 Test.uDst2In = RandU ## a_cBits ## Dst(iTest); \
2305 Test.uDst2Out = Test.uDst2In; \
2306 Test.uSrcIn = RandU ## a_cBits ## Src(iTest); \
2307 Test.rc = a_aSubTests[iFn].pfnNative(&Test.uDst1Out, &Test.uDst2Out, Test.uSrcIn, &Test.fEflOut); \
2308 RTStrmPrintf(pOut, " { %#08x, %#08x, " a_Fmt ", " a_Fmt ", " a_Fmt ", " a_Fmt ", " a_Fmt ", %d }, /* #%u */\n", \
2309 Test.fEflIn, Test.fEflOut, Test.uDst1In, Test.uDst1Out, Test.uDst2In, Test.uDst2Out, Test.uSrcIn, \
2310 Test.rc, iTest); \
2311 } \
2312 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
2313 } \
2314}
2315#else
2316# define GEN_MULDIV(a_cBits, a_Fmt, a_TestType, a_aSubTests)
2317#endif
2318
2319#define TEST_MULDIV(a_cBits, a_Type, a_Fmt, a_TestType, a_SubTestType, a_aSubTests) \
2320TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLMULDIVU ## a_cBits); \
2321static a_SubTestType const a_aSubTests [] = \
2322{ \
2323 ENTRY_AMD_EX(mul_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0), \
2324 ENTRY_INTEL_EX(mul_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0), \
2325 ENTRY_AMD_EX(imul_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0), \
2326 ENTRY_INTEL_EX(imul_u ## a_cBits, X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF, 0), \
2327 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), \
2328 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), \
2329 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), \
2330 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), \
2331}; \
2332\
2333GEN_MULDIV(a_cBits, a_Fmt, a_TestType, a_aSubTests) \
2334\
2335static void MulDivU ## a_cBits ## Test(void) \
2336{ \
2337 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2338 { \
2339 if (!SubTestAndCheckIfEnabled(a_aSubTests[iFn].pszName)) continue; \
2340 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
2341 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
2342 uint32_t const fEflIgn = a_aSubTests[iFn].uExtra; \
2343 PFNIEMAIMPLMULDIVU ## a_cBits pfn = a_aSubTests[iFn].pfn; \
2344 uint32_t const cVars = COUNT_VARIATIONS(a_aSubTests[iFn]); \
2345 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
2346 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
2347 { \
2348 for (uint32_t iTest = 0; iTest < cTests; iTest++ ) \
2349 { \
2350 uint32_t fEfl = paTests[iTest].fEflIn; \
2351 a_Type uDst1 = paTests[iTest].uDst1In; \
2352 a_Type uDst2 = paTests[iTest].uDst2In; \
2353 int rc = pfn(&uDst1, &uDst2, paTests[iTest].uSrcIn, &fEfl); \
2354 if ( uDst1 != paTests[iTest].uDst1Out \
2355 || uDst2 != paTests[iTest].uDst2Out \
2356 || (fEfl | fEflIgn) != (paTests[iTest].fEflOut | fEflIgn)\
2357 || rc != paTests[iTest].rc) \
2358 RTTestFailed(g_hTest, "#%02u%s: efl=%#08x dst1=" a_Fmt " dst2=" a_Fmt " src=" a_Fmt "\n" \
2359 " -> efl=%#08x dst1=" a_Fmt " dst2=" a_Fmt " rc=%d\n" \
2360 "expected %#08x " a_Fmt " " a_Fmt " %d%s -%s%s%s\n", \
2361 iTest, iVar == 0 ? "" : "/n", \
2362 paTests[iTest].fEflIn, paTests[iTest].uDst1In, paTests[iTest].uDst2In, paTests[iTest].uSrcIn, \
2363 fEfl, uDst1, uDst2, rc, \
2364 paTests[iTest].fEflOut, paTests[iTest].uDst1Out, paTests[iTest].uDst2Out, paTests[iTest].rc, \
2365 EFlagsDiff(fEfl | fEflIgn, paTests[iTest].fEflOut | fEflIgn), \
2366 uDst1 != paTests[iTest].uDst1Out ? " dst1" : "", uDst2 != paTests[iTest].uDst2Out ? " dst2" : "", \
2367 (fEfl | fEflIgn) != (paTests[iTest].fEflOut | fEflIgn) ? " eflags" : ""); \
2368 else \
2369 { \
2370 *g_pu ## a_cBits = paTests[iTest].uDst1In; \
2371 *g_pu ## a_cBits ## Two = paTests[iTest].uDst2In; \
2372 *g_pfEfl = paTests[iTest].fEflIn; \
2373 rc = pfn(g_pu ## a_cBits, g_pu ## a_cBits ## Two, paTests[iTest].uSrcIn, g_pfEfl); \
2374 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits == paTests[iTest].uDst1Out); \
2375 RTTEST_CHECK(g_hTest, *g_pu ## a_cBits ## Two == paTests[iTest].uDst2Out); \
2376 RTTEST_CHECK(g_hTest, (*g_pfEfl | fEflIgn) == (paTests[iTest].fEflOut | fEflIgn)); \
2377 RTTEST_CHECK(g_hTest, rc == paTests[iTest].rc); \
2378 } \
2379 } \
2380 pfn = a_aSubTests[iFn].pfnNative; \
2381 } \
2382 } \
2383}
2384TEST_MULDIV(16, uint16_t, "%#06RX16", MULDIVU16_TEST_T, INT_MULDIV_U16_T, g_aMulDivU16)
2385TEST_MULDIV(32, uint32_t, "%#010RX32", MULDIVU32_TEST_T, INT_MULDIV_U32_T, g_aMulDivU32)
2386TEST_MULDIV(64, uint64_t, "%#018RX64", MULDIVU64_TEST_T, INT_MULDIV_U64_T, g_aMulDivU64)
2387
2388#ifdef TSTIEMAIMPL_WITH_GENERATOR
2389static void MulDivGenerate(PRTSTREAM pOut, uint32_t cTests)
2390{
2391 MulDivU8Generate(pOut, cTests);
2392 MulDivU16Generate(pOut, cTests);
2393 MulDivU32Generate(pOut, cTests);
2394 MulDivU64Generate(pOut, cTests);
2395}
2396#endif
2397
2398static void MulDivTest(void)
2399{
2400 MulDivU8Test();
2401 MulDivU16Test();
2402 MulDivU32Test();
2403 MulDivU64Test();
2404}
2405
2406
2407/*
2408 * BSWAP
2409 */
2410static void BswapTest(void)
2411{
2412 if (SubTestAndCheckIfEnabled("bswap_u16"))
2413 {
2414 *g_pu32 = UINT32_C(0x12345678);
2415 iemAImpl_bswap_u16(g_pu32);
2416#if 0
2417 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0x12347856), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
2418#else
2419 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0x12340000), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
2420#endif
2421 *g_pu32 = UINT32_C(0xffff1122);
2422 iemAImpl_bswap_u16(g_pu32);
2423#if 0
2424 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0xffff2211), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
2425#else
2426 RTTEST_CHECK_MSG(g_hTest, *g_pu32 == UINT32_C(0xffff0000), (g_hTest, "*g_pu32=%#RX32\n", *g_pu32));
2427#endif
2428 }
2429
2430 if (SubTestAndCheckIfEnabled("bswap_u32"))
2431 {
2432 *g_pu32 = UINT32_C(0x12345678);
2433 iemAImpl_bswap_u32(g_pu32);
2434 RTTEST_CHECK(g_hTest, *g_pu32 == UINT32_C(0x78563412));
2435 }
2436
2437 if (SubTestAndCheckIfEnabled("bswap_u64"))
2438 {
2439 *g_pu64 = UINT64_C(0x0123456789abcdef);
2440 iemAImpl_bswap_u64(g_pu64);
2441 RTTEST_CHECK(g_hTest, *g_pu64 == UINT64_C(0xefcdab8967452301));
2442 }
2443}
2444
2445
2446
2447/*********************************************************************************************************************************
2448* Floating point (x87 style) *
2449*********************************************************************************************************************************/
2450
2451/*
2452 * FPU constant loading.
2453 */
2454TYPEDEF_SUBTEST_TYPE(FPU_LD_CONST_T, FPU_LD_CONST_TEST_T, PFNIEMAIMPLFPUR80LDCONST);
2455
2456static const FPU_LD_CONST_T g_aFpuLdConst[] =
2457{
2458 ENTRY(fld1),
2459 ENTRY(fldl2t),
2460 ENTRY(fldl2e),
2461 ENTRY(fldpi),
2462 ENTRY(fldlg2),
2463 ENTRY(fldln2),
2464 ENTRY(fldz),
2465};
2466
2467#ifdef TSTIEMAIMPL_WITH_GENERATOR
2468static void FpuLdConstGenerate(PRTSTREAM pOut, uint32_t cTests)
2469{
2470 X86FXSTATE State;
2471 RT_ZERO(State);
2472 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuLdConst); iFn++)
2473 {
2474 GenerateArrayStart(pOut, g_aFpuLdConst[iFn].pszName, "FPU_LD_CONST_TEST_T");
2475 for (uint32_t iTest = 0; iTest < cTests; iTest += 4)
2476 {
2477 State.FCW = RandFcw();
2478 State.FSW = RandFsw();
2479
2480 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
2481 {
2482 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 };
2483 State.FCW = (State.FCW & ~X86_FCW_RC_MASK) | (iRounding << X86_FCW_RC_SHIFT);
2484 g_aFpuLdConst[iFn].pfn(&State, &Res);
2485 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s }, /* #%u */\n",
2486 State.FCW, State.FSW, Res.FSW, GenFormatR80(&Res.r80Result), iTest + iRounding);
2487 }
2488 }
2489 GenerateArrayEnd(pOut, g_aFpuLdConst[iFn].pszName);
2490 }
2491}
2492#endif
2493
2494static void FpuLoadConstTest(void)
2495{
2496 /*
2497 * Inputs:
2498 * - FSW: C0, C1, C2, C3
2499 * - FCW: Exception masks, Precision control, Rounding control.
2500 *
2501 * C1 set to 1 on stack overflow, zero otherwise. C0, C2, and C3 are "undefined".
2502 */
2503 X86FXSTATE State;
2504 RT_ZERO(State);
2505 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuLdConst); iFn++)
2506 {
2507 if (!SubTestAndCheckIfEnabled(g_aFpuLdConst[iFn].pszName))
2508 continue;
2509
2510 uint32_t const cTests = *g_aFpuLdConst[iFn].pcTests;
2511 FPU_LD_CONST_TEST_T const *paTests = g_aFpuLdConst[iFn].paTests;
2512 PFNIEMAIMPLFPUR80LDCONST pfn = g_aFpuLdConst[iFn].pfn;
2513 uint32_t const cVars = COUNT_VARIATIONS(g_aFpuLdConst[iFn]); \
2514 if (!cTests) RTTestSkipped(g_hTest, "no tests");
2515 for (uint32_t iVar = 0; iVar < cVars; iVar++)
2516 {
2517 for (uint32_t iTest = 0; iTest < cTests; iTest++)
2518 {
2519 State.FCW = paTests[iTest].fFcw;
2520 State.FSW = paTests[iTest].fFswIn;
2521 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 };
2522 pfn(&State, &Res);
2523 if ( Res.FSW != paTests[iTest].fFswOut
2524 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult))
2525 RTTestFailed(g_hTest, "#%u%s: fcw=%#06x fsw=%#06x -> fsw=%#06x %s, expected %#06x %s%s%s (%s)\n",
2526 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
2527 Res.FSW, FormatR80(&Res.r80Result),
2528 paTests[iTest].fFswOut, FormatR80(&paTests[iTest].rdResult),
2529 FswDiff(Res.FSW, paTests[iTest].fFswOut),
2530 !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult) ? " - val" : "",
2531 FormatFcw(paTests[iTest].fFcw) );
2532 }
2533 pfn = g_aFpuLdConst[iFn].pfnNative;
2534 }
2535 }
2536}
2537
2538
2539/*
2540 * Load floating point values from memory.
2541 */
2542#ifdef TSTIEMAIMPL_WITH_GENERATOR
2543# define GEN_FPU_LOAD(a_cBits, a_rdTypeIn, a_aSubTests, a_TestType) \
2544static void FpuLdR ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
2545{ \
2546 X86FXSTATE State; \
2547 RT_ZERO(State); \
2548 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2549 { \
2550 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
2551 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
2552 { \
2553 State.FCW = RandFcw(); \
2554 State.FSW = RandFsw(); \
2555 a_rdTypeIn InVal = RandR ## a_cBits ## Src(iTest); \
2556 \
2557 for (uint16_t iRounding = 0; iRounding < 4; iRounding++) \
2558 { \
2559 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 }; \
2560 State.FCW = (State.FCW & ~X86_FCW_RC_MASK) | (iRounding << X86_FCW_RC_SHIFT); \
2561 a_aSubTests[iFn].pfn(&State, &Res, &InVal); \
2562 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u */\n", \
2563 State.FCW, State.FSW, Res.FSW, GenFormatR80(&Res.r80Result), \
2564 GenFormatR ## a_cBits(&InVal), iTest, iRounding); \
2565 } \
2566 } \
2567 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
2568 } \
2569}
2570#else
2571# define GEN_FPU_LOAD(a_cBits, a_rdTypeIn, a_aSubTests, a_TestType)
2572#endif
2573
2574#define TEST_FPU_LOAD(a_cBits, a_rdTypeIn, a_SubTestType, a_aSubTests, a_TestType) \
2575typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLFPULDR80FROM ## a_cBits,(PCX86FXSTATE, PIEMFPURESULT, PC ## a_rdTypeIn)); \
2576typedef FNIEMAIMPLFPULDR80FROM ## a_cBits *PFNIEMAIMPLFPULDR80FROM ## a_cBits; \
2577TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLFPULDR80FROM ## a_cBits); \
2578\
2579static const a_SubTestType a_aSubTests[] = \
2580{ \
2581 ENTRY(RT_CONCAT(fld_r80_from_r,a_cBits)) \
2582}; \
2583GEN_FPU_LOAD(a_cBits, a_rdTypeIn, a_aSubTests, a_TestType) \
2584\
2585static void FpuLdR ## a_cBits ## Test(void) \
2586{ \
2587 X86FXSTATE State; \
2588 RT_ZERO(State); \
2589 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2590 { \
2591 if (!SubTestAndCheckIfEnabled(a_aSubTests[iFn].pszName)) continue; \
2592 \
2593 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
2594 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
2595 PFNIEMAIMPLFPULDR80FROM ## a_cBits pfn = a_aSubTests[iFn].pfn; \
2596 uint32_t const cVars = COUNT_VARIATIONS(a_aSubTests[iFn]); \
2597 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
2598 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
2599 { \
2600 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
2601 { \
2602 a_rdTypeIn const InVal = paTests[iTest].InVal; \
2603 State.FCW = paTests[iTest].fFcw; \
2604 State.FSW = paTests[iTest].fFswIn; \
2605 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 }; \
2606 pfn(&State, &Res, &InVal); \
2607 if ( Res.FSW != paTests[iTest].fFswOut \
2608 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult)) \
2609 RTTestFailed(g_hTest, "#%03u%s: fcw=%#06x fsw=%#06x in=%s\n" \
2610 "%s -> fsw=%#06x %s\n" \
2611 "%s expected %#06x %s%s%s (%s)\n", \
2612 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, \
2613 FormatR ## a_cBits(&paTests[iTest].InVal), \
2614 iVar ? " " : "", Res.FSW, FormatR80(&Res.r80Result), \
2615 iVar ? " " : "", paTests[iTest].fFswOut, FormatR80(&paTests[iTest].rdResult), \
2616 FswDiff(Res.FSW, paTests[iTest].fFswOut), \
2617 !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult) ? " - val" : "", \
2618 FormatFcw(paTests[iTest].fFcw) ); \
2619 } \
2620 pfn = a_aSubTests[iFn].pfnNative; \
2621 } \
2622 } \
2623}
2624
2625TEST_FPU_LOAD(80, RTFLOAT80U, FPU_LD_R80_T, g_aFpuLdR80, FPU_R80_IN_TEST_T)
2626TEST_FPU_LOAD(64, RTFLOAT64U, FPU_LD_R64_T, g_aFpuLdR64, FPU_R64_IN_TEST_T)
2627TEST_FPU_LOAD(32, RTFLOAT32U, FPU_LD_R32_T, g_aFpuLdR32, FPU_R32_IN_TEST_T)
2628
2629#ifdef TSTIEMAIMPL_WITH_GENERATOR
2630static void FpuLdMemGenerate(PRTSTREAM pOut, uint32_t cTests)
2631{
2632 FpuLdR80Generate(pOut, cTests);
2633 FpuLdR64Generate(pOut, cTests);
2634 FpuLdR32Generate(pOut, cTests);
2635}
2636#endif
2637
2638static void FpuLdMemTest(void)
2639{
2640 FpuLdR80Test();
2641 FpuLdR64Test();
2642 FpuLdR32Test();
2643}
2644
2645
2646/*
2647 * Load integer values from memory.
2648 */
2649#ifdef TSTIEMAIMPL_WITH_GENERATOR
2650# define GEN_FPU_LOAD_INT(a_cBits, a_iTypeIn, a_szFmtIn, a_aSubTests, a_TestType) \
2651static void FpuLdI ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
2652{ \
2653 X86FXSTATE State; \
2654 RT_ZERO(State); \
2655 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2656 { \
2657 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
2658 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
2659 { \
2660 State.FCW = RandFcw(); \
2661 State.FSW = RandFsw(); \
2662 a_iTypeIn InVal = (a_iTypeIn)RandU ## a_cBits ## Src(iTest); \
2663 \
2664 for (uint16_t iRounding = 0; iRounding < 4; iRounding++) \
2665 { \
2666 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 }; \
2667 State.FCW = (State.FCW & ~X86_FCW_RC_MASK) | (iRounding << X86_FCW_RC_SHIFT); \
2668 a_aSubTests[iFn].pfn(&State, &Res, &InVal); \
2669 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, " a_szFmtIn " }, /* #%u/%u */\n", \
2670 State.FCW, State.FSW, Res.FSW, GenFormatR80(&Res.r80Result), InVal, iTest, iRounding); \
2671 } \
2672 } \
2673 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
2674 } \
2675}
2676#else
2677# define GEN_FPU_LOAD_INT(a_cBits, a_iTypeIn, a_szFmtIn, a_aSubTests, a_TestType)
2678#endif
2679
2680#define TEST_FPU_LOAD_INT(a_cBits, a_iTypeIn, a_szFmtIn, a_SubTestType, a_aSubTests, a_TestType) \
2681typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLFPULDR80FROMI ## a_cBits,(PCX86FXSTATE, PIEMFPURESULT, a_iTypeIn const *)); \
2682typedef FNIEMAIMPLFPULDR80FROMI ## a_cBits *PFNIEMAIMPLFPULDR80FROMI ## a_cBits; \
2683TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLFPULDR80FROMI ## a_cBits); \
2684\
2685static const a_SubTestType a_aSubTests[] = \
2686{ \
2687 ENTRY(RT_CONCAT(fild_r80_from_i,a_cBits)) \
2688}; \
2689GEN_FPU_LOAD_INT(a_cBits, a_iTypeIn, a_szFmtIn, a_aSubTests, a_TestType) \
2690\
2691static void FpuLdI ## a_cBits ## Test(void) \
2692{ \
2693 X86FXSTATE State; \
2694 RT_ZERO(State); \
2695 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2696 { \
2697 if (!SubTestAndCheckIfEnabled(a_aSubTests[iFn].pszName)) continue; \
2698 \
2699 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
2700 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
2701 PFNIEMAIMPLFPULDR80FROMI ## a_cBits pfn = a_aSubTests[iFn].pfn; \
2702 uint32_t const cVars = COUNT_VARIATIONS(a_aSubTests[iFn]); \
2703 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
2704 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
2705 { \
2706 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
2707 { \
2708 a_iTypeIn const iInVal = paTests[iTest].iInVal; \
2709 State.FCW = paTests[iTest].fFcw; \
2710 State.FSW = paTests[iTest].fFswIn; \
2711 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 }; \
2712 pfn(&State, &Res, &iInVal); \
2713 if ( Res.FSW != paTests[iTest].fFswOut \
2714 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult)) \
2715 RTTestFailed(g_hTest, "#%03u%s: fcw=%#06x fsw=%#06x in=" a_szFmtIn "\n" \
2716 "%s -> fsw=%#06x %s\n" \
2717 "%s expected %#06x %s%s%s (%s)\n", \
2718 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, paTests[iTest].iInVal, \
2719 iVar ? " " : "", Res.FSW, FormatR80(&Res.r80Result), \
2720 iVar ? " " : "", paTests[iTest].fFswOut, FormatR80(&paTests[iTest].rdResult), \
2721 FswDiff(Res.FSW, paTests[iTest].fFswOut), \
2722 !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult) ? " - val" : "", \
2723 FormatFcw(paTests[iTest].fFcw) ); \
2724 } \
2725 pfn = a_aSubTests[iFn].pfnNative; \
2726 } \
2727 } \
2728}
2729
2730TEST_FPU_LOAD_INT(64, int64_t, "%RI64", FPU_LD_I64_T, g_aFpuLdU64, FPU_I64_IN_TEST_T)
2731TEST_FPU_LOAD_INT(32, int32_t, "%RI32", FPU_LD_I32_T, g_aFpuLdU32, FPU_I32_IN_TEST_T)
2732TEST_FPU_LOAD_INT(16, int16_t, "%RI16", FPU_LD_I16_T, g_aFpuLdU16, FPU_I16_IN_TEST_T)
2733
2734#ifdef TSTIEMAIMPL_WITH_GENERATOR
2735static void FpuLdIntGenerate(PRTSTREAM pOut, uint32_t cTests)
2736{
2737 FpuLdI64Generate(pOut, cTests);
2738 FpuLdI32Generate(pOut, cTests);
2739 FpuLdI16Generate(pOut, cTests);
2740}
2741#endif
2742
2743static void FpuLdIntTest(void)
2744{
2745 FpuLdI64Test();
2746 FpuLdI32Test();
2747 FpuLdI16Test();
2748}
2749
2750
2751/*
2752 * Load binary coded decimal values from memory.
2753 */
2754typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLFPULDR80FROMD80,(PCX86FXSTATE, PIEMFPURESULT, PCRTPBCD80U));
2755typedef FNIEMAIMPLFPULDR80FROMD80 *PFNIEMAIMPLFPULDR80FROMD80;
2756TYPEDEF_SUBTEST_TYPE(FPU_LD_D80_T, FPU_D80_IN_TEST_T, PFNIEMAIMPLFPULDR80FROMD80);
2757
2758static const FPU_LD_D80_T g_aFpuLdD80[] =
2759{
2760 ENTRY(fld_r80_from_d80)
2761};
2762
2763#ifdef TSTIEMAIMPL_WITH_GENERATOR
2764static void FpuLdD80Generate(PRTSTREAM pOut, uint32_t cTests)
2765{
2766 X86FXSTATE State;
2767 RT_ZERO(State);
2768 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuLdD80); iFn++)
2769 {
2770 GenerateArrayStart(pOut, g_aFpuLdD80[iFn].pszName, "FPU_D80_IN_TEST_T");
2771 for (uint32_t iTest = 0; iTest < cTests; iTest++)
2772 {
2773 State.FCW = RandFcw();
2774 State.FSW = RandFsw();
2775 RTPBCD80U InVal = RandD80Src(iTest);
2776
2777 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
2778 {
2779 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 };
2780 State.FCW = (State.FCW & ~X86_FCW_RC_MASK) | (iRounding << X86_FCW_RC_SHIFT);
2781 g_aFpuLdD80[iFn].pfn(&State, &Res, &InVal);
2782 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u */\n",
2783 State.FCW, State.FSW, Res.FSW, GenFormatR80(&Res.r80Result), GenFormatD80(&InVal),
2784 iTest, iRounding);
2785 }
2786 }
2787 GenerateArrayEnd(pOut, g_aFpuLdD80[iFn].pszName);
2788 }
2789}
2790#endif
2791
2792static void FpuLdD80Test(void)
2793{
2794 X86FXSTATE State;
2795 RT_ZERO(State);
2796 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuLdD80); iFn++)
2797 {
2798 if (!SubTestAndCheckIfEnabled(g_aFpuLdD80[iFn].pszName))
2799 continue;
2800
2801 uint32_t const cTests = *g_aFpuLdD80[iFn].pcTests;
2802 FPU_D80_IN_TEST_T const * const paTests = g_aFpuLdD80[iFn].paTests;
2803 PFNIEMAIMPLFPULDR80FROMD80 pfn = g_aFpuLdD80[iFn].pfn;
2804 uint32_t const cVars = COUNT_VARIATIONS(g_aFpuLdD80[iFn]);
2805 if (!cTests) RTTestSkipped(g_hTest, "no tests");
2806 for (uint32_t iVar = 0; iVar < cVars; iVar++)
2807 {
2808 for (uint32_t iTest = 0; iTest < cTests; iTest++)
2809 {
2810 RTPBCD80U const InVal = paTests[iTest].InVal;
2811 State.FCW = paTests[iTest].fFcw;
2812 State.FSW = paTests[iTest].fFswIn;
2813 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 };
2814 pfn(&State, &Res, &InVal);
2815 if ( Res.FSW != paTests[iTest].fFswOut
2816 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult))
2817 RTTestFailed(g_hTest, "#%03u%s: fcw=%#06x fsw=%#06x in=%s\n"
2818 "%s -> fsw=%#06x %s\n"
2819 "%s expected %#06x %s%s%s (%s)\n",
2820 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
2821 FormatD80(&paTests[iTest].InVal),
2822 iVar ? " " : "", Res.FSW, FormatR80(&Res.r80Result),
2823 iVar ? " " : "", paTests[iTest].fFswOut, FormatR80(&paTests[iTest].rdResult),
2824 FswDiff(Res.FSW, paTests[iTest].fFswOut),
2825 !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].rdResult) ? " - val" : "",
2826 FormatFcw(paTests[iTest].fFcw) );
2827 }
2828 pfn = g_aFpuLdD80[iFn].pfnNative;
2829 }
2830 }
2831}
2832
2833
2834/*
2835 * Store values floating point values to memory.
2836 */
2837#ifdef TSTIEMAIMPL_WITH_GENERATOR
2838static const RTFLOAT80U g_aFpuStR32Specials[] =
2839{
2840 RTFLOAT80U_INIT_C(0, 0xffffff8000000000, RTFLOAT80U_EXP_BIAS), /* near rounding with carry */
2841 RTFLOAT80U_INIT_C(1, 0xffffff8000000000, RTFLOAT80U_EXP_BIAS), /* near rounding with carry */
2842 RTFLOAT80U_INIT_C(0, 0xfffffe8000000000, RTFLOAT80U_EXP_BIAS), /* near rounding */
2843 RTFLOAT80U_INIT_C(1, 0xfffffe8000000000, RTFLOAT80U_EXP_BIAS), /* near rounding */
2844};
2845static const RTFLOAT80U g_aFpuStR64Specials[] =
2846{
2847 RTFLOAT80U_INIT_C(0, 0xfffffffffffffc00, RTFLOAT80U_EXP_BIAS), /* near rounding with carry */
2848 RTFLOAT80U_INIT_C(1, 0xfffffffffffffc00, RTFLOAT80U_EXP_BIAS), /* near rounding with carry */
2849 RTFLOAT80U_INIT_C(0, 0xfffffffffffff400, RTFLOAT80U_EXP_BIAS), /* near rounding */
2850 RTFLOAT80U_INIT_C(1, 0xfffffffffffff400, RTFLOAT80U_EXP_BIAS), /* near rounding */
2851 RTFLOAT80U_INIT_C(0, 0xd0b9e6fdda887400, 687 + RTFLOAT80U_EXP_BIAS), /* random example for this */
2852};
2853static const RTFLOAT80U g_aFpuStR80Specials[] =
2854{
2855 RTFLOAT80U_INIT_C(0, 0x8000000000000000, RTFLOAT80U_EXP_BIAS), /* placeholder */
2856};
2857# define GEN_FPU_STORE(a_cBits, a_rdType, a_aSubTests, a_TestType) \
2858static void FpuStR ## a_cBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
2859{ \
2860 uint32_t const cTotalTests = cTests + RT_ELEMENTS(g_aFpuStR ## a_cBits ## Specials); \
2861 X86FXSTATE State; \
2862 RT_ZERO(State); \
2863 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2864 { \
2865 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
2866 for (uint32_t iTest = 0; iTest < cTotalTests; iTest++) \
2867 { \
2868 uint16_t const fFcw = RandFcw(); \
2869 State.FSW = RandFsw(); \
2870 RTFLOAT80U const InVal = iTest < cTests ? RandR80Src(iTest, a_cBits) \
2871 : g_aFpuStR ## a_cBits ## Specials[iTest - cTests]; \
2872 \
2873 for (uint16_t iRounding = 0; iRounding < 4; iRounding++) \
2874 { \
2875 /* PC doesn't influence these, so leave as is. */ \
2876 AssertCompile(X86_FCW_OM_BIT + 1 == X86_FCW_UM_BIT && X86_FCW_UM_BIT + 1 == X86_FCW_PM_BIT); \
2877 for (uint16_t iMask = 0; iMask < 16; iMask += 2 /*1*/) \
2878 { \
2879 uint16_t uFswOut = 0; \
2880 a_rdType OutVal; \
2881 RT_ZERO(OutVal); \
2882 memset(&OutVal, 0xfe, sizeof(OutVal)); \
2883 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_OM | X86_FCW_UM | X86_FCW_PM)) \
2884 | (iRounding << X86_FCW_RC_SHIFT); \
2885 /*if (iMask & 1) State.FCW ^= X86_FCW_MASK_ALL;*/ \
2886 State.FCW |= (iMask >> 1) << X86_FCW_OM_BIT; \
2887 a_aSubTests[iFn].pfn(&State, &uFswOut, &OutVal, &InVal); \
2888 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u/%u */\n", \
2889 State.FCW, State.FSW, uFswOut, GenFormatR80(&InVal), \
2890 GenFormatR ## a_cBits(&OutVal), iTest, iRounding, iMask); \
2891 } \
2892 } \
2893 } \
2894 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
2895 } \
2896}
2897#else
2898# define GEN_FPU_STORE(a_cBits, a_rdType, a_aSubTests, a_TestType)
2899#endif
2900
2901#define TEST_FPU_STORE(a_cBits, a_rdType, a_SubTestType, a_aSubTests, a_TestType) \
2902typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLFPUSTR80TOR ## a_cBits,(PCX86FXSTATE, uint16_t *, \
2903 PRTFLOAT ## a_cBits ## U, PCRTFLOAT80U)); \
2904typedef FNIEMAIMPLFPUSTR80TOR ## a_cBits *PFNIEMAIMPLFPUSTR80TOR ## a_cBits; \
2905TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLFPUSTR80TOR ## a_cBits); \
2906\
2907static const a_SubTestType a_aSubTests[] = \
2908{ \
2909 ENTRY(RT_CONCAT(fst_r80_to_r,a_cBits)) \
2910}; \
2911GEN_FPU_STORE(a_cBits, a_rdType, a_aSubTests, a_TestType) \
2912\
2913static void FpuStR ## a_cBits ## Test(void) \
2914{ \
2915 X86FXSTATE State; \
2916 RT_ZERO(State); \
2917 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
2918 { \
2919 if (!SubTestAndCheckIfEnabled(a_aSubTests[iFn].pszName)) continue; \
2920 \
2921 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
2922 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
2923 PFNIEMAIMPLFPUSTR80TOR ## a_cBits pfn = a_aSubTests[iFn].pfn; \
2924 uint32_t const cVars = COUNT_VARIATIONS(a_aSubTests[iFn]); \
2925 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
2926 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
2927 { \
2928 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
2929 { \
2930 RTFLOAT80U const InVal = paTests[iTest].InVal; \
2931 uint16_t uFswOut = 0; \
2932 a_rdType OutVal; \
2933 RT_ZERO(OutVal); \
2934 memset(&OutVal, 0xfe, sizeof(OutVal)); \
2935 State.FCW = paTests[iTest].fFcw; \
2936 State.FSW = paTests[iTest].fFswIn; \
2937 pfn(&State, &uFswOut, &OutVal, &InVal); \
2938 if ( uFswOut != paTests[iTest].fFswOut \
2939 || !RTFLOAT ## a_cBits ## U_ARE_IDENTICAL(&OutVal, &paTests[iTest].OutVal)) \
2940 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in=%s\n" \
2941 "%s -> fsw=%#06x %s\n" \
2942 "%s expected %#06x %s%s%s (%s)\n", \
2943 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, \
2944 FormatR80(&paTests[iTest].InVal), \
2945 iVar ? " " : "", uFswOut, FormatR ## a_cBits(&OutVal), \
2946 iVar ? " " : "", paTests[iTest].fFswOut, FormatR ## a_cBits(&paTests[iTest].OutVal), \
2947 FswDiff(uFswOut, paTests[iTest].fFswOut), \
2948 !RTFLOAT ## a_cBits ## U_ARE_IDENTICAL(&OutVal, &paTests[iTest].OutVal) ? " - val" : "", \
2949 FormatFcw(paTests[iTest].fFcw) ); \
2950 } \
2951 pfn = a_aSubTests[iFn].pfnNative; \
2952 } \
2953 } \
2954}
2955
2956TEST_FPU_STORE(80, RTFLOAT80U, FPU_ST_R80_T, g_aFpuStR80, FPU_ST_R80_TEST_T)
2957TEST_FPU_STORE(64, RTFLOAT64U, FPU_ST_R64_T, g_aFpuStR64, FPU_ST_R64_TEST_T)
2958TEST_FPU_STORE(32, RTFLOAT32U, FPU_ST_R32_T, g_aFpuStR32, FPU_ST_R32_TEST_T)
2959
2960#ifdef TSTIEMAIMPL_WITH_GENERATOR
2961static void FpuStMemGenerate(PRTSTREAM pOut, uint32_t cTests)
2962{
2963 FpuStR80Generate(pOut, cTests);
2964 FpuStR64Generate(pOut, cTests);
2965 FpuStR32Generate(pOut, cTests);
2966}
2967#endif
2968
2969static void FpuStMemTest(void)
2970{
2971 FpuStR80Test();
2972 FpuStR64Test();
2973 FpuStR32Test();
2974}
2975
2976
2977/*
2978 * Store integer values to memory or register.
2979 */
2980TYPEDEF_SUBTEST_TYPE(FPU_ST_I16_T, FPU_ST_I16_TEST_T, PFNIEMAIMPLFPUSTR80TOI16);
2981TYPEDEF_SUBTEST_TYPE(FPU_ST_I32_T, FPU_ST_I32_TEST_T, PFNIEMAIMPLFPUSTR80TOI32);
2982TYPEDEF_SUBTEST_TYPE(FPU_ST_I64_T, FPU_ST_I64_TEST_T, PFNIEMAIMPLFPUSTR80TOI64);
2983
2984static const FPU_ST_I16_T g_aFpuStI16[] =
2985{
2986 ENTRY(fist_r80_to_i16),
2987 ENTRY_AMD( fistt_r80_to_i16, 0),
2988 ENTRY_INTEL(fistt_r80_to_i16, 0),
2989};
2990static const FPU_ST_I32_T g_aFpuStI32[] =
2991{
2992 ENTRY(fist_r80_to_i32),
2993 ENTRY(fistt_r80_to_i32),
2994};
2995static const FPU_ST_I64_T g_aFpuStI64[] =
2996{
2997 ENTRY(fist_r80_to_i64),
2998 ENTRY(fistt_r80_to_i64),
2999};
3000
3001#ifdef TSTIEMAIMPL_WITH_GENERATOR
3002static const RTFLOAT80U g_aFpuStI16Specials[] = /* 16-bit variant borrows properties from the 32-bit one, thus all this stuff. */
3003{
3004 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 13 + RTFLOAT80U_EXP_BIAS),
3005 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 13 + RTFLOAT80U_EXP_BIAS),
3006 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 14 + RTFLOAT80U_EXP_BIAS),
3007 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 14 + RTFLOAT80U_EXP_BIAS),
3008 RTFLOAT80U_INIT_C(0, 0x8000080000000000, 14 + RTFLOAT80U_EXP_BIAS),
3009 RTFLOAT80U_INIT_C(1, 0x8000080000000000, 14 + RTFLOAT80U_EXP_BIAS),
3010 RTFLOAT80U_INIT_C(0, 0x8000100000000000, 14 + RTFLOAT80U_EXP_BIAS),
3011 RTFLOAT80U_INIT_C(1, 0x8000100000000000, 14 + RTFLOAT80U_EXP_BIAS),
3012 RTFLOAT80U_INIT_C(0, 0x8000200000000000, 14 + RTFLOAT80U_EXP_BIAS),
3013 RTFLOAT80U_INIT_C(1, 0x8000200000000000, 14 + RTFLOAT80U_EXP_BIAS),
3014 RTFLOAT80U_INIT_C(0, 0x8000400000000000, 14 + RTFLOAT80U_EXP_BIAS),
3015 RTFLOAT80U_INIT_C(1, 0x8000400000000000, 14 + RTFLOAT80U_EXP_BIAS),
3016 RTFLOAT80U_INIT_C(0, 0x8000800000000000, 14 + RTFLOAT80U_EXP_BIAS),
3017 RTFLOAT80U_INIT_C(1, 0x8000800000000000, 14 + RTFLOAT80U_EXP_BIAS),
3018 RTFLOAT80U_INIT_C(1, 0x8000ffffffffffff, 14 + RTFLOAT80U_EXP_BIAS),
3019 RTFLOAT80U_INIT_C(0, 0x8001000000000000, 14 + RTFLOAT80U_EXP_BIAS),
3020 RTFLOAT80U_INIT_C(1, 0x8001000000000000, 14 + RTFLOAT80U_EXP_BIAS),
3021 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 14 + RTFLOAT80U_EXP_BIAS),
3022 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 14 + RTFLOAT80U_EXP_BIAS),
3023 RTFLOAT80U_INIT_C(0, 0xffff800000000000, 14 + RTFLOAT80U_EXP_BIAS),
3024 RTFLOAT80U_INIT_C(0, 0xffff000000000000, 14 + RTFLOAT80U_EXP_BIAS), /* overflow to min/nan */
3025 RTFLOAT80U_INIT_C(0, 0xfffe000000000000, 14 + RTFLOAT80U_EXP_BIAS),
3026 RTFLOAT80U_INIT_C(1, 0xffff800000000000, 14 + RTFLOAT80U_EXP_BIAS),
3027 RTFLOAT80U_INIT_C(1, 0xffff000000000000, 14 + RTFLOAT80U_EXP_BIAS), /* min */
3028 RTFLOAT80U_INIT_C(1, 0xfffe000000000000, 14 + RTFLOAT80U_EXP_BIAS),
3029 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 15 + RTFLOAT80U_EXP_BIAS),
3030 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 15 + RTFLOAT80U_EXP_BIAS),
3031 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 16 + RTFLOAT80U_EXP_BIAS),
3032 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 17 + RTFLOAT80U_EXP_BIAS),
3033 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 20 + RTFLOAT80U_EXP_BIAS),
3034 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 24 + RTFLOAT80U_EXP_BIAS),
3035 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 28 + RTFLOAT80U_EXP_BIAS),
3036 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 30 + RTFLOAT80U_EXP_BIAS),
3037 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 30 + RTFLOAT80U_EXP_BIAS),
3038 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 30 + RTFLOAT80U_EXP_BIAS),
3039 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 30 + RTFLOAT80U_EXP_BIAS),
3040 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 31 + RTFLOAT80U_EXP_BIAS),
3041 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 31 + RTFLOAT80U_EXP_BIAS),
3042 RTFLOAT80U_INIT_C(0, 0x8000000000000001, 31 + RTFLOAT80U_EXP_BIAS),
3043 RTFLOAT80U_INIT_C(1, 0x8000000000000001, 31 + RTFLOAT80U_EXP_BIAS),
3044 RTFLOAT80U_INIT_C(0, 0x8000ffffffffffff, 31 + RTFLOAT80U_EXP_BIAS),
3045 RTFLOAT80U_INIT_C(1, 0x8000ffffffffffff, 31 + RTFLOAT80U_EXP_BIAS),
3046 RTFLOAT80U_INIT_C(0, 0x8001000000000000, 31 + RTFLOAT80U_EXP_BIAS),
3047 RTFLOAT80U_INIT_C(1, 0x8001000000000000, 31 + RTFLOAT80U_EXP_BIAS),
3048 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 31 + RTFLOAT80U_EXP_BIAS),
3049 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 31 + RTFLOAT80U_EXP_BIAS),
3050 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 32 + RTFLOAT80U_EXP_BIAS),
3051};
3052static const RTFLOAT80U g_aFpuStI32Specials[] =
3053{
3054 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 30 + RTFLOAT80U_EXP_BIAS),
3055 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 30 + RTFLOAT80U_EXP_BIAS),
3056 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 30 + RTFLOAT80U_EXP_BIAS), /* overflow to min/nan */
3057 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 30 + RTFLOAT80U_EXP_BIAS), /* min */
3058 RTFLOAT80U_INIT_C(0, 0xffffffff80000000, 30 + RTFLOAT80U_EXP_BIAS), /* overflow to min/nan */
3059 RTFLOAT80U_INIT_C(1, 0xffffffff80000000, 30 + RTFLOAT80U_EXP_BIAS), /* min */
3060 RTFLOAT80U_INIT_C(0, 0xffffffff00000000, 30 + RTFLOAT80U_EXP_BIAS), /* overflow to min/nan */
3061 RTFLOAT80U_INIT_C(1, 0xffffffff00000000, 30 + RTFLOAT80U_EXP_BIAS), /* min */
3062 RTFLOAT80U_INIT_C(0, 0xfffffffe00000000, 30 + RTFLOAT80U_EXP_BIAS),
3063 RTFLOAT80U_INIT_C(1, 0xfffffffe00000000, 30 + RTFLOAT80U_EXP_BIAS),
3064 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 31 + RTFLOAT80U_EXP_BIAS),
3065 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 31 + RTFLOAT80U_EXP_BIAS),
3066 RTFLOAT80U_INIT_C(0, 0x8000000000000001, 31 + RTFLOAT80U_EXP_BIAS),
3067 RTFLOAT80U_INIT_C(1, 0x8000000000000001, 31 + RTFLOAT80U_EXP_BIAS),
3068 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 31 + RTFLOAT80U_EXP_BIAS),
3069 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 31 + RTFLOAT80U_EXP_BIAS),
3070};
3071static const RTFLOAT80U g_aFpuStI64Specials[] =
3072{
3073 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 61 + RTFLOAT80U_EXP_BIAS),
3074 RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, 61 + RTFLOAT80U_EXP_BIAS),
3075 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 62 + RTFLOAT80U_EXP_BIAS),
3076 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 62 + RTFLOAT80U_EXP_BIAS),
3077 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 62 + RTFLOAT80U_EXP_BIAS),
3078 RTFLOAT80U_INIT_C(1, 0xfffffffffffffff0, 62 + RTFLOAT80U_EXP_BIAS),
3079 RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, 62 + RTFLOAT80U_EXP_BIAS), /* overflow to min/nan */
3080 RTFLOAT80U_INIT_C(1, 0xffffffffffffffff, 62 + RTFLOAT80U_EXP_BIAS), /* min */
3081 RTFLOAT80U_INIT_C(0, 0xfffffffffffffffe, 62 + RTFLOAT80U_EXP_BIAS),
3082 RTFLOAT80U_INIT_C(1, 0xfffffffffffffffe, 62 + RTFLOAT80U_EXP_BIAS),
3083 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 63 + RTFLOAT80U_EXP_BIAS),
3084 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 63 + RTFLOAT80U_EXP_BIAS),
3085 RTFLOAT80U_INIT_C(0, 0x8000000000000001, 63 + RTFLOAT80U_EXP_BIAS),
3086 RTFLOAT80U_INIT_C(1, 0x8000000000000001, 63 + RTFLOAT80U_EXP_BIAS),
3087 RTFLOAT80U_INIT_C(0, 0x8000000000000002, 63 + RTFLOAT80U_EXP_BIAS),
3088 RTFLOAT80U_INIT_C(1, 0x8000000000000002, 63 + RTFLOAT80U_EXP_BIAS),
3089 RTFLOAT80U_INIT_C(0, 0xfffffffffffffff0, 63 + RTFLOAT80U_EXP_BIAS),
3090};
3091
3092# define GEN_FPU_STORE_INT(a_cBits, a_iType, a_szFmt, a_aSubTests, a_TestType) \
3093static void FpuStI ## a_cBits ## Generate(PRTSTREAM pOut, PRTSTREAM pOutCpu, uint32_t cTests) \
3094{ \
3095 X86FXSTATE State; \
3096 RT_ZERO(State); \
3097 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
3098 { \
3099 PFNIEMAIMPLFPUSTR80TOI ## a_cBits const pfn = a_aSubTests[iFn].pfnNative \
3100 ? a_aSubTests[iFn].pfnNative : a_aSubTests[iFn].pfn; \
3101 PRTSTREAM pOutFn = pOut; \
3102 if (a_aSubTests[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE) \
3103 { \
3104 if (a_aSubTests[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour) \
3105 continue; \
3106 pOutFn = pOutCpu; \
3107 } \
3108 \
3109 GenerateArrayStart(pOutFn, a_aSubTests[iFn].pszName, #a_TestType); \
3110 uint32_t const cTotalTests = cTests + RT_ELEMENTS(g_aFpuStI ## a_cBits ## Specials); \
3111 for (uint32_t iTest = 0; iTest < cTotalTests; iTest++) \
3112 { \
3113 uint16_t const fFcw = RandFcw(); \
3114 State.FSW = RandFsw(); \
3115 RTFLOAT80U const InVal = iTest < cTests ? RandR80Src(iTest, a_cBits, true) \
3116 : g_aFpuStI ## a_cBits ## Specials[iTest - cTests]; \
3117 \
3118 for (uint16_t iRounding = 0; iRounding < 4; iRounding++) \
3119 { \
3120 /* PC doesn't influence these, so leave as is. */ \
3121 AssertCompile(X86_FCW_OM_BIT + 1 == X86_FCW_UM_BIT && X86_FCW_UM_BIT + 1 == X86_FCW_PM_BIT); \
3122 for (uint16_t iMask = 0; iMask < 16; iMask += 2 /*1*/) \
3123 { \
3124 uint16_t uFswOut = 0; \
3125 a_iType iOutVal = ~(a_iType)2; \
3126 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_OM | X86_FCW_UM | X86_FCW_PM)) \
3127 | (iRounding << X86_FCW_RC_SHIFT); \
3128 /*if (iMask & 1) State.FCW ^= X86_FCW_MASK_ALL;*/ \
3129 State.FCW |= (iMask >> 1) << X86_FCW_OM_BIT; \
3130 pfn(&State, &uFswOut, &iOutVal, &InVal); \
3131 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u/%u */\n", \
3132 State.FCW, State.FSW, uFswOut, GenFormatR80(&InVal), \
3133 GenFormatI ## a_cBits(iOutVal), iTest, iRounding, iMask); \
3134 } \
3135 } \
3136 } \
3137 GenerateArrayEnd(pOutFn, a_aSubTests[iFn].pszName); \
3138 } \
3139}
3140#else
3141# define GEN_FPU_STORE_INT(a_cBits, a_iType, a_szFmt, a_aSubTests, a_TestType)
3142#endif
3143
3144#define TEST_FPU_STORE_INT(a_cBits, a_iType, a_szFmt, a_SubTestType, a_aSubTests, a_TestType) \
3145GEN_FPU_STORE_INT(a_cBits, a_iType, a_szFmt, a_aSubTests, a_TestType) \
3146\
3147static void FpuStI ## a_cBits ## Test(void) \
3148{ \
3149 X86FXSTATE State; \
3150 RT_ZERO(State); \
3151 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
3152 { \
3153 if (!SubTestAndCheckIfEnabled(a_aSubTests[iFn].pszName)) continue; \
3154 \
3155 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
3156 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
3157 PFNIEMAIMPLFPUSTR80TOI ## a_cBits pfn = a_aSubTests[iFn].pfn; \
3158 uint32_t const cVars = COUNT_VARIATIONS(a_aSubTests[iFn]); \
3159 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
3160 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
3161 { \
3162 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
3163 { \
3164 RTFLOAT80U const InVal = paTests[iTest].InVal; \
3165 uint16_t uFswOut = 0; \
3166 a_iType iOutVal = ~(a_iType)2; \
3167 State.FCW = paTests[iTest].fFcw; \
3168 State.FSW = paTests[iTest].fFswIn; \
3169 pfn(&State, &uFswOut, &iOutVal, &InVal); \
3170 if ( uFswOut != paTests[iTest].fFswOut \
3171 || iOutVal != paTests[iTest].iOutVal) \
3172 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in=%s\n" \
3173 "%s -> fsw=%#06x " a_szFmt "\n" \
3174 "%s expected %#06x " a_szFmt "%s%s (%s)\n", \
3175 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, \
3176 FormatR80(&paTests[iTest].InVal), \
3177 iVar ? " " : "", uFswOut, iOutVal, \
3178 iVar ? " " : "", paTests[iTest].fFswOut, paTests[iTest].iOutVal, \
3179 FswDiff(uFswOut, paTests[iTest].fFswOut), \
3180 iOutVal != paTests[iTest].iOutVal ? " - val" : "", FormatFcw(paTests[iTest].fFcw) ); \
3181 } \
3182 pfn = a_aSubTests[iFn].pfnNative; \
3183 } \
3184 } \
3185}
3186
3187//fistt_r80_to_i16 diffs for AMD, of course :-)
3188
3189TEST_FPU_STORE_INT(64, int64_t, "%RI64", FPU_ST_I64_T, g_aFpuStI64, FPU_ST_I64_TEST_T)
3190TEST_FPU_STORE_INT(32, int32_t, "%RI32", FPU_ST_I32_T, g_aFpuStI32, FPU_ST_I32_TEST_T)
3191TEST_FPU_STORE_INT(16, int16_t, "%RI16", FPU_ST_I16_T, g_aFpuStI16, FPU_ST_I16_TEST_T)
3192
3193#ifdef TSTIEMAIMPL_WITH_GENERATOR
3194static void FpuStIntGenerate(PRTSTREAM pOut, PRTSTREAM pOutCpu, uint32_t cTests)
3195{
3196 FpuStI64Generate(pOut, pOutCpu, cTests);
3197 FpuStI32Generate(pOut, pOutCpu, cTests);
3198 FpuStI16Generate(pOut, pOutCpu, cTests);
3199}
3200#endif
3201
3202static void FpuStIntTest(void)
3203{
3204 FpuStI64Test();
3205 FpuStI32Test();
3206 FpuStI16Test();
3207}
3208
3209
3210/*
3211 * Store as packed BCD value (memory).
3212 */
3213typedef IEM_DECL_IMPL_TYPE(void, FNIEMAIMPLFPUSTR80TOD80,(PCX86FXSTATE, uint16_t *, PRTPBCD80U, PCRTFLOAT80U));
3214typedef FNIEMAIMPLFPUSTR80TOD80 *PFNIEMAIMPLFPUSTR80TOD80;
3215TYPEDEF_SUBTEST_TYPE(FPU_ST_D80_T, FPU_ST_D80_TEST_T, PFNIEMAIMPLFPUSTR80TOD80);
3216
3217static const FPU_ST_D80_T g_aFpuStD80[] =
3218{
3219 ENTRY(fst_r80_to_d80),
3220};
3221
3222#ifdef TSTIEMAIMPL_WITH_GENERATOR
3223static void FpuStD80Generate(PRTSTREAM pOut, uint32_t cTests)
3224{
3225 static RTFLOAT80U const s_aSpecials[] =
3226 {
3227 RTFLOAT80U_INIT_C(0, 0xde0b6b3a763fffe0, RTFLOAT80U_EXP_BIAS + 59), /* 1 below max */
3228 RTFLOAT80U_INIT_C(1, 0xde0b6b3a763fffe0, RTFLOAT80U_EXP_BIAS + 59), /* 1 above min */
3229 RTFLOAT80U_INIT_C(0, 0xde0b6b3a763ffff0, RTFLOAT80U_EXP_BIAS + 59), /* exact max */
3230 RTFLOAT80U_INIT_C(1, 0xde0b6b3a763ffff0, RTFLOAT80U_EXP_BIAS + 59), /* exact min */
3231 RTFLOAT80U_INIT_C(0, 0xde0b6b3a763fffff, RTFLOAT80U_EXP_BIAS + 59), /* max & all rounded off bits set */
3232 RTFLOAT80U_INIT_C(1, 0xde0b6b3a763fffff, RTFLOAT80U_EXP_BIAS + 59), /* min & all rounded off bits set */
3233 RTFLOAT80U_INIT_C(0, 0xde0b6b3a763ffff8, RTFLOAT80U_EXP_BIAS + 59), /* max & some rounded off bits set */
3234 RTFLOAT80U_INIT_C(1, 0xde0b6b3a763ffff8, RTFLOAT80U_EXP_BIAS + 59), /* min & some rounded off bits set */
3235 RTFLOAT80U_INIT_C(0, 0xde0b6b3a763ffff1, RTFLOAT80U_EXP_BIAS + 59), /* max & some other rounded off bits set */
3236 RTFLOAT80U_INIT_C(1, 0xde0b6b3a763ffff1, RTFLOAT80U_EXP_BIAS + 59), /* min & some other rounded off bits set */
3237 RTFLOAT80U_INIT_C(0, 0xde0b6b3a76400000, RTFLOAT80U_EXP_BIAS + 59), /* 1 above max */
3238 RTFLOAT80U_INIT_C(1, 0xde0b6b3a76400000, RTFLOAT80U_EXP_BIAS + 59), /* 1 below min */
3239 };
3240
3241 X86FXSTATE State;
3242 RT_ZERO(State);
3243 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuStD80); iFn++)
3244 {
3245 GenerateArrayStart(pOut, g_aFpuStD80[iFn].pszName, "FPU_ST_D80_TEST_T");
3246 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
3247 {
3248 uint16_t const fFcw = RandFcw();
3249 State.FSW = RandFsw();
3250 RTFLOAT80U const InVal = iTest < cTests ? RandR80Src(iTest, 59, true) : s_aSpecials[iTest - cTests];
3251
3252 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
3253 {
3254 /* PC doesn't influence these, so leave as is. */
3255 AssertCompile(X86_FCW_OM_BIT + 1 == X86_FCW_UM_BIT && X86_FCW_UM_BIT + 1 == X86_FCW_PM_BIT);
3256 for (uint16_t iMask = 0; iMask < 16; iMask += 2 /*1*/)
3257 {
3258 uint16_t uFswOut = 0;
3259 RTPBCD80U OutVal = RTPBCD80U_INIT_ZERO(0);
3260 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_OM | X86_FCW_UM | X86_FCW_PM))
3261 | (iRounding << X86_FCW_RC_SHIFT);
3262 /*if (iMask & 1) State.FCW ^= X86_FCW_MASK_ALL;*/
3263 State.FCW |= (iMask >> 1) << X86_FCW_OM_BIT;
3264 g_aFpuStD80[iFn].pfn(&State, &uFswOut, &OutVal, &InVal);
3265 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u/%u */\n",
3266 State.FCW, State.FSW, uFswOut, GenFormatR80(&InVal),
3267 GenFormatD80(&OutVal), iTest, iRounding, iMask);
3268 }
3269 }
3270 }
3271 GenerateArrayEnd(pOut, g_aFpuStD80[iFn].pszName);
3272 }
3273}
3274#endif
3275
3276
3277static void FpuStD80Test(void)
3278{
3279 X86FXSTATE State;
3280 RT_ZERO(State);
3281 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuStD80); iFn++)
3282 {
3283 if (!SubTestAndCheckIfEnabled(g_aFpuStD80[iFn].pszName))
3284 continue;
3285
3286 uint32_t const cTests = *g_aFpuStD80[iFn].pcTests;
3287 FPU_ST_D80_TEST_T const * const paTests = g_aFpuStD80[iFn].paTests;
3288 PFNIEMAIMPLFPUSTR80TOD80 pfn = g_aFpuStD80[iFn].pfn;
3289 uint32_t const cVars = COUNT_VARIATIONS(g_aFpuStD80[iFn]);
3290 if (!cTests) RTTestSkipped(g_hTest, "no tests");
3291 for (uint32_t iVar = 0; iVar < cVars; iVar++)
3292 {
3293 for (uint32_t iTest = 0; iTest < cTests; iTest++)
3294 {
3295 RTFLOAT80U const InVal = paTests[iTest].InVal;
3296 uint16_t uFswOut = 0;
3297 RTPBCD80U OutVal = RTPBCD80U_INIT_ZERO(0);
3298 State.FCW = paTests[iTest].fFcw;
3299 State.FSW = paTests[iTest].fFswIn;
3300 pfn(&State, &uFswOut, &OutVal, &InVal);
3301 if ( uFswOut != paTests[iTest].fFswOut
3302 || !RTPBCD80U_ARE_IDENTICAL(&OutVal, &paTests[iTest].OutVal))
3303 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in=%s\n"
3304 "%s -> fsw=%#06x %s\n"
3305 "%s expected %#06x %s%s%s (%s)\n",
3306 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
3307 FormatR80(&paTests[iTest].InVal),
3308 iVar ? " " : "", uFswOut, FormatD80(&OutVal),
3309 iVar ? " " : "", paTests[iTest].fFswOut, FormatD80(&paTests[iTest].OutVal),
3310 FswDiff(uFswOut, paTests[iTest].fFswOut),
3311 RTPBCD80U_ARE_IDENTICAL(&OutVal, &paTests[iTest].OutVal) ? " - val" : "",
3312 FormatFcw(paTests[iTest].fFcw) );
3313 }
3314 pfn = g_aFpuStD80[iFn].pfnNative;
3315 }
3316 }
3317}
3318
3319
3320
3321/*********************************************************************************************************************************
3322* x87 FPU Binary Operations *
3323*********************************************************************************************************************************/
3324
3325/*
3326 * Binary FPU operations on two 80-bit floating point values.
3327 */
3328TYPEDEF_SUBTEST_TYPE(FPU_BINARY_R80_T, FPU_BINARY_R80_TEST_T, PFNIEMAIMPLFPUR80);
3329enum { kFpuBinaryHint_fprem = 1, };
3330
3331static const FPU_BINARY_R80_T g_aFpuBinaryR80[] =
3332{
3333 ENTRY(fadd_r80_by_r80),
3334 ENTRY(fsub_r80_by_r80),
3335 ENTRY(fsubr_r80_by_r80),
3336 ENTRY(fmul_r80_by_r80),
3337 ENTRY(fdiv_r80_by_r80),
3338 ENTRY(fdivr_r80_by_r80),
3339 ENTRY_EX(fprem_r80_by_r80, kFpuBinaryHint_fprem),
3340 ENTRY_EX(fprem1_r80_by_r80, kFpuBinaryHint_fprem),
3341 ENTRY(fscale_r80_by_r80),
3342 ENTRY_AMD( fpatan_r80_by_r80, 0), // C1 and rounding differs on AMD
3343 ENTRY_INTEL(fpatan_r80_by_r80, 0), // C1 and rounding differs on AMD
3344 ENTRY_AMD( fyl2x_r80_by_r80, 0), // C1 and rounding differs on AMD
3345 ENTRY_INTEL(fyl2x_r80_by_r80, 0), // C1 and rounding differs on AMD
3346 ENTRY_AMD( fyl2xp1_r80_by_r80, 0), // C1 and rounding differs on AMD
3347 ENTRY_INTEL(fyl2xp1_r80_by_r80, 0), // C1 and rounding differs on AMD
3348};
3349
3350#ifdef TSTIEMAIMPL_WITH_GENERATOR
3351static void FpuBinaryR80Generate(PRTSTREAM pOut, PRTSTREAM pOutCpu, uint32_t cTests)
3352{
3353 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
3354
3355 static struct { RTFLOAT80U Val1, Val2; } const s_aSpecials[] =
3356 {
3357 { RTFLOAT80U_INIT_C(1, 0xdd762f07f2e80eef, 30142), /* causes weird overflows with DOWN and NEAR rounding. */
3358 RTFLOAT80U_INIT_C(1, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1) },
3359 { RTFLOAT80U_INIT_ZERO(0), /* causes weird overflows with UP and NEAR rounding when precision is lower than 64. */
3360 RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1) },
3361 { RTFLOAT80U_INIT_ZERO(0), /* minus variant */
3362 RTFLOAT80U_INIT_C(1, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1) },
3363 { RTFLOAT80U_INIT_C(0, 0xcef238bb9a0afd86, 577 + RTFLOAT80U_EXP_BIAS), /* for fprem and fprem1, max sequence length */
3364 RTFLOAT80U_INIT_C(0, 0xf11684ec0beaad94, 1 + RTFLOAT80U_EXP_BIAS) },
3365 { RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, -13396 + RTFLOAT80U_EXP_BIAS), /* for fdiv. We missed PE. */
3366 RTFLOAT80U_INIT_C(1, 0xffffffffffffffff, 16383 + RTFLOAT80U_EXP_BIAS) },
3367 { RTFLOAT80U_INIT_C(0, 0x8000000000000000, 1 + RTFLOAT80U_EXP_BIAS), /* for fprem/fprem1 */
3368 RTFLOAT80U_INIT_C(0, 0xe000000000000000, 0 + RTFLOAT80U_EXP_BIAS) },
3369 { RTFLOAT80U_INIT_C(0, 0x8000000000000000, 1 + RTFLOAT80U_EXP_BIAS), /* for fprem/fprem1 */
3370 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 0 + RTFLOAT80U_EXP_BIAS) },
3371 /* fscale: This may seriously increase the exponent, and it turns out overflow and underflow behaviour changes
3372 once RTFLOAT80U_EXP_BIAS_ADJUST is exceeded. */
3373 { RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1), /* for fscale: max * 2^1 */
3374 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 0 + RTFLOAT80U_EXP_BIAS) },
3375 { RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1), /* for fscale: max * 2^64 */
3376 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 6 + RTFLOAT80U_EXP_BIAS) },
3377 { RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1), /* for fscale: max * 2^1024 */
3378 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 10 + RTFLOAT80U_EXP_BIAS) },
3379 { RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1), /* for fscale: max * 2^4096 */
3380 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 12 + RTFLOAT80U_EXP_BIAS) },
3381 { RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1), /* for fscale: max * 2^16384 */
3382 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 14 + RTFLOAT80U_EXP_BIAS) }, /* resulting exponent: 49150 */
3383 { RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1), /* for fscale: max * 2^24576 (RTFLOAT80U_EXP_BIAS_ADJUST) */
3384 RTFLOAT80U_INIT_C(0, 0xc000000000000000, 14 + RTFLOAT80U_EXP_BIAS) }, /* resulting exponent: 57342 - within 10980XE range */
3385 { RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1), /* for fscale: max * 2^24577 */
3386 RTFLOAT80U_INIT_C(0, 0xc002000000000000, 14 + RTFLOAT80U_EXP_BIAS) }, /* resulting exponent: 57343 - outside 10980XE range, behaviour changes! */
3387 { RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1), /* for fscale: max * 2^32768 - result is within range on 10980XE */
3388 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 15 + RTFLOAT80U_EXP_BIAS) }, /* resulting exponent: 65534 */
3389 { RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1), /* for fscale: max * 2^65536 */
3390 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 16 + RTFLOAT80U_EXP_BIAS) },
3391 { RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1), /* for fscale: max * 2^1048576 */
3392 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 20 + RTFLOAT80U_EXP_BIAS) },
3393 { RTFLOAT80U_INIT_C(0, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1), /* for fscale: max * 2^16777216 */
3394 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 24 + RTFLOAT80U_EXP_BIAS) },
3395 { RTFLOAT80U_INIT_C(0, 0x8000000000000000, 1), /* for fscale: min * 2^-24576 (RTFLOAT80U_EXP_BIAS_ADJUST) */
3396 RTFLOAT80U_INIT_C(1, 0xc000000000000000, 14 + RTFLOAT80U_EXP_BIAS) }, /* resulting exponent: -24575 - within 10980XE range */
3397 { RTFLOAT80U_INIT_C(0, 0x8000000000000000, 1), /* for fscale: max * 2^-24577 (RTFLOAT80U_EXP_BIAS_ADJUST) */
3398 RTFLOAT80U_INIT_C(1, 0xc002000000000000, 14 + RTFLOAT80U_EXP_BIAS) }, /* resulting exponent: -24576 - outside 10980XE range, behaviour changes! */
3399 /* fscale: Negative variants for the essentials of the above. */
3400 { RTFLOAT80U_INIT_C(1, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1), /* for fscale: max * 2^24576 (RTFLOAT80U_EXP_BIAS_ADJUST) */
3401 RTFLOAT80U_INIT_C(0, 0xc000000000000000, 14 + RTFLOAT80U_EXP_BIAS) }, /* resulting exponent: 57342 - within 10980XE range */
3402 { RTFLOAT80U_INIT_C(1, 0xffffffffffffffff, RTFLOAT80U_EXP_MAX - 1), /* for fscale: max * 2^24577 */
3403 RTFLOAT80U_INIT_C(0, 0xc002000000000000, 14 + RTFLOAT80U_EXP_BIAS) }, /* resulting exponent: 57343 - outside 10980XE range, behaviour changes! */
3404 { RTFLOAT80U_INIT_C(1, 0x8000000000000000, 1), /* for fscale: min * 2^-24576 (RTFLOAT80U_EXP_BIAS_ADJUST) */
3405 RTFLOAT80U_INIT_C(1, 0xc000000000000000, 14 + RTFLOAT80U_EXP_BIAS) }, /* resulting exponent: -57342 - within 10980XE range */
3406 { RTFLOAT80U_INIT_C(1, 0x8000000000000000, 1), /* for fscale: max * 2^-24576 (RTFLOAT80U_EXP_BIAS_ADJUST) */
3407 RTFLOAT80U_INIT_C(1, 0xc002000000000000, 14 + RTFLOAT80U_EXP_BIAS) }, /* resulting exponent: -57343 - outside 10980XE range, behaviour changes! */
3408 /* fscale: Some fun with denormals and pseudo-denormals. */
3409 { RTFLOAT80U_INIT_C(0, 0x0800000000000000, 0), /* for fscale: max * 2^-4 */
3410 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 2 + RTFLOAT80U_EXP_BIAS) },
3411 { RTFLOAT80U_INIT_C(0, 0x0800000000000000, 0), /* for fscale: max * 2^+1 */
3412 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 0 + RTFLOAT80U_EXP_BIAS) },
3413 { RTFLOAT80U_INIT_C(0, 0x0800000000000000, 0), RTFLOAT80U_INIT_ZERO(0) }, /* for fscale: max * 2^+0 */
3414 { RTFLOAT80U_INIT_C(0, 0x0000000000000008, 0), /* for fscale: max * 2^-4 => underflow */
3415 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 2 + RTFLOAT80U_EXP_BIAS) },
3416 { RTFLOAT80U_INIT_C(0, 0x8005000300020001, 0), RTFLOAT80U_INIT_ZERO(0) }, /* pseudo-normal number * 2^+0. */
3417 { RTFLOAT80U_INIT_C(1, 0x8005000300020001, 0), RTFLOAT80U_INIT_ZERO(0) }, /* pseudo-normal number * 2^+0. */
3418 { RTFLOAT80U_INIT_C(0, 0x8005000300020001, 0), /* pseudo-normal number * 2^-4 */
3419 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 2 + RTFLOAT80U_EXP_BIAS) },
3420 { RTFLOAT80U_INIT_C(0, 0x8005000300020001, 0), /* pseudo-normal number * 2^+0 */
3421 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 0 + RTFLOAT80U_EXP_BIAS) },
3422 { RTFLOAT80U_INIT_C(0, 0x8005000300020001, 0), /* pseudo-normal number * 2^+1 */
3423 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 1 + RTFLOAT80U_EXP_BIAS) },
3424 };
3425
3426 X86FXSTATE State;
3427 RT_ZERO(State);
3428 uint32_t cMinNormalPairs = (cTests - 144) / 4;
3429 uint32_t cMinTargetRangeInputs = cMinNormalPairs / 2;
3430 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuBinaryR80); iFn++)
3431 {
3432 PFNIEMAIMPLFPUR80 const pfn = g_aFpuBinaryR80[iFn].pfnNative ? g_aFpuBinaryR80[iFn].pfnNative : g_aFpuBinaryR80[iFn].pfn;
3433 PRTSTREAM pOutFn = pOut;
3434 if (g_aFpuBinaryR80[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE)
3435 {
3436 if (g_aFpuBinaryR80[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour)
3437 continue;
3438 pOutFn = pOutCpu;
3439 }
3440
3441 GenerateArrayStart(pOutFn, g_aFpuBinaryR80[iFn].pszName, "FPU_BINARY_R80_TEST_T");
3442 uint32_t iTestOutput = 0;
3443 uint32_t cNormalInputPairs = 0;
3444 uint32_t cTargetRangeInputs = 0;
3445 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
3446 {
3447 RTFLOAT80U InVal1 = iTest < cTests ? RandR80Src1(iTest) : s_aSpecials[iTest - cTests].Val1;
3448 RTFLOAT80U InVal2 = iTest < cTests ? RandR80Src2(iTest) : s_aSpecials[iTest - cTests].Val2;
3449 bool fTargetRange = false;
3450 if (RTFLOAT80U_IS_NORMAL(&InVal1) && RTFLOAT80U_IS_NORMAL(&InVal2))
3451 {
3452 cNormalInputPairs++;
3453 if ( g_aFpuBinaryR80[iFn].uExtra == kFpuBinaryHint_fprem
3454 && (uint32_t)InVal1.s.uExponent - (uint32_t)InVal2.s.uExponent - (uint32_t)64 <= (uint32_t)512)
3455 cTargetRangeInputs += fTargetRange = true;
3456 else if (cTargetRangeInputs < cMinTargetRangeInputs && iTest < cTests)
3457 if (g_aFpuBinaryR80[iFn].uExtra == kFpuBinaryHint_fprem)
3458 { /* The aim is two values with an exponent difference between 64 and 640 so we can do the whole sequence. */
3459 InVal2.s.uExponent = RTRandU32Ex(1, RTFLOAT80U_EXP_MAX - 66);
3460 InVal1.s.uExponent = RTRandU32Ex(InVal2.s.uExponent + 64, RT_MIN(InVal2.s.uExponent + 512, RTFLOAT80U_EXP_MAX - 1));
3461 cTargetRangeInputs += fTargetRange = true;
3462 }
3463 }
3464 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
3465 {
3466 iTest -= 1;
3467 continue;
3468 }
3469
3470 uint16_t const fFcwExtra = 0;
3471 uint16_t const fFcw = RandFcw();
3472 State.FSW = RandFsw();
3473
3474 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
3475 for (uint16_t iPrecision = 0; iPrecision < 4; iPrecision++)
3476 {
3477 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_PC_MASK | X86_FCW_MASK_ALL))
3478 | (iRounding << X86_FCW_RC_SHIFT)
3479 | (iPrecision << X86_FCW_PC_SHIFT)
3480 | X86_FCW_MASK_ALL;
3481 IEMFPURESULT ResM = { RTFLOAT80U_INIT(0, 0, 0), 0 };
3482 pfn(&State, &ResM, &InVal1, &InVal2);
3483 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/m = #%u */\n",
3484 State.FCW | fFcwExtra, State.FSW, ResM.FSW, GenFormatR80(&InVal1), GenFormatR80(&InVal2),
3485 GenFormatR80(&ResM.r80Result), iTest, iRounding, iPrecision, iTestOutput++);
3486
3487 State.FCW = State.FCW & ~X86_FCW_MASK_ALL;
3488 IEMFPURESULT ResU = { RTFLOAT80U_INIT(0, 0, 0), 0 };
3489 pfn(&State, &ResU, &InVal1, &InVal2);
3490 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/u = #%u */\n",
3491 State.FCW | fFcwExtra, State.FSW, ResU.FSW, GenFormatR80(&InVal1), GenFormatR80(&InVal2),
3492 GenFormatR80(&ResU.r80Result), iTest, iRounding, iPrecision, iTestOutput++);
3493
3494 uint16_t fXcpt = (ResM.FSW | ResU.FSW) & X86_FSW_XCPT_MASK & ~X86_FSW_SF;
3495 if (fXcpt)
3496 {
3497 State.FCW = (State.FCW & ~X86_FCW_MASK_ALL) | fXcpt;
3498 IEMFPURESULT Res1 = { RTFLOAT80U_INIT(0, 0, 0), 0 };
3499 pfn(&State, &Res1, &InVal1, &InVal2);
3500 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/%#x = #%u */\n",
3501 State.FCW | fFcwExtra, State.FSW, Res1.FSW, GenFormatR80(&InVal1), GenFormatR80(&InVal2),
3502 GenFormatR80(&Res1.r80Result), iTest, iRounding, iPrecision, fXcpt, iTestOutput++);
3503 if (((Res1.FSW & X86_FSW_XCPT_MASK) & fXcpt) != (Res1.FSW & X86_FSW_XCPT_MASK))
3504 {
3505 fXcpt |= Res1.FSW & X86_FSW_XCPT_MASK;
3506 State.FCW = (State.FCW & ~X86_FCW_MASK_ALL) | fXcpt;
3507 IEMFPURESULT Res2 = { RTFLOAT80U_INIT(0, 0, 0), 0 };
3508 pfn(&State, &Res2, &InVal1, &InVal2);
3509 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/%#x[!] = #%u */\n",
3510 State.FCW | fFcwExtra, State.FSW, Res2.FSW, GenFormatR80(&InVal1), GenFormatR80(&InVal2),
3511 GenFormatR80(&Res2.r80Result), iTest, iRounding, iPrecision, fXcpt, iTestOutput++);
3512 }
3513 if (!RT_IS_POWER_OF_TWO(fXcpt))
3514 for (uint16_t fUnmasked = 1; fUnmasked <= X86_FCW_PM; fUnmasked <<= 1)
3515 if (fUnmasked & fXcpt)
3516 {
3517 State.FCW = (State.FCW & ~X86_FCW_MASK_ALL) | (fXcpt & ~fUnmasked);
3518 IEMFPURESULT Res3 = { RTFLOAT80U_INIT(0, 0, 0), 0 };
3519 pfn(&State, &Res3, &InVal1, &InVal2);
3520 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/u%#x = #%u */\n",
3521 State.FCW | fFcwExtra, State.FSW, Res3.FSW, GenFormatR80(&InVal1), GenFormatR80(&InVal2),
3522 GenFormatR80(&Res3.r80Result), iTest, iRounding, iPrecision, fUnmasked, iTestOutput++);
3523 }
3524 }
3525
3526 /* If the values are in range and caused no exceptions, do the whole series of
3527 partial reminders till we get the non-partial one or run into an exception. */
3528 if (fTargetRange && fXcpt == 0 && g_aFpuBinaryR80[iFn].uExtra == kFpuBinaryHint_fprem)
3529 {
3530 IEMFPURESULT ResPrev = ResM;
3531 for (unsigned i = 0; i < 32 && (ResPrev.FSW & (X86_FSW_C2 | X86_FSW_XCPT_MASK)) == X86_FSW_C2; i++)
3532 {
3533 State.FCW = State.FCW | X86_FCW_MASK_ALL;
3534 State.FSW = ResPrev.FSW;
3535 IEMFPURESULT ResSeq = { RTFLOAT80U_INIT(0, 0, 0), 0 };
3536 pfn(&State, &ResSeq, &ResPrev.r80Result, &InVal2);
3537 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/seq%u = #%u */\n",
3538 State.FCW | fFcwExtra, State.FSW, ResSeq.FSW, GenFormatR80(&ResPrev.r80Result),
3539 GenFormatR80(&InVal2), GenFormatR80(&ResSeq.r80Result),
3540 iTest, iRounding, iPrecision, i + 1, iTestOutput++);
3541 ResPrev = ResSeq;
3542 }
3543 }
3544 }
3545 }
3546 GenerateArrayEnd(pOutFn, g_aFpuBinaryR80[iFn].pszName);
3547 }
3548}
3549#endif
3550
3551
3552static void FpuBinaryR80Test(void)
3553{
3554 X86FXSTATE State;
3555 RT_ZERO(State);
3556 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuBinaryR80); iFn++)
3557 {
3558 if (!SubTestAndCheckIfEnabled(g_aFpuBinaryR80[iFn].pszName))
3559 continue;
3560
3561 uint32_t const cTests = *g_aFpuBinaryR80[iFn].pcTests;
3562 FPU_BINARY_R80_TEST_T const * const paTests = g_aFpuBinaryR80[iFn].paTests;
3563 PFNIEMAIMPLFPUR80 pfn = g_aFpuBinaryR80[iFn].pfn;
3564 uint32_t const cVars = COUNT_VARIATIONS(g_aFpuBinaryR80[iFn]);
3565 if (!cTests) RTTestSkipped(g_hTest, "no tests");
3566 for (uint32_t iVar = 0; iVar < cVars; iVar++)
3567 {
3568 for (uint32_t iTest = 0; iTest < cTests; iTest++)
3569 {
3570 RTFLOAT80U const InVal1 = paTests[iTest].InVal1;
3571 RTFLOAT80U const InVal2 = paTests[iTest].InVal2;
3572 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 };
3573 State.FCW = paTests[iTest].fFcw;
3574 State.FSW = paTests[iTest].fFswIn;
3575 pfn(&State, &Res, &InVal1, &InVal2);
3576 if ( Res.FSW != paTests[iTest].fFswOut
3577 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].OutVal))
3578 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in1=%s in2=%s\n"
3579 "%s -> fsw=%#06x %s\n"
3580 "%s expected %#06x %s%s%s (%s)\n",
3581 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
3582 FormatR80(&paTests[iTest].InVal1), FormatR80(&paTests[iTest].InVal2),
3583 iVar ? " " : "", Res.FSW, FormatR80(&Res.r80Result),
3584 iVar ? " " : "", paTests[iTest].fFswOut, FormatR80(&paTests[iTest].OutVal),
3585 FswDiff(Res.FSW, paTests[iTest].fFswOut),
3586 !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].OutVal) ? " - val" : "",
3587 FormatFcw(paTests[iTest].fFcw) );
3588 }
3589 pfn = g_aFpuBinaryR80[iFn].pfnNative;
3590 }
3591 }
3592}
3593
3594
3595/*
3596 * Binary FPU operations on one 80-bit floating point value and one 64-bit or 32-bit one.
3597 */
3598#define int64_t_IS_NORMAL(a) 1
3599#define int32_t_IS_NORMAL(a) 1
3600#define int16_t_IS_NORMAL(a) 1
3601
3602#ifdef TSTIEMAIMPL_WITH_GENERATOR
3603static struct { RTFLOAT80U Val1; RTFLOAT64U Val2; } const s_aFpuBinaryR64Specials[] =
3604{
3605 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3606 RTFLOAT64U_INIT_C(0, 0xfeeeeddddcccc, RTFLOAT64U_EXP_BIAS) }, /* whatever */
3607};
3608static struct { RTFLOAT80U Val1; RTFLOAT32U Val2; } const s_aFpuBinaryR32Specials[] =
3609{
3610 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3611 RTFLOAT32U_INIT_C(0, 0x7fffee, RTFLOAT32U_EXP_BIAS) }, /* whatever */
3612};
3613static struct { RTFLOAT80U Val1; int32_t Val2; } const s_aFpuBinaryI32Specials[] =
3614{
3615 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS), INT32_MAX }, /* whatever */
3616};
3617static struct { RTFLOAT80U Val1; int16_t Val2; } const s_aFpuBinaryI16Specials[] =
3618{
3619 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS), INT16_MAX }, /* whatever */
3620};
3621
3622# define GEN_FPU_BINARY_SMALL(a_fIntType, a_cBits, a_LoBits, a_UpBits, a_Type2, a_aSubTests, a_TestType) \
3623static void FpuBinary ## a_UpBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
3624{ \
3625 cTests = RT_MAX(160, cTests); /* there are 144 standard input variations for r80 by r80 */ \
3626 \
3627 X86FXSTATE State; \
3628 RT_ZERO(State); \
3629 uint32_t cMinNormalPairs = (cTests - 144) / 4; \
3630 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
3631 { \
3632 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
3633 uint32_t cNormalInputPairs = 0; \
3634 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aFpuBinary ## a_UpBits ## Specials); iTest += 1) \
3635 { \
3636 RTFLOAT80U const InVal1 = iTest < cTests ? RandR80Src1(iTest, a_cBits, a_fIntType) \
3637 : s_aFpuBinary ## a_UpBits ## Specials[iTest - cTests].Val1; \
3638 a_Type2 const InVal2 = iTest < cTests ? Rand ## a_UpBits ## Src2(iTest) \
3639 : s_aFpuBinary ## a_UpBits ## Specials[iTest - cTests].Val2; \
3640 if (RTFLOAT80U_IS_NORMAL(&InVal1) && a_Type2 ## _IS_NORMAL(&InVal2)) \
3641 cNormalInputPairs++; \
3642 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests) \
3643 { \
3644 iTest -= 1; \
3645 continue; \
3646 } \
3647 \
3648 uint16_t const fFcw = RandFcw(); \
3649 State.FSW = RandFsw(); \
3650 \
3651 for (uint16_t iRounding = 0; iRounding < 4; iRounding++) \
3652 { \
3653 for (uint16_t iPrecision = 0; iPrecision < 4; iPrecision++) \
3654 { \
3655 for (uint16_t iMask = 0; iMask <= X86_FCW_MASK_ALL; iMask += X86_FCW_MASK_ALL) \
3656 { \
3657 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_PC_MASK | X86_FCW_MASK_ALL)) \
3658 | (iRounding << X86_FCW_RC_SHIFT) \
3659 | (iPrecision << X86_FCW_PC_SHIFT) \
3660 | iMask; \
3661 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 }; \
3662 a_aSubTests[iFn].pfn(&State, &Res, &InVal1, &InVal2); \
3663 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/%c */\n", \
3664 State.FCW, State.FSW, Res.FSW, GenFormatR80(&InVal1), GenFormat ## a_UpBits(&InVal2), \
3665 GenFormatR80(&Res.r80Result), iTest, iRounding, iPrecision, iMask ? 'c' : 'u'); \
3666 } \
3667 } \
3668 } \
3669 } \
3670 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
3671 } \
3672}
3673#else
3674# define GEN_FPU_BINARY_SMALL(a_fIntType, a_cBits, a_LoBits, a_UpBits, a_Type2, a_aSubTests, a_TestType)
3675#endif
3676
3677#define TEST_FPU_BINARY_SMALL(a_fIntType, a_cBits, a_LoBits, a_UpBits, a_I, a_Type2, a_SubTestType, a_aSubTests, a_TestType) \
3678TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLFPU ## a_UpBits); \
3679\
3680static const a_SubTestType a_aSubTests[] = \
3681{ \
3682 ENTRY(RT_CONCAT4(f, a_I, add_r80_by_, a_LoBits)), \
3683 ENTRY(RT_CONCAT4(f, a_I, mul_r80_by_, a_LoBits)), \
3684 ENTRY(RT_CONCAT4(f, a_I, sub_r80_by_, a_LoBits)), \
3685 ENTRY(RT_CONCAT4(f, a_I, subr_r80_by_, a_LoBits)), \
3686 ENTRY(RT_CONCAT4(f, a_I, div_r80_by_, a_LoBits)), \
3687 ENTRY(RT_CONCAT4(f, a_I, divr_r80_by_, a_LoBits)), \
3688}; \
3689\
3690GEN_FPU_BINARY_SMALL(a_fIntType, a_cBits, a_LoBits, a_UpBits, a_Type2, a_aSubTests, a_TestType) \
3691\
3692static void FpuBinary ## a_UpBits ## Test(void) \
3693{ \
3694 X86FXSTATE State; \
3695 RT_ZERO(State); \
3696 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
3697 { \
3698 if (!SubTestAndCheckIfEnabled(a_aSubTests[iFn].pszName)) continue; \
3699 \
3700 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
3701 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
3702 PFNIEMAIMPLFPU ## a_UpBits pfn = a_aSubTests[iFn].pfn; \
3703 uint32_t const cVars = COUNT_VARIATIONS(a_aSubTests[iFn]); \
3704 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
3705 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
3706 { \
3707 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
3708 { \
3709 RTFLOAT80U const InVal1 = paTests[iTest].InVal1; \
3710 a_Type2 const InVal2 = paTests[iTest].InVal2; \
3711 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 }; \
3712 State.FCW = paTests[iTest].fFcw; \
3713 State.FSW = paTests[iTest].fFswIn; \
3714 pfn(&State, &Res, &InVal1, &InVal2); \
3715 if ( Res.FSW != paTests[iTest].fFswOut \
3716 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].OutVal)) \
3717 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in1=%s in2=%s\n" \
3718 "%s -> fsw=%#06x %s\n" \
3719 "%s expected %#06x %s%s%s (%s)\n", \
3720 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, \
3721 FormatR80(&paTests[iTest].InVal1), Format ## a_UpBits(&paTests[iTest].InVal2), \
3722 iVar ? " " : "", Res.FSW, FormatR80(&Res.r80Result), \
3723 iVar ? " " : "", paTests[iTest].fFswOut, FormatR80(&paTests[iTest].OutVal), \
3724 FswDiff(Res.FSW, paTests[iTest].fFswOut), \
3725 !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].OutVal) ? " - val" : "", \
3726 FormatFcw(paTests[iTest].fFcw) ); \
3727 } \
3728 pfn = a_aSubTests[iFn].pfnNative; \
3729 } \
3730 } \
3731}
3732
3733TEST_FPU_BINARY_SMALL(0, 64, r64, R64, RT_NOTHING, RTFLOAT64U, FPU_BINARY_R64_T, g_aFpuBinaryR64, FPU_BINARY_R64_TEST_T)
3734TEST_FPU_BINARY_SMALL(0, 32, r32, R32, RT_NOTHING, RTFLOAT32U, FPU_BINARY_R32_T, g_aFpuBinaryR32, FPU_BINARY_R32_TEST_T)
3735TEST_FPU_BINARY_SMALL(1, 32, i32, I32, i, int32_t, FPU_BINARY_I32_T, g_aFpuBinaryI32, FPU_BINARY_I32_TEST_T)
3736TEST_FPU_BINARY_SMALL(1, 16, i16, I16, i, int16_t, FPU_BINARY_I16_T, g_aFpuBinaryI16, FPU_BINARY_I16_TEST_T)
3737
3738
3739/*
3740 * Binary operations on 80-, 64- and 32-bit floating point only affecting FSW.
3741 */
3742#ifdef TSTIEMAIMPL_WITH_GENERATOR
3743static struct { RTFLOAT80U Val1, Val2; } const s_aFpuBinaryFswR80Specials[] =
3744{
3745 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3746 RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS) }, /* whatever */
3747};
3748static struct { RTFLOAT80U Val1; RTFLOAT64U Val2; } const s_aFpuBinaryFswR64Specials[] =
3749{
3750 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3751 RTFLOAT64U_INIT_C(0, 0xfeeeeddddcccc, RTFLOAT64U_EXP_BIAS) }, /* whatever */
3752};
3753static struct { RTFLOAT80U Val1; RTFLOAT32U Val2; } const s_aFpuBinaryFswR32Specials[] =
3754{
3755 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3756 RTFLOAT32U_INIT_C(0, 0x7fffee, RTFLOAT32U_EXP_BIAS) }, /* whatever */
3757};
3758static struct { RTFLOAT80U Val1; int32_t Val2; } const s_aFpuBinaryFswI32Specials[] =
3759{
3760 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS), INT32_MAX }, /* whatever */
3761};
3762static struct { RTFLOAT80U Val1; int16_t Val2; } const s_aFpuBinaryFswI16Specials[] =
3763{
3764 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS), INT16_MAX }, /* whatever */
3765};
3766
3767# define GEN_FPU_BINARY_FSW(a_fIntType, a_cBits, a_UpBits, a_Type2, a_aSubTests, a_TestType) \
3768static void FpuBinaryFsw ## a_UpBits ## Generate(PRTSTREAM pOut, uint32_t cTests) \
3769{ \
3770 cTests = RT_MAX(160, cTests); /* there are 144 standard input variations for r80 by r80 */ \
3771 \
3772 X86FXSTATE State; \
3773 RT_ZERO(State); \
3774 uint32_t cMinNormalPairs = (cTests - 144) / 4; \
3775 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
3776 { \
3777 GenerateArrayStart(pOut, a_aSubTests[iFn].pszName, #a_TestType); \
3778 uint32_t cNormalInputPairs = 0; \
3779 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aFpuBinaryFsw ## a_UpBits ## Specials); iTest += 1) \
3780 { \
3781 RTFLOAT80U const InVal1 = iTest < cTests ? RandR80Src1(iTest, a_cBits, a_fIntType) \
3782 : s_aFpuBinaryFsw ## a_UpBits ## Specials[iTest - cTests].Val1; \
3783 a_Type2 const InVal2 = iTest < cTests ? Rand ## a_UpBits ## Src2(iTest) \
3784 : s_aFpuBinaryFsw ## a_UpBits ## Specials[iTest - cTests].Val2; \
3785 if (RTFLOAT80U_IS_NORMAL(&InVal1) && a_Type2 ## _IS_NORMAL(&InVal2)) \
3786 cNormalInputPairs++; \
3787 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests) \
3788 { \
3789 iTest -= 1; \
3790 continue; \
3791 } \
3792 \
3793 uint16_t const fFcw = RandFcw(); \
3794 State.FSW = RandFsw(); \
3795 \
3796 /* Guess these aren't affected by precision or rounding, so just flip the exception mask. */ \
3797 for (uint16_t iMask = 0; iMask <= X86_FCW_MASK_ALL; iMask += X86_FCW_MASK_ALL) \
3798 { \
3799 State.FCW = (fFcw & ~(X86_FCW_MASK_ALL)) | iMask; \
3800 uint16_t fFswOut = 0; \
3801 a_aSubTests[iFn].pfn(&State, &fFswOut, &InVal1, &InVal2); \
3802 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%c */\n", \
3803 State.FCW, State.FSW, fFswOut, GenFormatR80(&InVal1), GenFormat ## a_UpBits(&InVal2), \
3804 iTest, iMask ? 'c' : 'u'); \
3805 } \
3806 } \
3807 GenerateArrayEnd(pOut, a_aSubTests[iFn].pszName); \
3808 } \
3809}
3810#else
3811# define GEN_FPU_BINARY_FSW(a_fIntType, a_cBits, a_UpBits, a_Type2, a_aSubTests, a_TestType)
3812#endif
3813
3814#define TEST_FPU_BINARY_FSW(a_fIntType, a_cBits, a_UpBits, a_Type2, a_SubTestType, a_aSubTests, a_TestType, ...) \
3815TYPEDEF_SUBTEST_TYPE(a_SubTestType, a_TestType, PFNIEMAIMPLFPU ## a_UpBits ## FSW); \
3816\
3817static const a_SubTestType a_aSubTests[] = \
3818{ \
3819 __VA_ARGS__ \
3820}; \
3821\
3822GEN_FPU_BINARY_FSW(a_fIntType, a_cBits, a_UpBits, a_Type2, a_aSubTests, a_TestType) \
3823\
3824static void FpuBinaryFsw ## a_UpBits ## Test(void) \
3825{ \
3826 X86FXSTATE State; \
3827 RT_ZERO(State); \
3828 for (size_t iFn = 0; iFn < RT_ELEMENTS(a_aSubTests); iFn++) \
3829 { \
3830 if (!SubTestAndCheckIfEnabled(a_aSubTests[iFn].pszName)) continue; \
3831 \
3832 uint32_t const cTests = *a_aSubTests[iFn].pcTests; \
3833 a_TestType const * const paTests = a_aSubTests[iFn].paTests; \
3834 PFNIEMAIMPLFPU ## a_UpBits ## FSW pfn = a_aSubTests[iFn].pfn; \
3835 uint32_t const cVars = COUNT_VARIATIONS(a_aSubTests[iFn]); \
3836 if (!cTests) RTTestSkipped(g_hTest, "no tests"); \
3837 for (uint32_t iVar = 0; iVar < cVars; iVar++) \
3838 { \
3839 for (uint32_t iTest = 0; iTest < cTests; iTest++) \
3840 { \
3841 uint16_t fFswOut = 0; \
3842 RTFLOAT80U const InVal1 = paTests[iTest].InVal1; \
3843 a_Type2 const InVal2 = paTests[iTest].InVal2; \
3844 State.FCW = paTests[iTest].fFcw; \
3845 State.FSW = paTests[iTest].fFswIn; \
3846 pfn(&State, &fFswOut, &InVal1, &InVal2); \
3847 if (fFswOut != paTests[iTest].fFswOut) \
3848 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in1=%s in2=%s\n" \
3849 "%s -> fsw=%#06x\n" \
3850 "%s expected %#06x %s (%s)\n", \
3851 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn, \
3852 FormatR80(&paTests[iTest].InVal1), Format ## a_UpBits(&paTests[iTest].InVal2), \
3853 iVar ? " " : "", fFswOut, \
3854 iVar ? " " : "", paTests[iTest].fFswOut, \
3855 FswDiff(fFswOut, paTests[iTest].fFswOut), FormatFcw(paTests[iTest].fFcw) ); \
3856 } \
3857 pfn = a_aSubTests[iFn].pfnNative; \
3858 } \
3859 } \
3860}
3861
3862TEST_FPU_BINARY_FSW(0, 80, R80, RTFLOAT80U, FPU_BINARY_FSW_R80_T, g_aFpuBinaryFswR80, FPU_BINARY_R80_TEST_T, ENTRY(fcom_r80_by_r80), ENTRY(fucom_r80_by_r80))
3863TEST_FPU_BINARY_FSW(0, 64, R64, RTFLOAT64U, FPU_BINARY_FSW_R64_T, g_aFpuBinaryFswR64, FPU_BINARY_R64_TEST_T, ENTRY(fcom_r80_by_r64))
3864TEST_FPU_BINARY_FSW(0, 32, R32, RTFLOAT32U, FPU_BINARY_FSW_R32_T, g_aFpuBinaryFswR32, FPU_BINARY_R32_TEST_T, ENTRY(fcom_r80_by_r32))
3865TEST_FPU_BINARY_FSW(1, 32, I32, int32_t, FPU_BINARY_FSW_I32_T, g_aFpuBinaryFswI32, FPU_BINARY_I32_TEST_T, ENTRY(ficom_r80_by_i32))
3866TEST_FPU_BINARY_FSW(1, 16, I16, int16_t, FPU_BINARY_FSW_I16_T, g_aFpuBinaryFswI16, FPU_BINARY_I16_TEST_T, ENTRY(ficom_r80_by_i16))
3867
3868
3869/*
3870 * Binary operations on 80-bit floating point that effects only EFLAGS and possibly FSW.
3871 */
3872TYPEDEF_SUBTEST_TYPE(FPU_BINARY_EFL_R80_T, FPU_BINARY_EFL_R80_TEST_T, PFNIEMAIMPLFPUR80EFL);
3873
3874static const FPU_BINARY_EFL_R80_T g_aFpuBinaryEflR80[] =
3875{
3876 ENTRY(fcomi_r80_by_r80),
3877 ENTRY(fucomi_r80_by_r80),
3878};
3879
3880#ifdef TSTIEMAIMPL_WITH_GENERATOR
3881static struct { RTFLOAT80U Val1, Val2; } const s_aFpuBinaryEflR80Specials[] =
3882{
3883 { RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS),
3884 RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS) }, /* whatever */
3885};
3886
3887static void FpuBinaryEflR80Generate(PRTSTREAM pOut, uint32_t cTests)
3888{
3889 cTests = RT_MAX(160, cTests); /* there are 144 standard input variations */
3890
3891 X86FXSTATE State;
3892 RT_ZERO(State);
3893 uint32_t cMinNormalPairs = (cTests - 144) / 4;
3894 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuBinaryEflR80); iFn++)
3895 {
3896 GenerateArrayStart(pOut, g_aFpuBinaryEflR80[iFn].pszName, "FPU_BINARY_EFL_R80_TEST_T");
3897 uint32_t cNormalInputPairs = 0;
3898 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aFpuBinaryEflR80Specials); iTest += 1)
3899 {
3900 RTFLOAT80U const InVal1 = iTest < cTests ? RandR80Src1(iTest) : s_aFpuBinaryEflR80Specials[iTest - cTests].Val1;
3901 RTFLOAT80U const InVal2 = iTest < cTests ? RandR80Src2(iTest) : s_aFpuBinaryEflR80Specials[iTest - cTests].Val2;
3902 if (RTFLOAT80U_IS_NORMAL(&InVal1) && RTFLOAT80U_IS_NORMAL(&InVal2))
3903 cNormalInputPairs++;
3904 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
3905 {
3906 iTest -= 1;
3907 continue;
3908 }
3909
3910 uint16_t const fFcw = RandFcw();
3911 State.FSW = RandFsw();
3912
3913 /* Guess these aren't affected by precision or rounding, so just flip the exception mask. */
3914 for (uint16_t iMask = 0; iMask <= X86_FCW_MASK_ALL; iMask += X86_FCW_MASK_ALL)
3915 {
3916 State.FCW = (fFcw & ~(X86_FCW_MASK_ALL)) | iMask;
3917 uint16_t uFswOut = 0;
3918 uint32_t fEflOut = g_aFpuBinaryEflR80[iFn].pfn(&State, &uFswOut, &InVal1, &InVal2);
3919 RTStrmPrintf(pOut, " { %#06x, %#06x, %#06x, %s, %s, %#08x }, /* #%u/%c */\n",
3920 State.FCW, State.FSW, uFswOut, GenFormatR80(&InVal1), GenFormatR80(&InVal2), fEflOut,
3921 iTest, iMask ? 'c' : 'u');
3922 }
3923 }
3924 GenerateArrayEnd(pOut, g_aFpuBinaryEflR80[iFn].pszName);
3925 }
3926}
3927#endif /*TSTIEMAIMPL_WITH_GENERATOR*/
3928
3929static void FpuBinaryEflR80Test(void)
3930{
3931 X86FXSTATE State;
3932 RT_ZERO(State);
3933 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuBinaryEflR80); iFn++)
3934 {
3935 if (!SubTestAndCheckIfEnabled(g_aFpuBinaryEflR80[iFn].pszName))
3936 continue;
3937
3938 uint32_t const cTests = *g_aFpuBinaryEflR80[iFn].pcTests;
3939 FPU_BINARY_EFL_R80_TEST_T const * const paTests = g_aFpuBinaryEflR80[iFn].paTests;
3940 PFNIEMAIMPLFPUR80EFL pfn = g_aFpuBinaryEflR80[iFn].pfn;
3941 uint32_t const cVars = COUNT_VARIATIONS(g_aFpuBinaryEflR80[iFn]);
3942 if (!cTests) RTTestSkipped(g_hTest, "no tests");
3943 for (uint32_t iVar = 0; iVar < cVars; iVar++)
3944 {
3945 for (uint32_t iTest = 0; iTest < cTests; iTest++)
3946 {
3947 RTFLOAT80U const InVal1 = paTests[iTest].InVal1;
3948 RTFLOAT80U const InVal2 = paTests[iTest].InVal2;
3949 State.FCW = paTests[iTest].fFcw;
3950 State.FSW = paTests[iTest].fFswIn;
3951 uint16_t uFswOut = 0;
3952 uint32_t fEflOut = pfn(&State, &uFswOut, &InVal1, &InVal2);
3953 if ( uFswOut != paTests[iTest].fFswOut
3954 || fEflOut != paTests[iTest].fEflOut)
3955 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in1=%s in2=%s\n"
3956 "%s -> fsw=%#06x efl=%#08x\n"
3957 "%s expected %#06x %#08x %s%s (%s)\n",
3958 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
3959 FormatR80(&paTests[iTest].InVal1), FormatR80(&paTests[iTest].InVal2),
3960 iVar ? " " : "", uFswOut, fEflOut,
3961 iVar ? " " : "", paTests[iTest].fFswOut, paTests[iTest].fEflOut,
3962 FswDiff(uFswOut, paTests[iTest].fFswOut), EFlagsDiff(fEflOut, paTests[iTest].fEflOut),
3963 FormatFcw(paTests[iTest].fFcw));
3964 }
3965 pfn = g_aFpuBinaryEflR80[iFn].pfnNative;
3966 }
3967 }
3968}
3969
3970
3971/*********************************************************************************************************************************
3972* x87 FPU Unary Operations *
3973*********************************************************************************************************************************/
3974
3975/*
3976 * Unary FPU operations on one 80-bit floating point value.
3977 *
3978 * Note! The FCW reserved bit 7 is used to indicate whether a test may produce
3979 * a rounding error or not.
3980 */
3981TYPEDEF_SUBTEST_TYPE(FPU_UNARY_R80_T, FPU_UNARY_R80_TEST_T, PFNIEMAIMPLFPUR80UNARY);
3982
3983enum { kUnary_Accurate = 0, kUnary_Accurate_Trigonometry /*probably not accurate, but need impl to know*/, kUnary_Rounding_F2xm1 };
3984static const FPU_UNARY_R80_T g_aFpuUnaryR80[] =
3985{
3986 ENTRY_EX( fabs_r80, kUnary_Accurate),
3987 ENTRY_EX( fchs_r80, kUnary_Accurate),
3988 ENTRY_AMD_EX( f2xm1_r80, 0, kUnary_Accurate), // C1 differs for -1m0x3fb263cc2c331e15^-2654 (different ln2 constant?)
3989 ENTRY_INTEL_EX(f2xm1_r80, 0, kUnary_Rounding_F2xm1),
3990 ENTRY_EX( fsqrt_r80, kUnary_Accurate),
3991 ENTRY_EX( frndint_r80, kUnary_Accurate),
3992 ENTRY_AMD_EX( fsin_r80, 0, kUnary_Accurate_Trigonometry), // value & C1 differences for pseudo denormals and others (e.g. -1m0x2b1e5683cbca5725^-3485)
3993 ENTRY_INTEL_EX(fsin_r80, 0, kUnary_Accurate_Trigonometry),
3994 ENTRY_AMD_EX( fcos_r80, 0, kUnary_Accurate_Trigonometry), // value & C1 differences
3995 ENTRY_INTEL_EX(fcos_r80, 0, kUnary_Accurate_Trigonometry),
3996};
3997
3998#ifdef TSTIEMAIMPL_WITH_GENERATOR
3999
4000static bool FpuUnaryR80MayHaveRoundingError(PCRTFLOAT80U pr80Val, int enmKind)
4001{
4002 if ( enmKind == kUnary_Rounding_F2xm1
4003 && RTFLOAT80U_IS_NORMAL(pr80Val)
4004 && pr80Val->s.uExponent < RTFLOAT80U_EXP_BIAS
4005 && pr80Val->s.uExponent >= RTFLOAT80U_EXP_BIAS - 69)
4006 return true;
4007 return false;
4008}
4009
4010static void FpuUnaryR80Generate(PRTSTREAM pOut, PRTSTREAM pOutCpu, uint32_t cTests)
4011{
4012 static RTFLOAT80U const s_aSpecials[] =
4013 {
4014 RTFLOAT80U_INIT_C(0, 0x8000000000000000, RTFLOAT80U_EXP_BIAS - 1), /* 0.5 (for f2xm1) */
4015 RTFLOAT80U_INIT_C(1, 0x8000000000000000, RTFLOAT80U_EXP_BIAS - 1), /* -0.5 (for f2xm1) */
4016 RTFLOAT80U_INIT_C(0, 0x8000000000000000, RTFLOAT80U_EXP_BIAS), /* 1.0 (for f2xm1) */
4017 RTFLOAT80U_INIT_C(1, 0x8000000000000000, RTFLOAT80U_EXP_BIAS), /* -1.0 (for f2xm1) */
4018 RTFLOAT80U_INIT_C(0, 0x8000000000000000, 0), /* +1.0^-16382 */
4019 RTFLOAT80U_INIT_C(1, 0x8000000000000000, 0), /* -1.0^-16382 */
4020 RTFLOAT80U_INIT_C(0, 0xc000000000000000, 0), /* +1.1^-16382 */
4021 RTFLOAT80U_INIT_C(1, 0xc000000000000000, 0), /* -1.1^-16382 */
4022 RTFLOAT80U_INIT_C(0, 0xc000100000000000, 0), /* +1.1xxx1^-16382 */
4023 RTFLOAT80U_INIT_C(1, 0xc000100000000000, 0), /* -1.1xxx1^-16382 */
4024 };
4025 X86FXSTATE State;
4026 RT_ZERO(State);
4027 uint32_t cMinNormals = cTests / 4;
4028 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuUnaryR80); iFn++)
4029 {
4030 PFNIEMAIMPLFPUR80UNARY const pfn = g_aFpuUnaryR80[iFn].pfnNative ? g_aFpuUnaryR80[iFn].pfnNative : g_aFpuUnaryR80[iFn].pfn;
4031 PRTSTREAM pOutFn = pOut;
4032 if (g_aFpuUnaryR80[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE)
4033 {
4034 if (g_aFpuUnaryR80[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour)
4035 continue;
4036 pOutFn = pOutCpu;
4037 }
4038
4039 GenerateArrayStart(pOutFn, g_aFpuUnaryR80[iFn].pszName, "FPU_UNARY_R80_TEST_T");
4040 uint32_t iTestOutput = 0;
4041 uint32_t cNormalInputs = 0;
4042 uint32_t cTargetRangeInputs = 0;
4043 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
4044 {
4045 RTFLOAT80U InVal = iTest < cTests ? RandR80Src(iTest) : s_aSpecials[iTest - cTests];
4046 if (RTFLOAT80U_IS_NORMAL(&InVal))
4047 {
4048 if (g_aFpuUnaryR80[iFn].uExtra == kUnary_Rounding_F2xm1)
4049 {
4050 unsigned uTargetExp = g_aFpuUnaryR80[iFn].uExtra == kUnary_Rounding_F2xm1
4051 ? RTFLOAT80U_EXP_BIAS /* 2^0..2^-69 */ : RTFLOAT80U_EXP_BIAS + 63 + 1 /* 2^64..2^-64 */;
4052 unsigned cTargetExp = g_aFpuUnaryR80[iFn].uExtra == kUnary_Rounding_F2xm1 ? 69 : 63*2 + 2;
4053 if (InVal.s.uExponent <= uTargetExp && InVal.s.uExponent >= uTargetExp - cTargetExp)
4054 cTargetRangeInputs++;
4055 else if (cTargetRangeInputs < cMinNormals / 2 && iTest + cMinNormals / 2 >= cTests && iTest < cTests)
4056 {
4057 InVal.s.uExponent = RTRandU32Ex(uTargetExp - cTargetExp, uTargetExp);
4058 cTargetRangeInputs++;
4059 }
4060 }
4061 cNormalInputs++;
4062 }
4063 else if (cNormalInputs < cMinNormals && iTest + cMinNormals >= cTests && iTest < cTests)
4064 {
4065 iTest -= 1;
4066 continue;
4067 }
4068
4069 uint16_t const fFcwExtra = FpuUnaryR80MayHaveRoundingError(&InVal, g_aFpuUnaryR80[iFn].uExtra) ? 0x80 : 0;
4070 uint16_t const fFcw = RandFcw();
4071 State.FSW = RandFsw();
4072
4073 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
4074 for (uint16_t iPrecision = 0; iPrecision < 4; iPrecision++)
4075 {
4076 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_PC_MASK | X86_FCW_MASK_ALL))
4077 | (iRounding << X86_FCW_RC_SHIFT)
4078 | (iPrecision << X86_FCW_PC_SHIFT)
4079 | X86_FCW_MASK_ALL;
4080 IEMFPURESULT ResM = { RTFLOAT80U_INIT(0, 0, 0), 0 };
4081 pfn(&State, &ResM, &InVal);
4082 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u/%u/m = #%u */\n",
4083 State.FCW | fFcwExtra, State.FSW, ResM.FSW, GenFormatR80(&InVal),
4084 GenFormatR80(&ResM.r80Result), iTest, iRounding, iPrecision, iTestOutput++);
4085
4086 State.FCW = State.FCW & ~X86_FCW_MASK_ALL;
4087 IEMFPURESULT ResU = { RTFLOAT80U_INIT(0, 0, 0), 0 };
4088 pfn(&State, &ResU, &InVal);
4089 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u/%u/u = #%u */\n",
4090 State.FCW | fFcwExtra, State.FSW, ResU.FSW, GenFormatR80(&InVal),
4091 GenFormatR80(&ResU.r80Result), iTest, iRounding, iPrecision, iTestOutput++);
4092
4093 uint16_t fXcpt = (ResM.FSW | ResU.FSW) & X86_FSW_XCPT_MASK & ~X86_FSW_SF;
4094 if (fXcpt)
4095 {
4096 State.FCW = (State.FCW & ~X86_FCW_MASK_ALL) | fXcpt;
4097 IEMFPURESULT Res1 = { RTFLOAT80U_INIT(0, 0, 0), 0 };
4098 pfn(&State, &Res1, &InVal);
4099 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u/%u/%#x = #%u */\n",
4100 State.FCW | fFcwExtra, State.FSW, Res1.FSW, GenFormatR80(&InVal),
4101 GenFormatR80(&Res1.r80Result), iTest, iRounding, iPrecision, fXcpt, iTestOutput++);
4102 if (((Res1.FSW & X86_FSW_XCPT_MASK) & fXcpt) != (Res1.FSW & X86_FSW_XCPT_MASK))
4103 {
4104 fXcpt |= Res1.FSW & X86_FSW_XCPT_MASK;
4105 State.FCW = (State.FCW & ~X86_FCW_MASK_ALL) | fXcpt;
4106 IEMFPURESULT Res2 = { RTFLOAT80U_INIT(0, 0, 0), 0 };
4107 pfn(&State, &Res2, &InVal);
4108 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u/%u/%#x[!] = #%u */\n",
4109 State.FCW | fFcwExtra, State.FSW, Res2.FSW, GenFormatR80(&InVal),
4110 GenFormatR80(&Res2.r80Result), iTest, iRounding, iPrecision, fXcpt, iTestOutput++);
4111 }
4112 if (!RT_IS_POWER_OF_TWO(fXcpt))
4113 for (uint16_t fUnmasked = 1; fUnmasked <= X86_FCW_PM; fUnmasked <<= 1)
4114 if (fUnmasked & fXcpt)
4115 {
4116 State.FCW = (State.FCW & ~X86_FCW_MASK_ALL) | (fXcpt & ~fUnmasked);
4117 IEMFPURESULT Res3 = { RTFLOAT80U_INIT(0, 0, 0), 0 };
4118 pfn(&State, &Res3, &InVal);
4119 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s }, /* #%u/%u/%u/u%#x = #%u */\n",
4120 State.FCW | fFcwExtra, State.FSW, Res3.FSW, GenFormatR80(&InVal),
4121 GenFormatR80(&Res3.r80Result), iTest, iRounding, iPrecision, fUnmasked, iTestOutput++);
4122 }
4123 }
4124 }
4125 }
4126 GenerateArrayEnd(pOutFn, g_aFpuUnaryR80[iFn].pszName);
4127 }
4128}
4129#endif
4130
4131static bool FpuIsEqualFcwMaybeIgnoreRoundErr(uint16_t fFcw1, uint16_t fFcw2, bool fRndErrOk, bool *pfRndErr)
4132{
4133 if (fFcw1 == fFcw2)
4134 return true;
4135 if (fRndErrOk && (fFcw1 & ~X86_FSW_C1) == (fFcw2 & ~X86_FSW_C1))
4136 {
4137 *pfRndErr = true;
4138 return true;
4139 }
4140 return false;
4141}
4142
4143static bool FpuIsEqualR80MaybeIgnoreRoundErr(PCRTFLOAT80U pr80Val1, PCRTFLOAT80U pr80Val2, bool fRndErrOk, bool *pfRndErr)
4144{
4145 if (RTFLOAT80U_ARE_IDENTICAL(pr80Val1, pr80Val2))
4146 return true;
4147 if ( fRndErrOk
4148 && pr80Val1->s.fSign == pr80Val2->s.fSign)
4149 {
4150 if ( ( pr80Val1->s.uExponent == pr80Val2->s.uExponent
4151 && ( pr80Val1->s.uMantissa > pr80Val2->s.uMantissa
4152 ? pr80Val1->s.uMantissa - pr80Val2->s.uMantissa == 1
4153 : pr80Val2->s.uMantissa - pr80Val1->s.uMantissa == 1))
4154 ||
4155 ( pr80Val1->s.uExponent + 1 == pr80Val2->s.uExponent
4156 && pr80Val1->s.uMantissa == UINT64_MAX
4157 && pr80Val2->s.uMantissa == RT_BIT_64(63))
4158 ||
4159 ( pr80Val1->s.uExponent == pr80Val2->s.uExponent + 1
4160 && pr80Val2->s.uMantissa == UINT64_MAX
4161 && pr80Val1->s.uMantissa == RT_BIT_64(63)) )
4162 {
4163 *pfRndErr = true;
4164 return true;
4165 }
4166 }
4167 return false;
4168}
4169
4170
4171static void FpuUnaryR80Test(void)
4172{
4173 X86FXSTATE State;
4174 RT_ZERO(State);
4175 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuUnaryR80); iFn++)
4176 {
4177 if (!SubTestAndCheckIfEnabled(g_aFpuUnaryR80[iFn].pszName))
4178 continue;
4179
4180 uint32_t const cTests = *g_aFpuUnaryR80[iFn].pcTests;
4181 FPU_UNARY_R80_TEST_T const * const paTests = g_aFpuUnaryR80[iFn].paTests;
4182 PFNIEMAIMPLFPUR80UNARY pfn = g_aFpuUnaryR80[iFn].pfn;
4183 uint32_t const cVars = COUNT_VARIATIONS(g_aFpuUnaryR80[iFn]);
4184 uint32_t cRndErrs = 0;
4185 uint32_t cPossibleRndErrs = 0;
4186 if (!cTests) RTTestSkipped(g_hTest, "no tests");
4187 for (uint32_t iVar = 0; iVar < cVars; iVar++)
4188 {
4189 for (uint32_t iTest = 0; iTest < cTests; iTest++)
4190 {
4191 RTFLOAT80U const InVal = paTests[iTest].InVal;
4192 IEMFPURESULT Res = { RTFLOAT80U_INIT(0, 0, 0), 0 };
4193 bool const fRndErrOk = RT_BOOL(paTests[iTest].fFcw & 0x80);
4194 State.FCW = paTests[iTest].fFcw & ~(uint16_t)0x80;
4195 State.FSW = paTests[iTest].fFswIn;
4196 pfn(&State, &Res, &InVal);
4197 bool fRndErr = false;
4198 if ( !FpuIsEqualFcwMaybeIgnoreRoundErr(Res.FSW, paTests[iTest].fFswOut, fRndErrOk, &fRndErr)
4199 || !FpuIsEqualR80MaybeIgnoreRoundErr(&Res.r80Result, &paTests[iTest].OutVal, fRndErrOk, &fRndErr))
4200 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in=%s\n"
4201 "%s -> fsw=%#06x %s\n"
4202 "%s expected %#06x %s%s%s%s (%s)\n",
4203 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
4204 FormatR80(&paTests[iTest].InVal),
4205 iVar ? " " : "", Res.FSW, FormatR80(&Res.r80Result),
4206 iVar ? " " : "", paTests[iTest].fFswOut, FormatR80(&paTests[iTest].OutVal),
4207 FswDiff(Res.FSW, paTests[iTest].fFswOut),
4208 !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result, &paTests[iTest].OutVal) ? " - val" : "",
4209 fRndErrOk ? " - rounding errors ok" : "", FormatFcw(paTests[iTest].fFcw));
4210 cRndErrs += fRndErr;
4211 cPossibleRndErrs += fRndErrOk;
4212 }
4213 pfn = g_aFpuUnaryR80[iFn].pfnNative;
4214 }
4215 if (cPossibleRndErrs > 0)
4216 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "rounding errors: %u out of %u\n", cRndErrs, cPossibleRndErrs);
4217 }
4218}
4219
4220
4221/*
4222 * Unary FPU operations on one 80-bit floating point value, but only affects the FSW.
4223 */
4224TYPEDEF_SUBTEST_TYPE(FPU_UNARY_FSW_R80_T, FPU_UNARY_R80_TEST_T, PFNIEMAIMPLFPUR80UNARYFSW);
4225
4226static const FPU_UNARY_FSW_R80_T g_aFpuUnaryFswR80[] =
4227{
4228 ENTRY(ftst_r80),
4229 ENTRY_EX(fxam_r80, 1),
4230};
4231
4232#ifdef TSTIEMAIMPL_WITH_GENERATOR
4233static void FpuUnaryFswR80Generate(PRTSTREAM pOut, PRTSTREAM pOutCpu, uint32_t cTests)
4234{
4235 static RTFLOAT80U const s_aSpecials[] =
4236 {
4237 RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS), /* whatever */
4238 };
4239
4240 X86FXSTATE State;
4241 RT_ZERO(State);
4242 uint32_t cMinNormals = cTests / 4;
4243 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuUnaryFswR80); iFn++)
4244 {
4245 bool const fIsFxam = g_aFpuUnaryFswR80[iFn].uExtra == 1;
4246 PFNIEMAIMPLFPUR80UNARYFSW const pfn = g_aFpuUnaryFswR80[iFn].pfnNative ? g_aFpuUnaryFswR80[iFn].pfnNative : g_aFpuUnaryFswR80[iFn].pfn;
4247 PRTSTREAM pOutFn = pOut;
4248 if (g_aFpuUnaryFswR80[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE)
4249 {
4250 if (g_aFpuUnaryFswR80[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour)
4251 continue;
4252 pOutFn = pOutCpu;
4253 }
4254 State.FTW = 0;
4255
4256 GenerateArrayStart(pOutFn, g_aFpuUnaryFswR80[iFn].pszName, "FPU_UNARY_R80_TEST_T");
4257 uint32_t cNormalInputs = 0;
4258 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
4259 {
4260 RTFLOAT80U const InVal = iTest < cTests ? RandR80Src(iTest) : s_aSpecials[iTest - cTests];
4261 if (RTFLOAT80U_IS_NORMAL(&InVal))
4262 cNormalInputs++;
4263 else if (cNormalInputs < cMinNormals && iTest + cMinNormals >= cTests && iTest < cTests)
4264 {
4265 iTest -= 1;
4266 continue;
4267 }
4268
4269 uint16_t const fFcw = RandFcw();
4270 State.FSW = RandFsw();
4271 if (!fIsFxam)
4272 {
4273 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
4274 {
4275 for (uint16_t iPrecision = 0; iPrecision < 4; iPrecision++)
4276 {
4277 for (uint16_t iMask = 0; iMask <= X86_FCW_MASK_ALL; iMask += X86_FCW_MASK_ALL)
4278 {
4279 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_PC_MASK | X86_FCW_MASK_ALL))
4280 | (iRounding << X86_FCW_RC_SHIFT)
4281 | (iPrecision << X86_FCW_PC_SHIFT)
4282 | iMask;
4283 uint16_t fFswOut = 0;
4284 pfn(&State, &fFswOut, &InVal);
4285 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s }, /* #%u/%u/%u/%c */\n",
4286 State.FCW, State.FSW, fFswOut, GenFormatR80(&InVal),
4287 iTest, iRounding, iPrecision, iMask ? 'c' : 'u');
4288 }
4289 }
4290 }
4291 }
4292 else
4293 {
4294 uint16_t fFswOut = 0;
4295 uint16_t const fEmpty = RTRandU32Ex(0, 3) == 3 ? 0x80 : 0; /* Using MBZ bit 7 in FCW to indicate empty tag value. */
4296 State.FTW = !fEmpty ? 1 << X86_FSW_TOP_GET(State.FSW) : 0;
4297 State.FCW = fFcw;
4298 pfn(&State, &fFswOut, &InVal);
4299 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s }, /* #%u%s */\n",
4300 fFcw | fEmpty, State.FSW, fFswOut, GenFormatR80(&InVal), iTest, fEmpty ? "/empty" : "");
4301 }
4302 }
4303 GenerateArrayEnd(pOutFn, g_aFpuUnaryFswR80[iFn].pszName);
4304 }
4305}
4306#endif
4307
4308
4309static void FpuUnaryFswR80Test(void)
4310{
4311 X86FXSTATE State;
4312 RT_ZERO(State);
4313 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuUnaryFswR80); iFn++)
4314 {
4315 if (!SubTestAndCheckIfEnabled(g_aFpuUnaryFswR80[iFn].pszName))
4316 continue;
4317
4318 uint32_t const cTests = *g_aFpuUnaryFswR80[iFn].pcTests;
4319 FPU_UNARY_R80_TEST_T const * const paTests = g_aFpuUnaryFswR80[iFn].paTests;
4320 PFNIEMAIMPLFPUR80UNARYFSW pfn = g_aFpuUnaryFswR80[iFn].pfn;
4321 uint32_t const cVars = COUNT_VARIATIONS(g_aFpuUnaryFswR80[iFn]);
4322 if (!cTests) RTTestSkipped(g_hTest, "no tests");
4323 for (uint32_t iVar = 0; iVar < cVars; iVar++)
4324 {
4325 for (uint32_t iTest = 0; iTest < cTests; iTest++)
4326 {
4327 RTFLOAT80U const InVal = paTests[iTest].InVal;
4328 uint16_t fFswOut = 0;
4329 State.FSW = paTests[iTest].fFswIn;
4330 State.FCW = paTests[iTest].fFcw & ~(uint16_t)0x80; /* see generator code */
4331 State.FTW = paTests[iTest].fFcw & 0x80 ? 0 : 1 << X86_FSW_TOP_GET(paTests[iTest].fFswIn);
4332 pfn(&State, &fFswOut, &InVal);
4333 if (fFswOut != paTests[iTest].fFswOut)
4334 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in=%s\n"
4335 "%s -> fsw=%#06x\n"
4336 "%s expected %#06x %s (%s%s)\n",
4337 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
4338 FormatR80(&paTests[iTest].InVal),
4339 iVar ? " " : "", fFswOut,
4340 iVar ? " " : "", paTests[iTest].fFswOut,
4341 FswDiff(fFswOut, paTests[iTest].fFswOut), FormatFcw(paTests[iTest].fFcw),
4342 paTests[iTest].fFcw & 0x80 ? " empty" : "");
4343 }
4344 pfn = g_aFpuUnaryFswR80[iFn].pfnNative;
4345 }
4346 }
4347}
4348
4349/*
4350 * Unary FPU operations on one 80-bit floating point value, but with two outputs.
4351 */
4352TYPEDEF_SUBTEST_TYPE(FPU_UNARY_TWO_R80_T, FPU_UNARY_TWO_R80_TEST_T, PFNIEMAIMPLFPUR80UNARYTWO);
4353
4354static const FPU_UNARY_TWO_R80_T g_aFpuUnaryTwoR80[] =
4355{
4356 ENTRY(fxtract_r80_r80),
4357 ENTRY_AMD( fptan_r80_r80, 0), // rounding differences
4358 ENTRY_INTEL(fptan_r80_r80, 0),
4359 ENTRY_AMD( fsincos_r80_r80, 0), // C1 differences & value differences (e.g. -1m0x235cf2f580244a27^-1696)
4360 ENTRY_INTEL(fsincos_r80_r80, 0),
4361};
4362
4363#ifdef TSTIEMAIMPL_WITH_GENERATOR
4364static void FpuUnaryTwoR80Generate(PRTSTREAM pOut, PRTSTREAM pOutCpu, uint32_t cTests)
4365{
4366 static RTFLOAT80U const s_aSpecials[] =
4367 {
4368 RTFLOAT80U_INIT_C(0, 0xffffeeeeddddcccc, RTFLOAT80U_EXP_BIAS), /* whatever */
4369 };
4370
4371 X86FXSTATE State;
4372 RT_ZERO(State);
4373 uint32_t cMinNormals = cTests / 4;
4374 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuUnaryTwoR80); iFn++)
4375 {
4376 PFNIEMAIMPLFPUR80UNARYTWO const pfn = g_aFpuUnaryTwoR80[iFn].pfnNative ? g_aFpuUnaryTwoR80[iFn].pfnNative : g_aFpuUnaryTwoR80[iFn].pfn;
4377 PRTSTREAM pOutFn = pOut;
4378 if (g_aFpuUnaryTwoR80[iFn].idxCpuEflFlavour != IEMTARGETCPU_EFL_BEHAVIOR_NATIVE)
4379 {
4380 if (g_aFpuUnaryTwoR80[iFn].idxCpuEflFlavour != g_idxCpuEflFlavour)
4381 continue;
4382 pOutFn = pOutCpu;
4383 }
4384
4385 GenerateArrayStart(pOutFn, g_aFpuUnaryTwoR80[iFn].pszName, "FPU_UNARY_TWO_R80_TEST_T");
4386 uint32_t iTestOutput = 0;
4387 uint32_t cNormalInputs = 0;
4388 uint32_t cTargetRangeInputs = 0;
4389 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
4390 {
4391 RTFLOAT80U InVal = iTest < cTests ? RandR80Src(iTest) : s_aSpecials[iTest - cTests];
4392 if (RTFLOAT80U_IS_NORMAL(&InVal))
4393 {
4394 if (iFn != 0)
4395 {
4396 unsigned uTargetExp = RTFLOAT80U_EXP_BIAS + 63 + 1 /* 2^64..2^-64 */;
4397 unsigned cTargetExp = g_aFpuUnaryR80[iFn].uExtra == kUnary_Rounding_F2xm1 ? 69 : 63*2 + 2;
4398 if (InVal.s.uExponent <= uTargetExp && InVal.s.uExponent >= uTargetExp - cTargetExp)
4399 cTargetRangeInputs++;
4400 else if (cTargetRangeInputs < cMinNormals / 2 && iTest + cMinNormals / 2 >= cTests && iTest < cTests)
4401 {
4402 InVal.s.uExponent = RTRandU32Ex(uTargetExp - cTargetExp, uTargetExp);
4403 cTargetRangeInputs++;
4404 }
4405 }
4406 cNormalInputs++;
4407 }
4408 else if (cNormalInputs < cMinNormals && iTest + cMinNormals >= cTests && iTest < cTests)
4409 {
4410 iTest -= 1;
4411 continue;
4412 }
4413
4414 uint16_t const fFcwExtra = 0; /* for rounding error indication */
4415 uint16_t const fFcw = RandFcw();
4416 State.FSW = RandFsw();
4417
4418 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
4419 for (uint16_t iPrecision = 0; iPrecision < 4; iPrecision++)
4420 {
4421 State.FCW = (fFcw & ~(X86_FCW_RC_MASK | X86_FCW_PC_MASK | X86_FCW_MASK_ALL))
4422 | (iRounding << X86_FCW_RC_SHIFT)
4423 | (iPrecision << X86_FCW_PC_SHIFT)
4424 | X86_FCW_MASK_ALL;
4425 IEMFPURESULTTWO ResM = { RTFLOAT80U_INIT(0, 0, 0), 0, RTFLOAT80U_INIT(0, 0, 0) };
4426 pfn(&State, &ResM, &InVal);
4427 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/m = #%u */\n",
4428 State.FCW | fFcwExtra, State.FSW, ResM.FSW, GenFormatR80(&InVal), GenFormatR80(&ResM.r80Result1),
4429 GenFormatR80(&ResM.r80Result2), iTest, iRounding, iPrecision, iTestOutput++);
4430
4431 State.FCW = State.FCW & ~X86_FCW_MASK_ALL;
4432 IEMFPURESULTTWO ResU = { RTFLOAT80U_INIT(0, 0, 0), 0, RTFLOAT80U_INIT(0, 0, 0) };
4433 pfn(&State, &ResU, &InVal);
4434 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/u = #%u */\n",
4435 State.FCW | fFcwExtra, State.FSW, ResU.FSW, GenFormatR80(&InVal), GenFormatR80(&ResU.r80Result1),
4436 GenFormatR80(&ResU.r80Result2), iTest, iRounding, iPrecision, iTestOutput++);
4437
4438 uint16_t fXcpt = (ResM.FSW | ResU.FSW) & X86_FSW_XCPT_MASK & ~X86_FSW_SF;
4439 if (fXcpt)
4440 {
4441 State.FCW = (State.FCW & ~X86_FCW_MASK_ALL) | fXcpt;
4442 IEMFPURESULTTWO Res1 = { RTFLOAT80U_INIT(0, 0, 0), 0, RTFLOAT80U_INIT(0, 0, 0) };
4443 pfn(&State, &Res1, &InVal);
4444 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/%#x = #%u */\n",
4445 State.FCW | fFcwExtra, State.FSW, Res1.FSW, GenFormatR80(&InVal), GenFormatR80(&Res1.r80Result1),
4446 GenFormatR80(&Res1.r80Result2), iTest, iRounding, iPrecision, fXcpt, iTestOutput++);
4447 if (((Res1.FSW & X86_FSW_XCPT_MASK) & fXcpt) != (Res1.FSW & X86_FSW_XCPT_MASK))
4448 {
4449 fXcpt |= Res1.FSW & X86_FSW_XCPT_MASK;
4450 State.FCW = (State.FCW & ~X86_FCW_MASK_ALL) | fXcpt;
4451 IEMFPURESULTTWO Res2 = { RTFLOAT80U_INIT(0, 0, 0), 0, RTFLOAT80U_INIT(0, 0, 0) };
4452 pfn(&State, &Res2, &InVal);
4453 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/%#x[!] = #%u */\n",
4454 State.FCW | fFcwExtra, State.FSW, Res2.FSW, GenFormatR80(&InVal), GenFormatR80(&Res2.r80Result1),
4455 GenFormatR80(&Res2.r80Result2), iTest, iRounding, iPrecision, fXcpt, iTestOutput++);
4456 }
4457 if (!RT_IS_POWER_OF_TWO(fXcpt))
4458 for (uint16_t fUnmasked = 1; fUnmasked <= X86_FCW_PM; fUnmasked <<= 1)
4459 if (fUnmasked & fXcpt)
4460 {
4461 State.FCW = (State.FCW & ~X86_FCW_MASK_ALL) | (fXcpt & ~fUnmasked);
4462 IEMFPURESULTTWO Res3 = { RTFLOAT80U_INIT(0, 0, 0), 0, RTFLOAT80U_INIT(0, 0, 0) };
4463 pfn(&State, &Res3, &InVal);
4464 RTStrmPrintf(pOutFn, " { %#06x, %#06x, %#06x, %s, %s, %s }, /* #%u/%u/%u/u%#x = #%u */\n",
4465 State.FCW | fFcwExtra, State.FSW, Res3.FSW, GenFormatR80(&InVal), GenFormatR80(&Res3.r80Result1),
4466 GenFormatR80(&Res3.r80Result2), iTest, iRounding, iPrecision, fUnmasked, iTestOutput++);
4467 }
4468 }
4469 }
4470 }
4471 GenerateArrayEnd(pOutFn, g_aFpuUnaryTwoR80[iFn].pszName);
4472 }
4473}
4474#endif
4475
4476
4477static void FpuUnaryTwoR80Test(void)
4478{
4479 X86FXSTATE State;
4480 RT_ZERO(State);
4481 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aFpuUnaryTwoR80); iFn++)
4482 {
4483 if (!SubTestAndCheckIfEnabled(g_aFpuUnaryTwoR80[iFn].pszName))
4484 continue;
4485
4486 uint32_t const cTests = *g_aFpuUnaryTwoR80[iFn].pcTests;
4487 FPU_UNARY_TWO_R80_TEST_T const * const paTests = g_aFpuUnaryTwoR80[iFn].paTests;
4488 PFNIEMAIMPLFPUR80UNARYTWO pfn = g_aFpuUnaryTwoR80[iFn].pfn;
4489 uint32_t const cVars = COUNT_VARIATIONS(g_aFpuUnaryTwoR80[iFn]);
4490 if (!cTests) RTTestSkipped(g_hTest, "no tests");
4491 for (uint32_t iVar = 0; iVar < cVars; iVar++)
4492 {
4493 for (uint32_t iTest = 0; iTest < cTests; iTest++)
4494 {
4495 IEMFPURESULTTWO Res = { RTFLOAT80U_INIT(0, 0, 0), 0, RTFLOAT80U_INIT(0, 0, 0) };
4496 RTFLOAT80U const InVal = paTests[iTest].InVal;
4497 State.FCW = paTests[iTest].fFcw;
4498 State.FSW = paTests[iTest].fFswIn;
4499 pfn(&State, &Res, &InVal);
4500 if ( Res.FSW != paTests[iTest].fFswOut
4501 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result1, &paTests[iTest].OutVal1)
4502 || !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result2, &paTests[iTest].OutVal2) )
4503 RTTestFailed(g_hTest, "#%04u%s: fcw=%#06x fsw=%#06x in=%s\n"
4504 "%s -> fsw=%#06x %s %s\n"
4505 "%s expected %#06x %s %s %s%s%s (%s)\n",
4506 iTest, iVar ? "/n" : "", paTests[iTest].fFcw, paTests[iTest].fFswIn,
4507 FormatR80(&paTests[iTest].InVal),
4508 iVar ? " " : "", Res.FSW, FormatR80(&Res.r80Result1), FormatR80(&Res.r80Result2),
4509 iVar ? " " : "", paTests[iTest].fFswOut,
4510 FormatR80(&paTests[iTest].OutVal1), FormatR80(&paTests[iTest].OutVal2),
4511 !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result1, &paTests[iTest].OutVal1) ? " - val1" : "",
4512 !RTFLOAT80U_ARE_IDENTICAL(&Res.r80Result2, &paTests[iTest].OutVal2) ? " - val2" : "",
4513 FswDiff(Res.FSW, paTests[iTest].fFswOut), FormatFcw(paTests[iTest].fFcw) );
4514 }
4515 pfn = g_aFpuUnaryTwoR80[iFn].pfnNative;
4516 }
4517 }
4518}
4519
4520
4521/*********************************************************************************************************************************
4522* SSE floating point Binary Operations *
4523*********************************************************************************************************************************/
4524
4525/*
4526 * Binary SSE operations on packed single precision floating point values.
4527 */
4528TYPEDEF_SUBTEST_TYPE(SSE_BINARY_R32_T, SSE_BINARY_TEST_T, PFNIEMAIMPLFPSSEF2U128);
4529
4530static const SSE_BINARY_R32_T g_aSseBinaryR32[] =
4531{
4532 ENTRY_BIN(addps_u128),
4533 ENTRY_BIN(mulps_u128),
4534 ENTRY_BIN(subps_u128),
4535 ENTRY_BIN(minps_u128),
4536 ENTRY_BIN(divps_u128),
4537 ENTRY_BIN(maxps_u128),
4538 ENTRY_BIN(haddps_u128),
4539 ENTRY_BIN(hsubps_u128),
4540 ENTRY_BIN(sqrtps_u128),
4541 ENTRY_BIN(addsubps_u128),
4542 ENTRY_BIN(cvtps2pd_u128),
4543};
4544
4545#ifdef TSTIEMAIMPL_WITH_GENERATOR
4546static RTEXITCODE SseBinaryR32Generate(const char *pszDataFileFmt, uint32_t cTests)
4547{
4548 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
4549
4550 static struct { RTFLOAT32U aVal1[4], aVal2[4]; } const s_aSpecials[] =
4551 {
4552 { { RTFLOAT32U_INIT_ZERO(0), RTFLOAT32U_INIT_ZERO(0), RTFLOAT32U_INIT_ZERO(0), RTFLOAT32U_INIT_ZERO(0), },
4553 { RTFLOAT32U_INIT_C(0, 8388607, RTFLOAT32U_EXP_MAX - 1), RTFLOAT32U_INIT_C(0, 8388607, RTFLOAT32U_EXP_MAX - 1), RTFLOAT32U_INIT_C(0, 8388607, RTFLOAT32U_EXP_MAX - 1), RTFLOAT32U_INIT_C(0, 8388607, RTFLOAT32U_EXP_MAX - 1) } },
4554 /** @todo More specials. */
4555 };
4556
4557 X86FXSTATE State;
4558 RT_ZERO(State);
4559 uint32_t cMinNormalPairs = (cTests - 144) / 4;
4560 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryR32); iFn++)
4561 {
4562 PFNIEMAIMPLFPSSEF2U128 const pfn = g_aSseBinaryR32[iFn].pfnNative ? g_aSseBinaryR32[iFn].pfnNative : g_aSseBinaryR32[iFn].pfn;
4563
4564 PRTSTREAM pStrmOut = NULL;
4565 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseBinaryR32[iFn].pszName);
4566 if (RT_FAILURE(rc))
4567 {
4568 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseBinaryR32[iFn].pszName, rc);
4569 return RTEXITCODE_FAILURE;
4570 }
4571
4572 uint32_t cNormalInputPairs = 0;
4573 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
4574 {
4575 SSE_BINARY_TEST_T TestData; RT_ZERO(TestData);
4576
4577 TestData.InVal1.ar32[0] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].aVal1[0];
4578 TestData.InVal1.ar32[1] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].aVal1[1];
4579 TestData.InVal1.ar32[2] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].aVal1[2];
4580 TestData.InVal1.ar32[3] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].aVal1[3];
4581
4582 TestData.InVal2.ar32[0] = iTest < cTests ? RandR32Src2(iTest) : s_aSpecials[iTest - cTests].aVal2[0];
4583 TestData.InVal2.ar32[1] = iTest < cTests ? RandR32Src2(iTest) : s_aSpecials[iTest - cTests].aVal2[1];
4584 TestData.InVal2.ar32[2] = iTest < cTests ? RandR32Src2(iTest) : s_aSpecials[iTest - cTests].aVal2[2];
4585 TestData.InVal2.ar32[3] = iTest < cTests ? RandR32Src2(iTest) : s_aSpecials[iTest - cTests].aVal2[3];
4586
4587 if ( RTFLOAT32U_IS_NORMAL(&TestData.InVal1.ar32[0]) && RTFLOAT32U_IS_NORMAL(&TestData.InVal2.ar32[0])
4588 && RTFLOAT32U_IS_NORMAL(&TestData.InVal1.ar32[1]) && RTFLOAT32U_IS_NORMAL(&TestData.InVal2.ar32[1])
4589 && RTFLOAT32U_IS_NORMAL(&TestData.InVal1.ar32[2]) && RTFLOAT32U_IS_NORMAL(&TestData.InVal2.ar32[2])
4590 && RTFLOAT32U_IS_NORMAL(&TestData.InVal1.ar32[3]) && RTFLOAT32U_IS_NORMAL(&TestData.InVal2.ar32[3]))
4591 cNormalInputPairs++;
4592 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
4593 {
4594 iTest -= 1;
4595 continue;
4596 }
4597
4598 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
4599 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
4600 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
4601 for (uint8_t iFz = 0; iFz < 2; iFz++)
4602 {
4603 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
4604 | (iRounding << X86_MXCSR_RC_SHIFT)
4605 | (iDaz ? X86_MXCSR_DAZ : 0)
4606 | (iFz ? X86_MXCSR_FZ : 0)
4607 | X86_MXCSR_XCPT_MASK;
4608 IEMSSERESULT ResM; RT_ZERO(ResM);
4609 pfn(&State, &ResM, &TestData.InVal1, &TestData.InVal2);
4610 TestData.fMxcsrIn = State.MXCSR;
4611 TestData.fMxcsrOut = ResM.MXCSR;
4612 TestData.OutVal = ResM.uResult;
4613 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
4614
4615 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
4616 IEMSSERESULT ResU; RT_ZERO(ResU);
4617 pfn(&State, &ResU, &TestData.InVal1, &TestData.InVal2);
4618 TestData.fMxcsrIn = State.MXCSR;
4619 TestData.fMxcsrOut = ResU.MXCSR;
4620 TestData.OutVal = ResU.uResult;
4621 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
4622
4623 uint16_t fXcpt = (ResM.MXCSR | ResU.MXCSR) & X86_MXCSR_XCPT_FLAGS;
4624 if (fXcpt)
4625 {
4626 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
4627 IEMSSERESULT Res1; RT_ZERO(Res1);
4628 pfn(&State, &Res1, &TestData.InVal1, &TestData.InVal2);
4629 TestData.fMxcsrIn = State.MXCSR;
4630 TestData.fMxcsrOut = Res1.MXCSR;
4631 TestData.OutVal = Res1.uResult;
4632 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
4633
4634 if (((Res1.MXCSR & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (Res1.MXCSR & X86_MXCSR_XCPT_FLAGS))
4635 {
4636 fXcpt |= Res1.MXCSR & X86_MXCSR_XCPT_FLAGS;
4637 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
4638 IEMSSERESULT Res2; RT_ZERO(Res2);
4639 pfn(&State, &Res2, &TestData.InVal1, &TestData.InVal2);
4640 TestData.fMxcsrIn = State.MXCSR;
4641 TestData.fMxcsrOut = Res2.MXCSR;
4642 TestData.OutVal = Res2.uResult;
4643 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
4644 }
4645 if (!RT_IS_POWER_OF_TWO(fXcpt))
4646 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
4647 if (fUnmasked & fXcpt)
4648 {
4649 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
4650 IEMSSERESULT Res3; RT_ZERO(Res3);
4651 pfn(&State, &Res3, &TestData.InVal1, &TestData.InVal2);
4652 TestData.fMxcsrIn = State.MXCSR;
4653 TestData.fMxcsrOut = Res3.MXCSR;
4654 TestData.OutVal = Res3.uResult;
4655 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
4656 }
4657 }
4658 }
4659 }
4660 rc = RTStrmClose(pStrmOut);
4661 if (RT_FAILURE(rc))
4662 {
4663 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseBinaryR32[iFn].pszName, rc);
4664 return RTEXITCODE_FAILURE;
4665 }
4666 }
4667
4668 return RTEXITCODE_SUCCESS;
4669}
4670#endif
4671
4672static void SseBinaryR32Test(void)
4673{
4674 X86FXSTATE State;
4675 RT_ZERO(State);
4676 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryR32); iFn++)
4677 {
4678 if (!SubTestAndCheckIfEnabled(g_aSseBinaryR32[iFn].pszName))
4679 continue;
4680
4681 uint32_t const cTests = *g_aSseBinaryR32[iFn].pcTests;
4682 SSE_BINARY_TEST_T const * const paTests = g_aSseBinaryR32[iFn].paTests;
4683 PFNIEMAIMPLFPSSEF2U128 pfn = g_aSseBinaryR32[iFn].pfn;
4684 uint32_t const cVars = COUNT_VARIATIONS(g_aSseBinaryR32[iFn]);
4685 if (!cTests) RTTestSkipped(g_hTest, "no tests");
4686 for (uint32_t iVar = 0; iVar < cVars; iVar++)
4687 {
4688 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_BINARY_TEST_T); iTest++)
4689 {
4690 IEMSSERESULT Res; RT_ZERO(Res);
4691
4692 State.MXCSR = paTests[iTest].fMxcsrIn;
4693 pfn(&State, &Res, &paTests[iTest].InVal1, &paTests[iTest].InVal2);
4694 bool fValsIdentical = RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[0], &paTests[iTest].OutVal.ar32[0])
4695 && RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[1], &paTests[iTest].OutVal.ar32[1])
4696 && RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[2], &paTests[iTest].OutVal.ar32[2])
4697 && RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[3], &paTests[iTest].OutVal.ar32[3]);
4698 if ( Res.MXCSR != paTests[iTest].fMxcsrOut
4699 || !fValsIdentical)
4700 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%s'%s'%s'%s in2=%s'%s'%s'%s\n"
4701 "%s -> mxcsr=%#08x %s'%s'%s'%s\n"
4702 "%s expected %#08x %s'%s'%s'%s%s%s (%s)\n",
4703 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
4704 FormatR32(&paTests[iTest].InVal1.ar32[0]), FormatR32(&paTests[iTest].InVal1.ar32[1]),
4705 FormatR32(&paTests[iTest].InVal1.ar32[2]), FormatR32(&paTests[iTest].InVal1.ar32[3]),
4706 FormatR32(&paTests[iTest].InVal2.ar32[0]), FormatR32(&paTests[iTest].InVal2.ar32[1]),
4707 FormatR32(&paTests[iTest].InVal2.ar32[2]), FormatR32(&paTests[iTest].InVal2.ar32[3]),
4708 iVar ? " " : "", Res.MXCSR,
4709 FormatR32(&Res.uResult.ar32[0]), FormatR32(&Res.uResult.ar32[1]),
4710 FormatR32(&Res.uResult.ar32[2]), FormatR32(&Res.uResult.ar32[3]),
4711 iVar ? " " : "", paTests[iTest].fMxcsrOut,
4712 FormatR32(&paTests[iTest].OutVal.ar32[0]), FormatR32(&paTests[iTest].OutVal.ar32[1]),
4713 FormatR32(&paTests[iTest].OutVal.ar32[2]), FormatR32(&paTests[iTest].OutVal.ar32[3]),
4714 MxcsrDiff(Res.MXCSR, paTests[iTest].fMxcsrOut),
4715 !fValsIdentical ? " - val" : "",
4716 FormatMxcsr(paTests[iTest].fMxcsrIn) );
4717 }
4718 pfn = g_aSseBinaryR32[iFn].pfnNative;
4719 }
4720 }
4721}
4722
4723
4724/*
4725 * Binary SSE operations on packed single precision floating point values.
4726 */
4727TYPEDEF_SUBTEST_TYPE(SSE_BINARY_R64_T, SSE_BINARY_TEST_T, PFNIEMAIMPLFPSSEF2U128);
4728
4729static const SSE_BINARY_R64_T g_aSseBinaryR64[] =
4730{
4731 ENTRY_BIN(addpd_u128),
4732 ENTRY_BIN(mulpd_u128),
4733 ENTRY_BIN(subpd_u128),
4734 ENTRY_BIN(minpd_u128),
4735 ENTRY_BIN(divpd_u128),
4736 ENTRY_BIN(maxpd_u128),
4737 ENTRY_BIN(haddpd_u128),
4738 ENTRY_BIN(hsubpd_u128),
4739 ENTRY_BIN(sqrtpd_u128),
4740 ENTRY_BIN(addsubpd_u128),
4741 ENTRY_BIN(cvtpd2ps_u128),
4742};
4743
4744#ifdef TSTIEMAIMPL_WITH_GENERATOR
4745static RTEXITCODE SseBinaryR64Generate(const char *pszDataFileFmt, uint32_t cTests)
4746{
4747 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
4748
4749 static struct { RTFLOAT64U aVal1[2], aVal2[2]; } const s_aSpecials[] =
4750 {
4751 { { RTFLOAT64U_INIT_ZERO(0), RTFLOAT64U_INIT_ZERO(0) },
4752 { RTFLOAT64U_INIT_C(0, 8388607, RTFLOAT64U_EXP_MAX - 1), RTFLOAT64U_INIT_C(0, 8388607, RTFLOAT64U_EXP_MAX - 1) } },
4753 /** @todo More specials. */
4754 };
4755
4756 X86FXSTATE State;
4757 RT_ZERO(State);
4758 uint32_t cMinNormalPairs = (cTests - 144) / 4;
4759 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryR64); iFn++)
4760 {
4761 PFNIEMAIMPLFPSSEF2U128 const pfn = g_aSseBinaryR64[iFn].pfnNative ? g_aSseBinaryR64[iFn].pfnNative : g_aSseBinaryR64[iFn].pfn;
4762
4763 PRTSTREAM pStrmOut = NULL;
4764 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseBinaryR64[iFn].pszName);
4765 if (RT_FAILURE(rc))
4766 {
4767 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseBinaryR64[iFn].pszName, rc);
4768 return RTEXITCODE_FAILURE;
4769 }
4770
4771 uint32_t cNormalInputPairs = 0;
4772 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
4773 {
4774 SSE_BINARY_TEST_T TestData; RT_ZERO(TestData);
4775
4776 TestData.InVal1.ar64[0] = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].aVal1[0];
4777 TestData.InVal1.ar64[1] = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].aVal1[0];
4778 TestData.InVal2.ar64[0] = iTest < cTests ? RandR64Src2(iTest) : s_aSpecials[iTest - cTests].aVal2[0];
4779 TestData.InVal2.ar64[1] = iTest < cTests ? RandR64Src2(iTest) : s_aSpecials[iTest - cTests].aVal2[0];
4780
4781 if ( RTFLOAT64U_IS_NORMAL(&TestData.InVal1.ar64[0]) && RTFLOAT64U_IS_NORMAL(&TestData.InVal1.ar64[1])
4782 && RTFLOAT64U_IS_NORMAL(&TestData.InVal2.ar64[0]) && RTFLOAT64U_IS_NORMAL(&TestData.InVal2.ar64[1]))
4783 cNormalInputPairs++;
4784 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
4785 {
4786 iTest -= 1;
4787 continue;
4788 }
4789
4790 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
4791 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
4792 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
4793 for (uint8_t iFz = 0; iFz < 2; iFz++)
4794 {
4795 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
4796 | (iRounding << X86_MXCSR_RC_SHIFT)
4797 | (iDaz ? X86_MXCSR_DAZ : 0)
4798 | (iFz ? X86_MXCSR_FZ : 0)
4799 | X86_MXCSR_XCPT_MASK;
4800 IEMSSERESULT ResM; RT_ZERO(ResM);
4801 pfn(&State, &ResM, &TestData.InVal1, &TestData.InVal2);
4802 TestData.fMxcsrIn = State.MXCSR;
4803 TestData.fMxcsrOut = ResM.MXCSR;
4804 TestData.OutVal = ResM.uResult;
4805 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
4806
4807 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
4808 IEMSSERESULT ResU; RT_ZERO(ResU);
4809 pfn(&State, &ResU, &TestData.InVal1, &TestData.InVal2);
4810 TestData.fMxcsrIn = State.MXCSR;
4811 TestData.fMxcsrOut = ResU.MXCSR;
4812 TestData.OutVal = ResU.uResult;
4813 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
4814
4815 uint16_t fXcpt = (ResM.MXCSR | ResU.MXCSR) & X86_MXCSR_XCPT_FLAGS;
4816 if (fXcpt)
4817 {
4818 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
4819 IEMSSERESULT Res1; RT_ZERO(Res1);
4820 pfn(&State, &Res1, &TestData.InVal1, &TestData.InVal2);
4821 TestData.fMxcsrIn = State.MXCSR;
4822 TestData.fMxcsrOut = Res1.MXCSR;
4823 TestData.OutVal = Res1.uResult;
4824 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
4825
4826 if (((Res1.MXCSR & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (Res1.MXCSR & X86_MXCSR_XCPT_FLAGS))
4827 {
4828 fXcpt |= Res1.MXCSR & X86_MXCSR_XCPT_FLAGS;
4829 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
4830 IEMSSERESULT Res2; RT_ZERO(Res2);
4831 pfn(&State, &Res2, &TestData.InVal1, &TestData.InVal2);
4832 TestData.fMxcsrIn = State.MXCSR;
4833 TestData.fMxcsrOut = Res2.MXCSR;
4834 TestData.OutVal = Res2.uResult;
4835 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
4836 }
4837 if (!RT_IS_POWER_OF_TWO(fXcpt))
4838 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
4839 if (fUnmasked & fXcpt)
4840 {
4841 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
4842 IEMSSERESULT Res3; RT_ZERO(Res3);
4843 pfn(&State, &Res3, &TestData.InVal1, &TestData.InVal2);
4844 TestData.fMxcsrIn = State.MXCSR;
4845 TestData.fMxcsrOut = Res3.MXCSR;
4846 TestData.OutVal = Res3.uResult;
4847 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
4848 }
4849 }
4850 }
4851 }
4852 rc = RTStrmClose(pStrmOut);
4853 if (RT_FAILURE(rc))
4854 {
4855 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseBinaryR64[iFn].pszName, rc);
4856 return RTEXITCODE_FAILURE;
4857 }
4858 }
4859
4860 return RTEXITCODE_SUCCESS;
4861}
4862#endif
4863
4864
4865static void SseBinaryR64Test(void)
4866{
4867 X86FXSTATE State;
4868 RT_ZERO(State);
4869 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryR64); iFn++)
4870 {
4871 if (!SubTestAndCheckIfEnabled(g_aSseBinaryR64[iFn].pszName))
4872 continue;
4873
4874 uint32_t const cTests = *g_aSseBinaryR64[iFn].pcTests;
4875 SSE_BINARY_TEST_T const * const paTests = g_aSseBinaryR64[iFn].paTests;
4876 PFNIEMAIMPLFPSSEF2U128 pfn = g_aSseBinaryR64[iFn].pfn;
4877 uint32_t const cVars = COUNT_VARIATIONS(g_aSseBinaryR64[iFn]);
4878 if (!cTests) RTTestSkipped(g_hTest, "no tests");
4879 for (uint32_t iVar = 0; iVar < cVars; iVar++)
4880 {
4881 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_BINARY_TEST_T); iTest++)
4882 {
4883 IEMSSERESULT Res; RT_ZERO(Res);
4884
4885 State.MXCSR = paTests[iTest].fMxcsrIn;
4886 pfn(&State, &Res, &paTests[iTest].InVal1, &paTests[iTest].InVal2);
4887 if ( Res.MXCSR != paTests[iTest].fMxcsrOut
4888 || !RTFLOAT64U_ARE_IDENTICAL(&Res.uResult.ar64[0], &paTests[iTest].OutVal.ar64[0])
4889 || !RTFLOAT64U_ARE_IDENTICAL(&Res.uResult.ar64[1], &paTests[iTest].OutVal.ar64[1]))
4890 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%s'%s in2=%s'%s\n"
4891 "%s -> mxcsr=%#08x %s'%s\n"
4892 "%s expected %#08x %s'%s%s%s (%s)\n",
4893 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
4894 FormatR64(&paTests[iTest].InVal1.ar64[0]), FormatR64(&paTests[iTest].InVal1.ar64[1]),
4895 FormatR64(&paTests[iTest].InVal2.ar64[0]), FormatR64(&paTests[iTest].InVal2.ar64[1]),
4896 iVar ? " " : "", Res.MXCSR,
4897 FormatR64(&Res.uResult.ar64[0]), FormatR64(&Res.uResult.ar64[1]),
4898 iVar ? " " : "", paTests[iTest].fMxcsrOut,
4899 FormatR64(&paTests[iTest].OutVal.ar64[0]), FormatR64(&paTests[iTest].OutVal.ar64[1]),
4900 MxcsrDiff(Res.MXCSR, paTests[iTest].fMxcsrOut),
4901 ( !RTFLOAT64U_ARE_IDENTICAL(&Res.uResult.ar64[0], &paTests[iTest].OutVal.ar64[0])
4902 || !RTFLOAT64U_ARE_IDENTICAL(&Res.uResult.ar64[1], &paTests[iTest].OutVal.ar64[1]))
4903 ? " - val" : "",
4904 FormatMxcsr(paTests[iTest].fMxcsrIn) );
4905 }
4906 pfn = g_aSseBinaryR64[iFn].pfnNative;
4907 }
4908 }
4909}
4910
4911
4912/*
4913 * Binary SSE operations on packed single precision floating point values.
4914 */
4915TYPEDEF_SUBTEST_TYPE(SSE_BINARY_U128_R32_T, SSE_BINARY_U128_R32_TEST_T, PFNIEMAIMPLFPSSEF2U128R32);
4916
4917static const SSE_BINARY_U128_R32_T g_aSseBinaryU128R32[] =
4918{
4919 ENTRY_BIN(addss_u128_r32),
4920 ENTRY_BIN(mulss_u128_r32),
4921 ENTRY_BIN(subss_u128_r32),
4922 ENTRY_BIN(minss_u128_r32),
4923 ENTRY_BIN(divss_u128_r32),
4924 ENTRY_BIN(maxss_u128_r32),
4925 ENTRY_BIN(cvtss2sd_u128_r32),
4926 ENTRY_BIN(sqrtss_u128_r32),
4927};
4928
4929#ifdef TSTIEMAIMPL_WITH_GENERATOR
4930static RTEXITCODE SseBinaryU128R32Generate(const char *pszDataFileFmt, uint32_t cTests)
4931{
4932 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
4933
4934 static struct { RTFLOAT32U aVal1[4], Val2; } const s_aSpecials[] =
4935 {
4936 { { RTFLOAT32U_INIT_ZERO(0), RTFLOAT32U_INIT_ZERO(0), RTFLOAT32U_INIT_ZERO(0), RTFLOAT32U_INIT_ZERO(0), }, RTFLOAT32U_INIT_C(0, 8388607, RTFLOAT32U_EXP_MAX - 1) },
4937 /** @todo More specials. */
4938 };
4939
4940 X86FXSTATE State;
4941 RT_ZERO(State);
4942 uint32_t cMinNormalPairs = (cTests - 144) / 4;
4943 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryU128R32); iFn++)
4944 {
4945 PFNIEMAIMPLFPSSEF2U128R32 const pfn = g_aSseBinaryU128R32[iFn].pfnNative ? g_aSseBinaryU128R32[iFn].pfnNative : g_aSseBinaryU128R32[iFn].pfn;
4946
4947 PRTSTREAM pStrmOut = NULL;
4948 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseBinaryU128R32[iFn].pszName);
4949 if (RT_FAILURE(rc))
4950 {
4951 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseBinaryU128R32[iFn].pszName, rc);
4952 return RTEXITCODE_FAILURE;
4953 }
4954
4955 uint32_t cNormalInputPairs = 0;
4956 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
4957 {
4958 SSE_BINARY_U128_R32_TEST_T TestData; RT_ZERO(TestData);
4959
4960 TestData.InVal1.ar32[0] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].aVal1[0];
4961 TestData.InVal1.ar32[1] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].aVal1[1];
4962 TestData.InVal1.ar32[2] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].aVal1[2];
4963 TestData.InVal1.ar32[3] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].aVal1[3];
4964
4965 TestData.r32Val2 = iTest < cTests ? RandR32Src2(iTest) : s_aSpecials[iTest - cTests].Val2;
4966
4967 if ( RTFLOAT32U_IS_NORMAL(&TestData.InVal1.ar32[0])
4968 && RTFLOAT32U_IS_NORMAL(&TestData.InVal1.ar32[1])
4969 && RTFLOAT32U_IS_NORMAL(&TestData.InVal1.ar32[2])
4970 && RTFLOAT32U_IS_NORMAL(&TestData.InVal1.ar32[3])
4971 && RTFLOAT32U_IS_NORMAL(&TestData.r32Val2))
4972 cNormalInputPairs++;
4973 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
4974 {
4975 iTest -= 1;
4976 continue;
4977 }
4978
4979 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
4980 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
4981 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
4982 for (uint8_t iFz = 0; iFz < 2; iFz++)
4983 {
4984 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
4985 | (iRounding << X86_MXCSR_RC_SHIFT)
4986 | (iDaz ? X86_MXCSR_DAZ : 0)
4987 | (iFz ? X86_MXCSR_FZ : 0)
4988 | X86_MXCSR_XCPT_MASK;
4989 IEMSSERESULT ResM; RT_ZERO(ResM);
4990 pfn(&State, &ResM, &TestData.InVal1, &TestData.r32Val2);
4991 TestData.fMxcsrIn = State.MXCSR;
4992 TestData.fMxcsrOut = ResM.MXCSR;
4993 TestData.OutVal = ResM.uResult;
4994 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
4995
4996 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
4997 IEMSSERESULT ResU; RT_ZERO(ResU);
4998 pfn(&State, &ResU, &TestData.InVal1, &TestData.r32Val2);
4999 TestData.fMxcsrIn = State.MXCSR;
5000 TestData.fMxcsrOut = ResU.MXCSR;
5001 TestData.OutVal = ResU.uResult;
5002 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5003
5004 uint16_t fXcpt = (ResM.MXCSR | ResU.MXCSR) & X86_MXCSR_XCPT_FLAGS;
5005 if (fXcpt)
5006 {
5007 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
5008 IEMSSERESULT Res1; RT_ZERO(Res1);
5009 pfn(&State, &Res1, &TestData.InVal1, &TestData.r32Val2);
5010 TestData.fMxcsrIn = State.MXCSR;
5011 TestData.fMxcsrOut = Res1.MXCSR;
5012 TestData.OutVal = Res1.uResult;
5013 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5014
5015 if (((Res1.MXCSR & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (Res1.MXCSR & X86_MXCSR_XCPT_FLAGS))
5016 {
5017 fXcpt |= Res1.MXCSR & X86_MXCSR_XCPT_FLAGS;
5018 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
5019 IEMSSERESULT Res2; RT_ZERO(Res2);
5020 pfn(&State, &Res2, &TestData.InVal1, &TestData.r32Val2);
5021 TestData.fMxcsrIn = State.MXCSR;
5022 TestData.fMxcsrOut = Res2.MXCSR;
5023 TestData.OutVal = Res2.uResult;
5024 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5025 }
5026 if (!RT_IS_POWER_OF_TWO(fXcpt))
5027 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
5028 if (fUnmasked & fXcpt)
5029 {
5030 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
5031 IEMSSERESULT Res3; RT_ZERO(Res3);
5032 pfn(&State, &Res3, &TestData.InVal1, &TestData.r32Val2);
5033 TestData.fMxcsrIn = State.MXCSR;
5034 TestData.fMxcsrOut = Res3.MXCSR;
5035 TestData.OutVal = Res3.uResult;
5036 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5037 }
5038 }
5039 }
5040 }
5041 rc = RTStrmClose(pStrmOut);
5042 if (RT_FAILURE(rc))
5043 {
5044 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseBinaryU128R32[iFn].pszName, rc);
5045 return RTEXITCODE_FAILURE;
5046 }
5047 }
5048
5049 return RTEXITCODE_SUCCESS;
5050}
5051#endif
5052
5053static void SseBinaryU128R32Test(void)
5054{
5055 X86FXSTATE State;
5056 RT_ZERO(State);
5057 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryU128R32); iFn++)
5058 {
5059 if (!SubTestAndCheckIfEnabled(g_aSseBinaryU128R32[iFn].pszName))
5060 continue;
5061
5062 uint32_t const cTests = *g_aSseBinaryU128R32[iFn].pcTests;
5063 SSE_BINARY_U128_R32_TEST_T const * const paTests = g_aSseBinaryU128R32[iFn].paTests;
5064 PFNIEMAIMPLFPSSEF2U128R32 pfn = g_aSseBinaryU128R32[iFn].pfn;
5065 uint32_t const cVars = COUNT_VARIATIONS(g_aSseBinaryU128R32[iFn]);
5066 if (!cTests) RTTestSkipped(g_hTest, "no tests");
5067 for (uint32_t iVar = 0; iVar < cVars; iVar++)
5068 {
5069 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_BINARY_TEST_T); iTest++)
5070 {
5071 IEMSSERESULT Res; RT_ZERO(Res);
5072
5073 State.MXCSR = paTests[iTest].fMxcsrIn;
5074 pfn(&State, &Res, &paTests[iTest].InVal1, &paTests[iTest].r32Val2);
5075 bool fValsIdentical = RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[0], &paTests[iTest].OutVal.ar32[0])
5076 && RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[1], &paTests[iTest].OutVal.ar32[1])
5077 && RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[2], &paTests[iTest].OutVal.ar32[2])
5078 && RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[3], &paTests[iTest].OutVal.ar32[3]);
5079 if ( Res.MXCSR != paTests[iTest].fMxcsrOut
5080 || !fValsIdentical)
5081 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%s'%s'%s'%s in2=%s\n"
5082 "%s -> mxcsr=%#08x %s'%s'%s'%s\n"
5083 "%s expected %#08x %s'%s'%s'%s%s%s (%s)\n",
5084 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
5085 FormatR32(&paTests[iTest].InVal1.ar32[0]), FormatR32(&paTests[iTest].InVal1.ar32[1]),
5086 FormatR32(&paTests[iTest].InVal1.ar32[2]), FormatR32(&paTests[iTest].InVal1.ar32[3]),
5087 FormatR32(&paTests[iTest].r32Val2),
5088 iVar ? " " : "", Res.MXCSR,
5089 FormatR32(&Res.uResult.ar32[0]), FormatR32(&Res.uResult.ar32[1]),
5090 FormatR32(&Res.uResult.ar32[2]), FormatR32(&Res.uResult.ar32[3]),
5091 iVar ? " " : "", paTests[iTest].fMxcsrOut,
5092 FormatR32(&paTests[iTest].OutVal.ar32[0]), FormatR32(&paTests[iTest].OutVal.ar32[1]),
5093 FormatR32(&paTests[iTest].OutVal.ar32[2]), FormatR32(&paTests[iTest].OutVal.ar32[3]),
5094 MxcsrDiff(Res.MXCSR, paTests[iTest].fMxcsrOut),
5095 !fValsIdentical ? " - val" : "",
5096 FormatMxcsr(paTests[iTest].fMxcsrIn) );
5097 }
5098 }
5099 }
5100}
5101
5102
5103/*
5104 * Binary SSE operations on packed single precision floating point values (xxxsd xmm1, r/m64).
5105 */
5106TYPEDEF_SUBTEST_TYPE(SSE_BINARY_U128_R64_T, SSE_BINARY_U128_R64_TEST_T, PFNIEMAIMPLFPSSEF2U128R64);
5107
5108static const SSE_BINARY_U128_R64_T g_aSseBinaryU128R64[] =
5109{
5110 ENTRY_BIN(addsd_u128_r64),
5111 ENTRY_BIN(mulsd_u128_r64),
5112 ENTRY_BIN(subsd_u128_r64),
5113 ENTRY_BIN(minsd_u128_r64),
5114 ENTRY_BIN(divsd_u128_r64),
5115 ENTRY_BIN(maxsd_u128_r64),
5116 ENTRY_BIN(cvtsd2ss_u128_r64),
5117 ENTRY_BIN(sqrtsd_u128_r64),
5118};
5119
5120#ifdef TSTIEMAIMPL_WITH_GENERATOR
5121static RTEXITCODE SseBinaryU128R64Generate(const char *pszDataFileFmt, uint32_t cTests)
5122{
5123 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
5124
5125 static struct { RTFLOAT64U aVal1[2], Val2; } const s_aSpecials[] =
5126 {
5127 { { RTFLOAT64U_INIT_ZERO(0), RTFLOAT64U_INIT_ZERO(0) }, RTFLOAT64U_INIT_C(0, 8388607, RTFLOAT64U_EXP_MAX - 1) },
5128 /** @todo More specials. */
5129 };
5130
5131 X86FXSTATE State;
5132 RT_ZERO(State);
5133 uint32_t cMinNormalPairs = (cTests - 144) / 4;
5134 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryU128R64); iFn++)
5135 {
5136 PFNIEMAIMPLFPSSEF2U128R64 const pfn = g_aSseBinaryU128R64[iFn].pfnNative ? g_aSseBinaryU128R64[iFn].pfnNative : g_aSseBinaryU128R64[iFn].pfn;
5137
5138 PRTSTREAM pStrmOut = NULL;
5139 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseBinaryU128R64[iFn].pszName);
5140 if (RT_FAILURE(rc))
5141 {
5142 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseBinaryU128R64[iFn].pszName, rc);
5143 return RTEXITCODE_FAILURE;
5144 }
5145
5146 uint32_t cNormalInputPairs = 0;
5147 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
5148 {
5149 SSE_BINARY_U128_R64_TEST_T TestData; RT_ZERO(TestData);
5150
5151 TestData.InVal1.ar64[0] = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].aVal1[0];
5152 TestData.InVal1.ar64[1] = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].aVal1[1];
5153 TestData.r64Val2 = iTest < cTests ? RandR64Src2(iTest) : s_aSpecials[iTest - cTests].Val2;
5154
5155 if ( RTFLOAT64U_IS_NORMAL(&TestData.InVal1.ar64[0]) && RTFLOAT64U_IS_NORMAL(&TestData.InVal1.ar64[1])
5156 && RTFLOAT64U_IS_NORMAL(&TestData.r64Val2))
5157 cNormalInputPairs++;
5158 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
5159 {
5160 iTest -= 1;
5161 continue;
5162 }
5163
5164 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
5165 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
5166 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
5167 for (uint8_t iFz = 0; iFz < 2; iFz++)
5168 {
5169 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
5170 | (iRounding << X86_MXCSR_RC_SHIFT)
5171 | (iDaz ? X86_MXCSR_DAZ : 0)
5172 | (iFz ? X86_MXCSR_FZ : 0)
5173 | X86_MXCSR_XCPT_MASK;
5174 IEMSSERESULT ResM; RT_ZERO(ResM);
5175 pfn(&State, &ResM, &TestData.InVal1, &TestData.r64Val2);
5176 TestData.fMxcsrIn = State.MXCSR;
5177 TestData.fMxcsrOut = ResM.MXCSR;
5178 TestData.OutVal = ResM.uResult;
5179 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5180
5181 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
5182 IEMSSERESULT ResU; RT_ZERO(ResU);
5183 pfn(&State, &ResU, &TestData.InVal1, &TestData.r64Val2);
5184 TestData.fMxcsrIn = State.MXCSR;
5185 TestData.fMxcsrOut = ResU.MXCSR;
5186 TestData.OutVal = ResU.uResult;
5187 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5188
5189 uint16_t fXcpt = (ResM.MXCSR | ResU.MXCSR) & X86_MXCSR_XCPT_FLAGS;
5190 if (fXcpt)
5191 {
5192 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
5193 IEMSSERESULT Res1; RT_ZERO(Res1);
5194 pfn(&State, &Res1, &TestData.InVal1, &TestData.r64Val2);
5195 TestData.fMxcsrIn = State.MXCSR;
5196 TestData.fMxcsrOut = Res1.MXCSR;
5197 TestData.OutVal = Res1.uResult;
5198 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5199
5200 if (((Res1.MXCSR & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (Res1.MXCSR & X86_MXCSR_XCPT_FLAGS))
5201 {
5202 fXcpt |= Res1.MXCSR & X86_MXCSR_XCPT_FLAGS;
5203 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
5204 IEMSSERESULT Res2; RT_ZERO(Res2);
5205 pfn(&State, &Res2, &TestData.InVal1, &TestData.r64Val2);
5206 TestData.fMxcsrIn = State.MXCSR;
5207 TestData.fMxcsrOut = Res2.MXCSR;
5208 TestData.OutVal = Res2.uResult;
5209 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5210 }
5211 if (!RT_IS_POWER_OF_TWO(fXcpt))
5212 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
5213 if (fUnmasked & fXcpt)
5214 {
5215 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
5216 IEMSSERESULT Res3; RT_ZERO(Res3);
5217 pfn(&State, &Res3, &TestData.InVal1, &TestData.r64Val2);
5218 TestData.fMxcsrIn = State.MXCSR;
5219 TestData.fMxcsrOut = Res3.MXCSR;
5220 TestData.OutVal = Res3.uResult;
5221 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5222 }
5223 }
5224 }
5225 }
5226 rc = RTStrmClose(pStrmOut);
5227 if (RT_FAILURE(rc))
5228 {
5229 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseBinaryU128R64[iFn].pszName, rc);
5230 return RTEXITCODE_FAILURE;
5231 }
5232 }
5233
5234 return RTEXITCODE_SUCCESS;
5235}
5236#endif
5237
5238
5239static void SseBinaryU128R64Test(void)
5240{
5241 X86FXSTATE State;
5242 RT_ZERO(State);
5243 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryU128R64); iFn++)
5244 {
5245 if (!SubTestAndCheckIfEnabled(g_aSseBinaryU128R64[iFn].pszName))
5246 continue;
5247
5248 uint32_t const cTests = *g_aSseBinaryU128R64[iFn].pcTests;
5249 SSE_BINARY_U128_R64_TEST_T const * const paTests = g_aSseBinaryU128R64[iFn].paTests;
5250 PFNIEMAIMPLFPSSEF2U128R64 pfn = g_aSseBinaryU128R64[iFn].pfn;
5251 uint32_t const cVars = COUNT_VARIATIONS(g_aSseBinaryU128R64[iFn]);
5252 if (!cTests) RTTestSkipped(g_hTest, "no tests");
5253 for (uint32_t iVar = 0; iVar < cVars; iVar++)
5254 {
5255 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_BINARY_U128_R64_TEST_T); iTest++)
5256 {
5257 IEMSSERESULT Res; RT_ZERO(Res);
5258
5259 State.MXCSR = paTests[iTest].fMxcsrIn;
5260 pfn(&State, &Res, &paTests[iTest].InVal1, &paTests[iTest].r64Val2);
5261 if ( Res.MXCSR != paTests[iTest].fMxcsrOut
5262 || !RTFLOAT64U_ARE_IDENTICAL(&Res.uResult.ar64[0], &paTests[iTest].OutVal.ar64[0])
5263 || !RTFLOAT64U_ARE_IDENTICAL(&Res.uResult.ar64[1], &paTests[iTest].OutVal.ar64[1]))
5264 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%s'%s in2=%s\n"
5265 "%s -> mxcsr=%#08x %s'%s\n"
5266 "%s expected %#08x %s'%s%s%s (%s)\n",
5267 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
5268 FormatR64(&paTests[iTest].InVal1.ar64[0]), FormatR64(&paTests[iTest].InVal1.ar64[1]),
5269 FormatR64(&paTests[iTest].r64Val2),
5270 iVar ? " " : "", Res.MXCSR,
5271 FormatR64(&Res.uResult.ar64[0]), FormatR64(&Res.uResult.ar64[1]),
5272 iVar ? " " : "", paTests[iTest].fMxcsrOut,
5273 FormatR64(&paTests[iTest].OutVal.ar64[0]), FormatR64(&paTests[iTest].OutVal.ar64[1]),
5274 MxcsrDiff(Res.MXCSR, paTests[iTest].fMxcsrOut),
5275 ( !RTFLOAT64U_ARE_IDENTICAL(&Res.uResult.ar64[0], &paTests[iTest].OutVal.ar64[0])
5276 || !RTFLOAT64U_ARE_IDENTICAL(&Res.uResult.ar64[1], &paTests[iTest].OutVal.ar64[1]))
5277 ? " - val" : "",
5278 FormatMxcsr(paTests[iTest].fMxcsrIn) );
5279 }
5280 }
5281 }
5282}
5283
5284
5285/*
5286 * SSE operations converting single double-precision floating point values to signed double-word integers (cvttsd2si and friends).
5287 */
5288TYPEDEF_SUBTEST_TYPE(SSE_BINARY_I32_R64_T, SSE_BINARY_I32_R64_TEST_T, PFNIEMAIMPLSSEF2I32U64);
5289
5290static const SSE_BINARY_I32_R64_T g_aSseBinaryI32R64[] =
5291{
5292 ENTRY_BIN(cvttsd2si_i32_r64),
5293 ENTRY_BIN(cvtsd2si_i32_r64),
5294};
5295
5296#ifdef TSTIEMAIMPL_WITH_GENERATOR
5297static RTEXITCODE SseBinaryI32R64Generate(const char *pszDataFileFmt, uint32_t cTests)
5298{
5299 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
5300
5301 static struct { RTFLOAT64U Val; } const s_aSpecials[] =
5302 {
5303 { RTFLOAT64U_INIT_C(0, 8388607, RTFLOAT64U_EXP_MAX - 1) },
5304 /** @todo More specials. */
5305 };
5306
5307 X86FXSTATE State;
5308 RT_ZERO(State);
5309 uint32_t cMinNormalPairs = (cTests - 144) / 4;
5310 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryI32R64); iFn++)
5311 {
5312 PFNIEMAIMPLSSEF2I32U64 const pfn = g_aSseBinaryI32R64[iFn].pfnNative ? g_aSseBinaryI32R64[iFn].pfnNative : g_aSseBinaryI32R64[iFn].pfn;
5313
5314 PRTSTREAM pStrmOut = NULL;
5315 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseBinaryI32R64[iFn].pszName);
5316 if (RT_FAILURE(rc))
5317 {
5318 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseBinaryI32R64[iFn].pszName, rc);
5319 return RTEXITCODE_FAILURE;
5320 }
5321
5322 uint32_t cNormalInputPairs = 0;
5323 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
5324 {
5325 SSE_BINARY_I32_R64_TEST_T TestData; RT_ZERO(TestData);
5326
5327 TestData.r64ValIn = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].Val;
5328
5329 if (RTFLOAT64U_IS_NORMAL(&TestData.r64ValIn))
5330 cNormalInputPairs++;
5331 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
5332 {
5333 iTest -= 1;
5334 continue;
5335 }
5336
5337 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
5338 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
5339 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
5340 for (uint8_t iFz = 0; iFz < 2; iFz++)
5341 {
5342 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
5343 | (iRounding << X86_MXCSR_RC_SHIFT)
5344 | (iDaz ? X86_MXCSR_DAZ : 0)
5345 | (iFz ? X86_MXCSR_FZ : 0)
5346 | X86_MXCSR_XCPT_MASK;
5347 uint32_t fMxcsrM; int32_t i32OutM;
5348 pfn(&State, &fMxcsrM, &i32OutM, &TestData.r64ValIn.u);
5349 TestData.fMxcsrIn = State.MXCSR;
5350 TestData.fMxcsrOut = fMxcsrM;
5351 TestData.i32ValOut = i32OutM;
5352 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5353
5354 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
5355 uint32_t fMxcsrU; int32_t i32OutU;
5356 pfn(&State, &fMxcsrU, &i32OutU, &TestData.r64ValIn.u);
5357 TestData.fMxcsrIn = State.MXCSR;
5358 TestData.fMxcsrOut = fMxcsrU;
5359 TestData.i32ValOut = i32OutU;
5360 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5361
5362 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
5363 if (fXcpt)
5364 {
5365 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
5366 uint32_t fMxcsr1; int32_t i32Out1;
5367 pfn(&State, &fMxcsr1, &i32Out1, &TestData.r64ValIn.u);
5368 TestData.fMxcsrIn = State.MXCSR;
5369 TestData.fMxcsrOut = fMxcsr1;
5370 TestData.i32ValOut = i32Out1;
5371 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5372
5373 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
5374 {
5375 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
5376 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
5377 uint32_t fMxcsr2; int32_t i32Out2;
5378 pfn(&State, &fMxcsr2, &i32Out2, &TestData.r64ValIn.u);
5379 TestData.fMxcsrIn = State.MXCSR;
5380 TestData.fMxcsrOut = fMxcsr2;
5381 TestData.i32ValOut = i32Out2;
5382 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5383 }
5384 if (!RT_IS_POWER_OF_TWO(fXcpt))
5385 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
5386 if (fUnmasked & fXcpt)
5387 {
5388 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
5389 uint32_t fMxcsr3; int32_t i32Out3;
5390 pfn(&State, &fMxcsr3, &i32Out3, &TestData.r64ValIn.u);
5391 TestData.fMxcsrIn = State.MXCSR;
5392 TestData.fMxcsrOut = fMxcsr3;
5393 TestData.i32ValOut = i32Out3;
5394 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5395 }
5396 }
5397 }
5398 }
5399 rc = RTStrmClose(pStrmOut);
5400 if (RT_FAILURE(rc))
5401 {
5402 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseBinaryI32R64[iFn].pszName, rc);
5403 return RTEXITCODE_FAILURE;
5404 }
5405 }
5406
5407 return RTEXITCODE_SUCCESS;
5408}
5409#endif
5410
5411
5412static void SseBinaryI32R64Test(void)
5413{
5414 X86FXSTATE State;
5415 RT_ZERO(State);
5416 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryI32R64); iFn++)
5417 {
5418 if (!SubTestAndCheckIfEnabled(g_aSseBinaryI32R64[iFn].pszName))
5419 continue;
5420
5421 uint32_t const cTests = *g_aSseBinaryI32R64[iFn].pcTests;
5422 SSE_BINARY_I32_R64_TEST_T const * const paTests = g_aSseBinaryI32R64[iFn].paTests;
5423 PFNIEMAIMPLSSEF2I32U64 pfn = g_aSseBinaryI32R64[iFn].pfn;
5424 uint32_t const cVars = COUNT_VARIATIONS(g_aSseBinaryI32R64[iFn]);
5425 if (!cTests) RTTestSkipped(g_hTest, "no tests");
5426 for (uint32_t iVar = 0; iVar < cVars; iVar++)
5427 {
5428 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_BINARY_I32_R64_TEST_T); iTest++)
5429 {
5430 uint32_t fMxcsr = 0;
5431 int32_t i32Dst = 0;
5432
5433 State.MXCSR = paTests[iTest].fMxcsrIn;
5434 pfn(&State, &fMxcsr, &i32Dst, &paTests[iTest].r64ValIn.u);
5435 if ( fMxcsr != paTests[iTest].fMxcsrOut
5436 || i32Dst != paTests[iTest].i32ValOut)
5437 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%s\n"
5438 "%s -> mxcsr=%#08x %RI32\n"
5439 "%s expected %#08x %RI32%s%s (%s)\n",
5440 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
5441 FormatR64(&paTests[iTest].r64ValIn),
5442 iVar ? " " : "", fMxcsr, i32Dst,
5443 iVar ? " " : "", paTests[iTest].fMxcsrOut, paTests[iTest].i32ValOut,
5444 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
5445 i32Dst != paTests[iTest].i32ValOut
5446 ? " - val" : "",
5447 FormatMxcsr(paTests[iTest].fMxcsrIn) );
5448 }
5449 }
5450 }
5451}
5452
5453
5454/*
5455 * SSE operations converting single double-precision floating point values to signed quad-word integers (cvttsd2si and friends).
5456 */
5457TYPEDEF_SUBTEST_TYPE(SSE_BINARY_I64_R64_T, SSE_BINARY_I64_R64_TEST_T, PFNIEMAIMPLSSEF2I64U64);
5458
5459static const SSE_BINARY_I64_R64_T g_aSseBinaryI64R64[] =
5460{
5461 ENTRY_BIN(cvttsd2si_i64_r64),
5462 ENTRY_BIN(cvtsd2si_i64_r64),
5463};
5464
5465#ifdef TSTIEMAIMPL_WITH_GENERATOR
5466static RTEXITCODE SseBinaryI64R64Generate(const char *pszDataFileFmt, uint32_t cTests)
5467{
5468 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
5469
5470 static struct { RTFLOAT64U Val; } const s_aSpecials[] =
5471 {
5472 { RTFLOAT64U_INIT_C(0, 8388607, RTFLOAT64U_EXP_MAX - 1) },
5473 /** @todo More specials. */
5474 };
5475
5476 X86FXSTATE State;
5477 RT_ZERO(State);
5478 uint32_t cMinNormalPairs = (cTests - 144) / 4;
5479 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryI64R64); iFn++)
5480 {
5481 PFNIEMAIMPLSSEF2I64U64 const pfn = g_aSseBinaryI64R64[iFn].pfnNative ? g_aSseBinaryI64R64[iFn].pfnNative : g_aSseBinaryI64R64[iFn].pfn;
5482
5483 PRTSTREAM pStrmOut = NULL;
5484 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseBinaryI64R64[iFn].pszName);
5485 if (RT_FAILURE(rc))
5486 {
5487 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseBinaryI64R64[iFn].pszName, rc);
5488 return RTEXITCODE_FAILURE;
5489 }
5490
5491 uint32_t cNormalInputPairs = 0;
5492 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
5493 {
5494 SSE_BINARY_I64_R64_TEST_T TestData; RT_ZERO(TestData);
5495
5496 TestData.r64ValIn = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].Val;
5497
5498 if (RTFLOAT64U_IS_NORMAL(&TestData.r64ValIn))
5499 cNormalInputPairs++;
5500 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
5501 {
5502 iTest -= 1;
5503 continue;
5504 }
5505
5506 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
5507 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
5508 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
5509 for (uint8_t iFz = 0; iFz < 2; iFz++)
5510 {
5511 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
5512 | (iRounding << X86_MXCSR_RC_SHIFT)
5513 | (iDaz ? X86_MXCSR_DAZ : 0)
5514 | (iFz ? X86_MXCSR_FZ : 0)
5515 | X86_MXCSR_XCPT_MASK;
5516 uint32_t fMxcsrM; int64_t i64OutM;
5517 pfn(&State, &fMxcsrM, &i64OutM, &TestData.r64ValIn.u);
5518 TestData.fMxcsrIn = State.MXCSR;
5519 TestData.fMxcsrOut = fMxcsrM;
5520 TestData.i64ValOut = i64OutM;
5521 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5522
5523 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
5524 uint32_t fMxcsrU; int64_t i64OutU;
5525 pfn(&State, &fMxcsrU, &i64OutU, &TestData.r64ValIn.u);
5526 TestData.fMxcsrIn = State.MXCSR;
5527 TestData.fMxcsrOut = fMxcsrU;
5528 TestData.i64ValOut = i64OutU;
5529 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5530
5531 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
5532 if (fXcpt)
5533 {
5534 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
5535 uint32_t fMxcsr1; int64_t i64Out1;
5536 pfn(&State, &fMxcsr1, &i64Out1, &TestData.r64ValIn.u);
5537 TestData.fMxcsrIn = State.MXCSR;
5538 TestData.fMxcsrOut = fMxcsr1;
5539 TestData.i64ValOut = i64Out1;
5540 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5541
5542 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
5543 {
5544 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
5545 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
5546 uint32_t fMxcsr2; int64_t i64Out2;
5547 pfn(&State, &fMxcsr2, &i64Out2, &TestData.r64ValIn.u);
5548 TestData.fMxcsrIn = State.MXCSR;
5549 TestData.fMxcsrOut = fMxcsr2;
5550 TestData.i64ValOut = i64Out2;
5551 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5552 }
5553 if (!RT_IS_POWER_OF_TWO(fXcpt))
5554 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
5555 if (fUnmasked & fXcpt)
5556 {
5557 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
5558 uint32_t fMxcsr3; int64_t i64Out3;
5559 pfn(&State, &fMxcsr3, &i64Out3, &TestData.r64ValIn.u);
5560 TestData.fMxcsrIn = State.MXCSR;
5561 TestData.fMxcsrOut = fMxcsr3;
5562 TestData.i64ValOut = i64Out3;
5563 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5564 }
5565 }
5566 }
5567 }
5568 rc = RTStrmClose(pStrmOut);
5569 if (RT_FAILURE(rc))
5570 {
5571 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseBinaryI64R64[iFn].pszName, rc);
5572 return RTEXITCODE_FAILURE;
5573 }
5574 }
5575
5576 return RTEXITCODE_SUCCESS;
5577}
5578#endif
5579
5580
5581static void SseBinaryI64R64Test(void)
5582{
5583 X86FXSTATE State;
5584 RT_ZERO(State);
5585 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryI64R64); iFn++)
5586 {
5587 if (!SubTestAndCheckIfEnabled(g_aSseBinaryI64R64[iFn].pszName))
5588 continue;
5589
5590 uint32_t const cTests = *g_aSseBinaryI64R64[iFn].pcTests;
5591 SSE_BINARY_I64_R64_TEST_T const * const paTests = g_aSseBinaryI64R64[iFn].paTests;
5592 PFNIEMAIMPLSSEF2I64U64 pfn = g_aSseBinaryI64R64[iFn].pfn;
5593 uint32_t const cVars = COUNT_VARIATIONS(g_aSseBinaryI32R64[iFn]);
5594 if (!cTests) RTTestSkipped(g_hTest, "no tests");
5595 for (uint32_t iVar = 0; iVar < cVars; iVar++)
5596 {
5597 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_BINARY_I64_R64_TEST_T); iTest++)
5598 {
5599 uint32_t fMxcsr = 0;
5600 int64_t i64Dst = 0;
5601
5602 State.MXCSR = paTests[iTest].fMxcsrIn;
5603 pfn(&State, &fMxcsr, &i64Dst, &paTests[iTest].r64ValIn.u);
5604 if ( fMxcsr != paTests[iTest].fMxcsrOut
5605 || i64Dst != paTests[iTest].i64ValOut)
5606 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%s\n"
5607 "%s -> mxcsr=%#08x %RI64\n"
5608 "%s expected %#08x %RI64%s%s (%s)\n",
5609 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
5610 FormatR64(&paTests[iTest].r64ValIn),
5611 iVar ? " " : "", fMxcsr, i64Dst,
5612 iVar ? " " : "", paTests[iTest].fMxcsrOut, paTests[iTest].i64ValOut,
5613 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
5614 i64Dst != paTests[iTest].i64ValOut
5615 ? " - val" : "",
5616 FormatMxcsr(paTests[iTest].fMxcsrIn) );
5617 }
5618 }
5619 }
5620}
5621
5622
5623/*
5624 * SSE operations converting single single-precision floating point values to signed double-word integers (cvttss2si and friends).
5625 */
5626TYPEDEF_SUBTEST_TYPE(SSE_BINARY_I32_R32_T, SSE_BINARY_I32_R32_TEST_T, PFNIEMAIMPLSSEF2I32U32);
5627
5628static const SSE_BINARY_I32_R32_T g_aSseBinaryI32R32[] =
5629{
5630 ENTRY_BIN(cvttss2si_i32_r32),
5631 ENTRY_BIN(cvtss2si_i32_r32),
5632};
5633
5634#ifdef TSTIEMAIMPL_WITH_GENERATOR
5635static RTEXITCODE SseBinaryI32R32Generate(const char *pszDataFileFmt, uint32_t cTests)
5636{
5637 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
5638
5639 static struct { RTFLOAT32U Val; } const s_aSpecials[] =
5640 {
5641 { RTFLOAT32U_INIT_C(0, 8388607, RTFLOAT32U_EXP_MAX - 1) },
5642 /** @todo More specials. */
5643 };
5644
5645 X86FXSTATE State;
5646 RT_ZERO(State);
5647 uint32_t cMinNormalPairs = (cTests - 144) / 4;
5648 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryI32R32); iFn++)
5649 {
5650 PFNIEMAIMPLSSEF2I32U32 const pfn = g_aSseBinaryI32R32[iFn].pfnNative ? g_aSseBinaryI32R32[iFn].pfnNative : g_aSseBinaryI32R32[iFn].pfn;
5651
5652 PRTSTREAM pStrmOut = NULL;
5653 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseBinaryI32R32[iFn].pszName);
5654 if (RT_FAILURE(rc))
5655 {
5656 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseBinaryI32R32[iFn].pszName, rc);
5657 return RTEXITCODE_FAILURE;
5658 }
5659
5660 uint32_t cNormalInputPairs = 0;
5661 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
5662 {
5663 SSE_BINARY_I32_R32_TEST_T TestData; RT_ZERO(TestData);
5664
5665 TestData.r32ValIn = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].Val;
5666
5667 if (RTFLOAT32U_IS_NORMAL(&TestData.r32ValIn))
5668 cNormalInputPairs++;
5669 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
5670 {
5671 iTest -= 1;
5672 continue;
5673 }
5674
5675 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
5676 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
5677 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
5678 for (uint8_t iFz = 0; iFz < 2; iFz++)
5679 {
5680 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
5681 | (iRounding << X86_MXCSR_RC_SHIFT)
5682 | (iDaz ? X86_MXCSR_DAZ : 0)
5683 | (iFz ? X86_MXCSR_FZ : 0)
5684 | X86_MXCSR_XCPT_MASK;
5685 uint32_t fMxcsrM; int32_t i32OutM;
5686 pfn(&State, &fMxcsrM, &i32OutM, &TestData.r32ValIn.u);
5687 TestData.fMxcsrIn = State.MXCSR;
5688 TestData.fMxcsrOut = fMxcsrM;
5689 TestData.i32ValOut = i32OutM;
5690 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5691
5692 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
5693 uint32_t fMxcsrU; int32_t i32OutU;
5694 pfn(&State, &fMxcsrU, &i32OutU, &TestData.r32ValIn.u);
5695 TestData.fMxcsrIn = State.MXCSR;
5696 TestData.fMxcsrOut = fMxcsrU;
5697 TestData.i32ValOut = i32OutU;
5698 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5699
5700 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
5701 if (fXcpt)
5702 {
5703 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
5704 uint32_t fMxcsr1; int32_t i32Out1;
5705 pfn(&State, &fMxcsr1, &i32Out1, &TestData.r32ValIn.u);
5706 TestData.fMxcsrIn = State.MXCSR;
5707 TestData.fMxcsrOut = fMxcsr1;
5708 TestData.i32ValOut = i32Out1;
5709 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5710
5711 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
5712 {
5713 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
5714 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
5715 uint32_t fMxcsr2; int32_t i32Out2;
5716 pfn(&State, &fMxcsr2, &i32Out2, &TestData.r32ValIn.u);
5717 TestData.fMxcsrIn = State.MXCSR;
5718 TestData.fMxcsrOut = fMxcsr2;
5719 TestData.i32ValOut = i32Out2;
5720 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5721 }
5722 if (!RT_IS_POWER_OF_TWO(fXcpt))
5723 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
5724 if (fUnmasked & fXcpt)
5725 {
5726 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
5727 uint32_t fMxcsr3; int32_t i32Out3;
5728 pfn(&State, &fMxcsr3, &i32Out3, &TestData.r32ValIn.u);
5729 TestData.fMxcsrIn = State.MXCSR;
5730 TestData.fMxcsrOut = fMxcsr3;
5731 TestData.i32ValOut = i32Out3;
5732 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5733 }
5734 }
5735 }
5736 }
5737 rc = RTStrmClose(pStrmOut);
5738 if (RT_FAILURE(rc))
5739 {
5740 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseBinaryI32R32[iFn].pszName, rc);
5741 return RTEXITCODE_FAILURE;
5742 }
5743 }
5744
5745 return RTEXITCODE_SUCCESS;
5746}
5747#endif
5748
5749
5750static void SseBinaryI32R32Test(void)
5751{
5752 X86FXSTATE State;
5753 RT_ZERO(State);
5754 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryI32R32); iFn++)
5755 {
5756 if (!SubTestAndCheckIfEnabled(g_aSseBinaryI32R32[iFn].pszName))
5757 continue;
5758
5759 uint32_t const cTests = *g_aSseBinaryI32R32[iFn].pcTests;
5760 SSE_BINARY_I32_R32_TEST_T const * const paTests = g_aSseBinaryI32R32[iFn].paTests;
5761 PFNIEMAIMPLSSEF2I32U32 pfn = g_aSseBinaryI32R32[iFn].pfn;
5762 uint32_t const cVars = COUNT_VARIATIONS(g_aSseBinaryI32R32[iFn]);
5763 if (!cTests) RTTestSkipped(g_hTest, "no tests");
5764 for (uint32_t iVar = 0; iVar < cVars; iVar++)
5765 {
5766 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_BINARY_I32_R32_TEST_T); iTest++)
5767 {
5768 uint32_t fMxcsr = 0;
5769 int32_t i32Dst = 0;
5770
5771 State.MXCSR = paTests[iTest].fMxcsrIn;
5772 pfn(&State, &fMxcsr, &i32Dst, &paTests[iTest].r32ValIn.u);
5773 if ( fMxcsr != paTests[iTest].fMxcsrOut
5774 || i32Dst != paTests[iTest].i32ValOut)
5775 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%s\n"
5776 "%s -> mxcsr=%#08x %RI32\n"
5777 "%s expected %#08x %RI32%s%s (%s)\n",
5778 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
5779 FormatR32(&paTests[iTest].r32ValIn),
5780 iVar ? " " : "", fMxcsr, i32Dst,
5781 iVar ? " " : "", paTests[iTest].fMxcsrOut, paTests[iTest].i32ValOut,
5782 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
5783 i32Dst != paTests[iTest].i32ValOut
5784 ? " - val" : "",
5785 FormatMxcsr(paTests[iTest].fMxcsrIn) );
5786 }
5787 }
5788 }
5789}
5790
5791
5792/*
5793 * SSE operations converting single single-precision floating point values to signed quad-word integers (cvttss2si and friends).
5794 */
5795TYPEDEF_SUBTEST_TYPE(SSE_BINARY_I64_R32_T, SSE_BINARY_I64_R32_TEST_T, PFNIEMAIMPLSSEF2I64U32);
5796
5797static const SSE_BINARY_I64_R32_T g_aSseBinaryI64R32[] =
5798{
5799 ENTRY_BIN(cvttss2si_i64_r32),
5800 ENTRY_BIN(cvtss2si_i64_r32),
5801};
5802
5803#ifdef TSTIEMAIMPL_WITH_GENERATOR
5804static RTEXITCODE SseBinaryI64R32Generate(const char *pszDataFileFmt, uint32_t cTests)
5805{
5806 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
5807
5808 static struct { RTFLOAT32U Val; } const s_aSpecials[] =
5809 {
5810 { RTFLOAT32U_INIT_C(0, 8388607, RTFLOAT32U_EXP_MAX - 1) },
5811 /** @todo More specials. */
5812 };
5813
5814 X86FXSTATE State;
5815 RT_ZERO(State);
5816 uint32_t cMinNormalPairs = (cTests - 144) / 4;
5817 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryI64R32); iFn++)
5818 {
5819 PFNIEMAIMPLSSEF2I64U32 const pfn = g_aSseBinaryI64R32[iFn].pfnNative ? g_aSseBinaryI64R32[iFn].pfnNative : g_aSseBinaryI64R32[iFn].pfn;
5820
5821 PRTSTREAM pStrmOut = NULL;
5822 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseBinaryI64R32[iFn].pszName);
5823 if (RT_FAILURE(rc))
5824 {
5825 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseBinaryI64R32[iFn].pszName, rc);
5826 return RTEXITCODE_FAILURE;
5827 }
5828
5829 uint32_t cNormalInputPairs = 0;
5830 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
5831 {
5832 SSE_BINARY_I64_R32_TEST_T TestData; RT_ZERO(TestData);
5833
5834 TestData.r32ValIn = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].Val;
5835
5836 if (RTFLOAT32U_IS_NORMAL(&TestData.r32ValIn))
5837 cNormalInputPairs++;
5838 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
5839 {
5840 iTest -= 1;
5841 continue;
5842 }
5843
5844 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
5845 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
5846 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
5847 for (uint8_t iFz = 0; iFz < 2; iFz++)
5848 {
5849 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
5850 | (iRounding << X86_MXCSR_RC_SHIFT)
5851 | (iDaz ? X86_MXCSR_DAZ : 0)
5852 | (iFz ? X86_MXCSR_FZ : 0)
5853 | X86_MXCSR_XCPT_MASK;
5854 uint32_t fMxcsrM; int64_t i64OutM;
5855 pfn(&State, &fMxcsrM, &i64OutM, &TestData.r32ValIn.u);
5856 TestData.fMxcsrIn = State.MXCSR;
5857 TestData.fMxcsrOut = fMxcsrM;
5858 TestData.i64ValOut = i64OutM;
5859 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5860
5861 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
5862 uint32_t fMxcsrU; int64_t i64OutU;
5863 pfn(&State, &fMxcsrU, &i64OutU, &TestData.r32ValIn.u);
5864 TestData.fMxcsrIn = State.MXCSR;
5865 TestData.fMxcsrOut = fMxcsrU;
5866 TestData.i64ValOut = i64OutU;
5867 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5868
5869 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
5870 if (fXcpt)
5871 {
5872 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
5873 uint32_t fMxcsr1; int64_t i64Out1;
5874 pfn(&State, &fMxcsr1, &i64Out1, &TestData.r32ValIn.u);
5875 TestData.fMxcsrIn = State.MXCSR;
5876 TestData.fMxcsrOut = fMxcsr1;
5877 TestData.i64ValOut = i64Out1;
5878 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5879
5880 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
5881 {
5882 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
5883 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
5884 uint32_t fMxcsr2; int64_t i64Out2;
5885 pfn(&State, &fMxcsr2, &i64Out2, &TestData.r32ValIn.u);
5886 TestData.fMxcsrIn = State.MXCSR;
5887 TestData.fMxcsrOut = fMxcsr2;
5888 TestData.i64ValOut = i64Out2;
5889 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5890 }
5891 if (!RT_IS_POWER_OF_TWO(fXcpt))
5892 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
5893 if (fUnmasked & fXcpt)
5894 {
5895 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
5896 uint32_t fMxcsr3; int64_t i64Out3;
5897 pfn(&State, &fMxcsr3, &i64Out3, &TestData.r32ValIn.u);
5898 TestData.fMxcsrIn = State.MXCSR;
5899 TestData.fMxcsrOut = fMxcsr3;
5900 TestData.i64ValOut = i64Out3;
5901 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
5902 }
5903 }
5904 }
5905 }
5906 rc = RTStrmClose(pStrmOut);
5907 if (RT_FAILURE(rc))
5908 {
5909 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseBinaryI64R32[iFn].pszName, rc);
5910 return RTEXITCODE_FAILURE;
5911 }
5912 }
5913
5914 return RTEXITCODE_SUCCESS;
5915}
5916#endif
5917
5918
5919static void SseBinaryI64R32Test(void)
5920{
5921 X86FXSTATE State;
5922 RT_ZERO(State);
5923 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryI64R32); iFn++)
5924 {
5925 if (!SubTestAndCheckIfEnabled(g_aSseBinaryI64R32[iFn].pszName))
5926 continue;
5927
5928 uint32_t const cTests = *g_aSseBinaryI64R32[iFn].pcTests;
5929 SSE_BINARY_I64_R32_TEST_T const * const paTests = g_aSseBinaryI64R32[iFn].paTests;
5930 PFNIEMAIMPLSSEF2I64U32 pfn = g_aSseBinaryI64R32[iFn].pfn;
5931 uint32_t const cVars = COUNT_VARIATIONS(g_aSseBinaryI64R32[iFn]);
5932 if (!cTests) RTTestSkipped(g_hTest, "no tests");
5933 for (uint32_t iVar = 0; iVar < cVars; iVar++)
5934 {
5935 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_BINARY_I64_R32_TEST_T); iTest++)
5936 {
5937 uint32_t fMxcsr = 0;
5938 int64_t i64Dst = 0;
5939
5940 State.MXCSR = paTests[iTest].fMxcsrIn;
5941 pfn(&State, &fMxcsr, &i64Dst, &paTests[iTest].r32ValIn.u);
5942 if ( fMxcsr != paTests[iTest].fMxcsrOut
5943 || i64Dst != paTests[iTest].i64ValOut)
5944 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%s\n"
5945 "%s -> mxcsr=%#08x %RI64\n"
5946 "%s expected %#08x %RI64%s%s (%s)\n",
5947 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
5948 FormatR32(&paTests[iTest].r32ValIn),
5949 iVar ? " " : "", fMxcsr, i64Dst,
5950 iVar ? " " : "", paTests[iTest].fMxcsrOut, paTests[iTest].i64ValOut,
5951 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
5952 i64Dst != paTests[iTest].i64ValOut
5953 ? " - val" : "",
5954 FormatMxcsr(paTests[iTest].fMxcsrIn) );
5955 }
5956 }
5957 }
5958}
5959
5960
5961/*
5962 * SSE operations converting single signed double-word integers to double-precision floating point values (probably only cvtsi2sd).
5963 */
5964TYPEDEF_SUBTEST_TYPE(SSE_BINARY_R64_I32_T, SSE_BINARY_R64_I32_TEST_T, PFNIEMAIMPLSSEF2R64I32);
5965
5966static const SSE_BINARY_R64_I32_T g_aSseBinaryR64I32[] =
5967{
5968 ENTRY_BIN(cvtsi2sd_r64_i32)
5969};
5970
5971#ifdef TSTIEMAIMPL_WITH_GENERATOR
5972static RTEXITCODE SseBinaryR64I32Generate(const char *pszDataFileFmt, uint32_t cTests)
5973{
5974 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
5975
5976 static int32_t const s_aSpecials[] =
5977 {
5978 INT32_MIN,
5979 INT32_MAX,
5980 /** @todo More specials. */
5981 };
5982
5983 X86FXSTATE State;
5984 RT_ZERO(State);
5985 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryR64I32); iFn++)
5986 {
5987 PFNIEMAIMPLSSEF2R64I32 const pfn = g_aSseBinaryR64I32[iFn].pfnNative ? g_aSseBinaryR64I32[iFn].pfnNative : g_aSseBinaryR64I32[iFn].pfn;
5988
5989 PRTSTREAM pStrmOut = NULL;
5990 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseBinaryR64I32[iFn].pszName);
5991 if (RT_FAILURE(rc))
5992 {
5993 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseBinaryR64I32[iFn].pszName, rc);
5994 return RTEXITCODE_FAILURE;
5995 }
5996
5997 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
5998 {
5999 SSE_BINARY_R64_I32_TEST_T TestData; RT_ZERO(TestData);
6000
6001 TestData.i32ValIn = iTest < cTests ? RandI32Src2(iTest) : s_aSpecials[iTest - cTests];
6002
6003 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
6004 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
6005 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
6006 for (uint8_t iFz = 0; iFz < 2; iFz++)
6007 {
6008 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
6009 | (iRounding << X86_MXCSR_RC_SHIFT)
6010 | (iDaz ? X86_MXCSR_DAZ : 0)
6011 | (iFz ? X86_MXCSR_FZ : 0)
6012 | X86_MXCSR_XCPT_MASK;
6013 uint32_t fMxcsrM; RTFLOAT64U r64OutM;
6014 pfn(&State, &fMxcsrM, &r64OutM, &TestData.i32ValIn);
6015 TestData.fMxcsrIn = State.MXCSR;
6016 TestData.fMxcsrOut = fMxcsrM;
6017 TestData.r64ValOut = r64OutM;
6018 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6019
6020 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
6021 uint32_t fMxcsrU; RTFLOAT64U r64OutU;
6022 pfn(&State, &fMxcsrU, &r64OutU, &TestData.i32ValIn);
6023 TestData.fMxcsrIn = State.MXCSR;
6024 TestData.fMxcsrOut = fMxcsrU;
6025 TestData.r64ValOut = r64OutU;
6026 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6027
6028 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
6029 if (fXcpt)
6030 {
6031 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
6032 uint32_t fMxcsr1; RTFLOAT64U r64Out1;
6033 pfn(&State, &fMxcsr1, &r64Out1, &TestData.i32ValIn);
6034 TestData.fMxcsrIn = State.MXCSR;
6035 TestData.fMxcsrOut = fMxcsr1;
6036 TestData.r64ValOut = r64Out1;
6037 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6038
6039 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
6040 {
6041 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
6042 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
6043 uint32_t fMxcsr2; RTFLOAT64U r64Out2;
6044 pfn(&State, &fMxcsr2, &r64Out2, &TestData.i32ValIn);
6045 TestData.fMxcsrIn = State.MXCSR;
6046 TestData.fMxcsrOut = fMxcsr2;
6047 TestData.r64ValOut = r64Out2;
6048 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6049 }
6050 if (!RT_IS_POWER_OF_TWO(fXcpt))
6051 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
6052 if (fUnmasked & fXcpt)
6053 {
6054 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
6055 uint32_t fMxcsr3; RTFLOAT64U r64Out3;
6056 pfn(&State, &fMxcsr3, &r64Out3, &TestData.i32ValIn);
6057 TestData.fMxcsrIn = State.MXCSR;
6058 TestData.fMxcsrOut = fMxcsr3;
6059 TestData.r64ValOut = r64Out3;
6060 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6061 }
6062 }
6063 }
6064 }
6065 rc = RTStrmClose(pStrmOut);
6066 if (RT_FAILURE(rc))
6067 {
6068 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseBinaryR64I32[iFn].pszName, rc);
6069 return RTEXITCODE_FAILURE;
6070 }
6071 }
6072
6073 return RTEXITCODE_SUCCESS;
6074}
6075#endif
6076
6077
6078static void SseBinaryR64I32Test(void)
6079{
6080 X86FXSTATE State;
6081 RT_ZERO(State);
6082 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryR64I32); iFn++)
6083 {
6084 if (!SubTestAndCheckIfEnabled(g_aSseBinaryR64I32[iFn].pszName))
6085 continue;
6086
6087 uint32_t const cTests = *g_aSseBinaryR64I32[iFn].pcTests;
6088 SSE_BINARY_R64_I32_TEST_T const * const paTests = g_aSseBinaryR64I32[iFn].paTests;
6089 PFNIEMAIMPLSSEF2R64I32 pfn = g_aSseBinaryR64I32[iFn].pfn;
6090 uint32_t const cVars = COUNT_VARIATIONS(g_aSseBinaryR64I32[iFn]);
6091 if (!cTests) RTTestSkipped(g_hTest, "no tests");
6092 for (uint32_t iVar = 0; iVar < cVars; iVar++)
6093 {
6094 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_BINARY_R64_I32_TEST_T); iTest++)
6095 {
6096 uint32_t fMxcsr = 0;
6097 RTFLOAT64U r64Dst; RT_ZERO(r64Dst);
6098
6099 State.MXCSR = paTests[iTest].fMxcsrIn;
6100 pfn(&State, &fMxcsr, &r64Dst, &paTests[iTest].i32ValIn);
6101 if ( fMxcsr != paTests[iTest].fMxcsrOut
6102 || !RTFLOAT64U_ARE_IDENTICAL(&r64Dst, &paTests[iTest].r64ValOut))
6103 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%RI32\n"
6104 "%s -> mxcsr=%#08x %s\n"
6105 "%s expected %#08x %s%s%s (%s)\n",
6106 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
6107 &paTests[iTest].i32ValIn,
6108 iVar ? " " : "", fMxcsr, FormatR64(&r64Dst),
6109 iVar ? " " : "", paTests[iTest].fMxcsrOut, FormatR64(&paTests[iTest].r64ValOut),
6110 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
6111 !RTFLOAT64U_ARE_IDENTICAL(&r64Dst, &paTests[iTest].r64ValOut)
6112 ? " - val" : "",
6113 FormatMxcsr(paTests[iTest].fMxcsrIn) );
6114 }
6115 }
6116 }
6117}
6118
6119
6120/*
6121 * SSE operations converting single signed quad-word integers to double-precision floating point values (probably only cvtsi2sd).
6122 */
6123TYPEDEF_SUBTEST_TYPE(SSE_BINARY_R64_I64_T, SSE_BINARY_R64_I64_TEST_T, PFNIEMAIMPLSSEF2R64I64);
6124
6125static const SSE_BINARY_R64_I64_T g_aSseBinaryR64I64[] =
6126{
6127 ENTRY_BIN(cvtsi2sd_r64_i64),
6128};
6129
6130#ifdef TSTIEMAIMPL_WITH_GENERATOR
6131static RTEXITCODE SseBinaryR64I64Generate(const char *pszDataFileFmt, uint32_t cTests)
6132{
6133 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
6134
6135 static int64_t const s_aSpecials[] =
6136 {
6137 INT64_MIN,
6138 INT64_MAX
6139 /** @todo More specials. */
6140 };
6141
6142 X86FXSTATE State;
6143 RT_ZERO(State);
6144 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryR64I64); iFn++)
6145 {
6146 PFNIEMAIMPLSSEF2R64I64 const pfn = g_aSseBinaryR64I64[iFn].pfnNative ? g_aSseBinaryR64I64[iFn].pfnNative : g_aSseBinaryR64I64[iFn].pfn;
6147
6148 PRTSTREAM pStrmOut = NULL;
6149 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseBinaryR64I64[iFn].pszName);
6150 if (RT_FAILURE(rc))
6151 {
6152 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseBinaryR64I64[iFn].pszName, rc);
6153 return RTEXITCODE_FAILURE;
6154 }
6155
6156 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
6157 {
6158 SSE_BINARY_R64_I64_TEST_T TestData; RT_ZERO(TestData);
6159
6160 TestData.i64ValIn = iTest < cTests ? RandI64Src(iTest) : s_aSpecials[iTest - cTests];
6161
6162 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
6163 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
6164 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
6165 for (uint8_t iFz = 0; iFz < 2; iFz++)
6166 {
6167 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
6168 | (iRounding << X86_MXCSR_RC_SHIFT)
6169 | (iDaz ? X86_MXCSR_DAZ : 0)
6170 | (iFz ? X86_MXCSR_FZ : 0)
6171 | X86_MXCSR_XCPT_MASK;
6172 uint32_t fMxcsrM; RTFLOAT64U r64OutM;
6173 pfn(&State, &fMxcsrM, &r64OutM, &TestData.i64ValIn);
6174 TestData.fMxcsrIn = State.MXCSR;
6175 TestData.fMxcsrOut = fMxcsrM;
6176 TestData.r64ValOut = r64OutM;
6177 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6178
6179 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
6180 uint32_t fMxcsrU; RTFLOAT64U r64OutU;
6181 pfn(&State, &fMxcsrU, &r64OutU, &TestData.i64ValIn);
6182 TestData.fMxcsrIn = State.MXCSR;
6183 TestData.fMxcsrOut = fMxcsrU;
6184 TestData.r64ValOut = r64OutU;
6185 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6186
6187 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
6188 if (fXcpt)
6189 {
6190 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
6191 uint32_t fMxcsr1; RTFLOAT64U r64Out1;
6192 pfn(&State, &fMxcsr1, &r64Out1, &TestData.i64ValIn);
6193 TestData.fMxcsrIn = State.MXCSR;
6194 TestData.fMxcsrOut = fMxcsr1;
6195 TestData.r64ValOut = r64Out1;
6196 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6197
6198 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
6199 {
6200 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
6201 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
6202 uint32_t fMxcsr2; RTFLOAT64U r64Out2;
6203 pfn(&State, &fMxcsr2, &r64Out2, &TestData.i64ValIn);
6204 TestData.fMxcsrIn = State.MXCSR;
6205 TestData.fMxcsrOut = fMxcsr2;
6206 TestData.r64ValOut = r64Out2;
6207 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6208 }
6209 if (!RT_IS_POWER_OF_TWO(fXcpt))
6210 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
6211 if (fUnmasked & fXcpt)
6212 {
6213 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
6214 uint32_t fMxcsr3; RTFLOAT64U r64Out3;
6215 pfn(&State, &fMxcsr3, &r64Out3, &TestData.i64ValIn);
6216 TestData.fMxcsrIn = State.MXCSR;
6217 TestData.fMxcsrOut = fMxcsr3;
6218 TestData.r64ValOut = r64Out3;
6219 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6220 }
6221 }
6222 }
6223 }
6224 rc = RTStrmClose(pStrmOut);
6225 if (RT_FAILURE(rc))
6226 {
6227 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseBinaryR64I64[iFn].pszName, rc);
6228 return RTEXITCODE_FAILURE;
6229 }
6230 }
6231
6232 return RTEXITCODE_SUCCESS;
6233}
6234#endif
6235
6236
6237static void SseBinaryR64I64Test(void)
6238{
6239 X86FXSTATE State;
6240 RT_ZERO(State);
6241 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryR64I64); iFn++)
6242 {
6243 if (!SubTestAndCheckIfEnabled(g_aSseBinaryR64I64[iFn].pszName))
6244 continue;
6245
6246 uint32_t const cTests = *g_aSseBinaryR64I64[iFn].pcTests;
6247 SSE_BINARY_R64_I64_TEST_T const * const paTests = g_aSseBinaryR64I64[iFn].paTests;
6248 PFNIEMAIMPLSSEF2R64I64 pfn = g_aSseBinaryR64I64[iFn].pfn;
6249 uint32_t const cVars = COUNT_VARIATIONS(g_aSseBinaryR64I64[iFn]);
6250 if (!cTests) RTTestSkipped(g_hTest, "no tests");
6251 for (uint32_t iVar = 0; iVar < cVars; iVar++)
6252 {
6253 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_BINARY_R64_I64_TEST_T); iTest++)
6254 {
6255 uint32_t fMxcsr = 0;
6256 RTFLOAT64U r64Dst; RT_ZERO(r64Dst);
6257
6258 State.MXCSR = paTests[iTest].fMxcsrIn;
6259 pfn(&State, &fMxcsr, &r64Dst, &paTests[iTest].i64ValIn);
6260 if ( fMxcsr != paTests[iTest].fMxcsrOut
6261 || !RTFLOAT64U_ARE_IDENTICAL(&r64Dst, &paTests[iTest].r64ValOut))
6262 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%RI64\n"
6263 "%s -> mxcsr=%#08x %s\n"
6264 "%s expected %#08x %s%s%s (%s)\n",
6265 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
6266 &paTests[iTest].i64ValIn,
6267 iVar ? " " : "", fMxcsr, FormatR64(&r64Dst),
6268 iVar ? " " : "", paTests[iTest].fMxcsrOut, FormatR64(&paTests[iTest].r64ValOut),
6269 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
6270 !RTFLOAT64U_ARE_IDENTICAL(&r64Dst, &paTests[iTest].r64ValOut)
6271 ? " - val" : "",
6272 FormatMxcsr(paTests[iTest].fMxcsrIn) );
6273 }
6274 }
6275 }
6276}
6277
6278
6279/*
6280 * SSE operations converting single signed double-word integers to single-precision floating point values (probably only cvtsi2ss).
6281 */
6282TYPEDEF_SUBTEST_TYPE(SSE_BINARY_R32_I32_T, SSE_BINARY_R32_I32_TEST_T, PFNIEMAIMPLSSEF2R32I32);
6283
6284static const SSE_BINARY_R32_I32_T g_aSseBinaryR32I32[] =
6285{
6286 ENTRY_BIN(cvtsi2ss_r32_i32),
6287};
6288
6289#ifdef TSTIEMAIMPL_WITH_GENERATOR
6290static RTEXITCODE SseBinaryR32I32Generate(const char *pszDataFileFmt, uint32_t cTests)
6291{
6292 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
6293
6294 static int32_t const s_aSpecials[] =
6295 {
6296 INT32_MIN,
6297 INT32_MAX,
6298 /** @todo More specials. */
6299 };
6300
6301 X86FXSTATE State;
6302 RT_ZERO(State);
6303 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryR32I32); iFn++)
6304 {
6305 PFNIEMAIMPLSSEF2R32I32 const pfn = g_aSseBinaryR32I32[iFn].pfnNative ? g_aSseBinaryR32I32[iFn].pfnNative : g_aSseBinaryR32I32[iFn].pfn;
6306
6307 PRTSTREAM pStrmOut = NULL;
6308 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseBinaryR32I32[iFn].pszName);
6309 if (RT_FAILURE(rc))
6310 {
6311 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseBinaryR32I32[iFn].pszName, rc);
6312 return RTEXITCODE_FAILURE;
6313 }
6314
6315 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
6316 {
6317 SSE_BINARY_R32_I32_TEST_T TestData; RT_ZERO(TestData);
6318
6319 TestData.i32ValIn = iTest < cTests ? RandI32Src2(iTest) : s_aSpecials[iTest - cTests];
6320
6321 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
6322 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
6323 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
6324 for (uint8_t iFz = 0; iFz < 2; iFz++)
6325 {
6326 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
6327 | (iRounding << X86_MXCSR_RC_SHIFT)
6328 | (iDaz ? X86_MXCSR_DAZ : 0)
6329 | (iFz ? X86_MXCSR_FZ : 0)
6330 | X86_MXCSR_XCPT_MASK;
6331 uint32_t fMxcsrM; RTFLOAT32U r32OutM;
6332 pfn(&State, &fMxcsrM, &r32OutM, &TestData.i32ValIn);
6333 TestData.fMxcsrIn = State.MXCSR;
6334 TestData.fMxcsrOut = fMxcsrM;
6335 TestData.r32ValOut = r32OutM;
6336 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6337
6338 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
6339 uint32_t fMxcsrU; RTFLOAT32U r32OutU;
6340 pfn(&State, &fMxcsrU, &r32OutU, &TestData.i32ValIn);
6341 TestData.fMxcsrIn = State.MXCSR;
6342 TestData.fMxcsrOut = fMxcsrU;
6343 TestData.r32ValOut = r32OutU;
6344 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6345
6346 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
6347 if (fXcpt)
6348 {
6349 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
6350 uint32_t fMxcsr1; RTFLOAT32U r32Out1;
6351 pfn(&State, &fMxcsr1, &r32Out1, &TestData.i32ValIn);
6352 TestData.fMxcsrIn = State.MXCSR;
6353 TestData.fMxcsrOut = fMxcsr1;
6354 TestData.r32ValOut = r32Out1;
6355 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6356
6357 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
6358 {
6359 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
6360 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
6361 uint32_t fMxcsr2; RTFLOAT32U r32Out2;
6362 pfn(&State, &fMxcsr2, &r32Out2, &TestData.i32ValIn);
6363 TestData.fMxcsrIn = State.MXCSR;
6364 TestData.fMxcsrOut = fMxcsr2;
6365 TestData.r32ValOut = r32Out2;
6366 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6367 }
6368 if (!RT_IS_POWER_OF_TWO(fXcpt))
6369 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
6370 if (fUnmasked & fXcpt)
6371 {
6372 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
6373 uint32_t fMxcsr3; RTFLOAT32U r32Out3;
6374 pfn(&State, &fMxcsr3, &r32Out3, &TestData.i32ValIn);
6375 TestData.fMxcsrIn = State.MXCSR;
6376 TestData.fMxcsrOut = fMxcsr3;
6377 TestData.r32ValOut = r32Out3;
6378 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6379 }
6380 }
6381 }
6382 }
6383 rc = RTStrmClose(pStrmOut);
6384 if (RT_FAILURE(rc))
6385 {
6386 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseBinaryR32I32[iFn].pszName, rc);
6387 return RTEXITCODE_FAILURE;
6388 }
6389 }
6390
6391 return RTEXITCODE_SUCCESS;
6392}
6393#endif
6394
6395
6396static void SseBinaryR32I32Test(void)
6397{
6398 X86FXSTATE State;
6399 RT_ZERO(State);
6400 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryR32I32); iFn++)
6401 {
6402 if (!SubTestAndCheckIfEnabled(g_aSseBinaryR32I32[iFn].pszName))
6403 continue;
6404
6405 uint32_t const cTests = *g_aSseBinaryR32I32[iFn].pcTests;
6406 SSE_BINARY_R32_I32_TEST_T const * const paTests = g_aSseBinaryR32I32[iFn].paTests;
6407 PFNIEMAIMPLSSEF2R32I32 pfn = g_aSseBinaryR32I32[iFn].pfn;
6408 uint32_t const cVars = COUNT_VARIATIONS(g_aSseBinaryR32I32[iFn]);
6409 if (!cTests) RTTestSkipped(g_hTest, "no tests");
6410 for (uint32_t iVar = 0; iVar < cVars; iVar++)
6411 {
6412 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_BINARY_R32_I32_TEST_T); iTest++)
6413 {
6414 uint32_t fMxcsr = 0;
6415 RTFLOAT32U r32Dst; RT_ZERO(r32Dst);
6416
6417 State.MXCSR = paTests[iTest].fMxcsrIn;
6418 pfn(&State, &fMxcsr, &r32Dst, &paTests[iTest].i32ValIn);
6419 if ( fMxcsr != paTests[iTest].fMxcsrOut
6420 || !RTFLOAT32U_ARE_IDENTICAL(&r32Dst, &paTests[iTest].r32ValOut))
6421 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%RI32\n"
6422 "%s -> mxcsr=%#08x %RI32\n"
6423 "%s expected %#08x %RI32%s%s (%s)\n",
6424 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
6425 &paTests[iTest].i32ValIn,
6426 iVar ? " " : "", fMxcsr, FormatR32(&r32Dst),
6427 iVar ? " " : "", paTests[iTest].fMxcsrOut, FormatR32(&paTests[iTest].r32ValOut),
6428 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
6429 !RTFLOAT32U_ARE_IDENTICAL(&r32Dst, &paTests[iTest].r32ValOut)
6430 ? " - val" : "",
6431 FormatMxcsr(paTests[iTest].fMxcsrIn) );
6432 }
6433 }
6434 }
6435}
6436
6437
6438/*
6439 * SSE operations converting single signed quad-word integers to single-precision floating point values (probably only cvtsi2ss).
6440 */
6441TYPEDEF_SUBTEST_TYPE(SSE_BINARY_R32_I64_T, SSE_BINARY_R32_I64_TEST_T, PFNIEMAIMPLSSEF2R32I64);
6442
6443static const SSE_BINARY_R32_I64_T g_aSseBinaryR32I64[] =
6444{
6445 ENTRY_BIN(cvtsi2ss_r32_i64),
6446};
6447
6448#ifdef TSTIEMAIMPL_WITH_GENERATOR
6449static RTEXITCODE SseBinaryR32I64Generate(const char *pszDataFileFmt, uint32_t cTests)
6450{
6451 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
6452
6453 static int64_t const s_aSpecials[] =
6454 {
6455 INT64_MIN,
6456 INT64_MAX
6457 /** @todo More specials. */
6458 };
6459
6460 X86FXSTATE State;
6461 RT_ZERO(State);
6462 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryR32I64); iFn++)
6463 {
6464 PFNIEMAIMPLSSEF2R32I64 const pfn = g_aSseBinaryR32I64[iFn].pfnNative ? g_aSseBinaryR32I64[iFn].pfnNative : g_aSseBinaryR32I64[iFn].pfn;
6465
6466 PRTSTREAM pStrmOut = NULL;
6467 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseBinaryR32I64[iFn].pszName);
6468 if (RT_FAILURE(rc))
6469 {
6470 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseBinaryR32I64[iFn].pszName, rc);
6471 return RTEXITCODE_FAILURE;
6472 }
6473
6474 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
6475 {
6476 SSE_BINARY_R32_I64_TEST_T TestData; RT_ZERO(TestData);
6477
6478 TestData.i64ValIn = iTest < cTests ? RandI64Src(iTest) : s_aSpecials[iTest - cTests];
6479
6480 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
6481 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
6482 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
6483 for (uint8_t iFz = 0; iFz < 2; iFz++)
6484 {
6485 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
6486 | (iRounding << X86_MXCSR_RC_SHIFT)
6487 | (iDaz ? X86_MXCSR_DAZ : 0)
6488 | (iFz ? X86_MXCSR_FZ : 0)
6489 | X86_MXCSR_XCPT_MASK;
6490 uint32_t fMxcsrM; RTFLOAT32U r32OutM;
6491 pfn(&State, &fMxcsrM, &r32OutM, &TestData.i64ValIn);
6492 TestData.fMxcsrIn = State.MXCSR;
6493 TestData.fMxcsrOut = fMxcsrM;
6494 TestData.r32ValOut = r32OutM;
6495 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6496
6497 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
6498 uint32_t fMxcsrU; RTFLOAT32U r32OutU;
6499 pfn(&State, &fMxcsrU, &r32OutU, &TestData.i64ValIn);
6500 TestData.fMxcsrIn = State.MXCSR;
6501 TestData.fMxcsrOut = fMxcsrU;
6502 TestData.r32ValOut = r32OutU;
6503 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6504
6505 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
6506 if (fXcpt)
6507 {
6508 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
6509 uint32_t fMxcsr1; RTFLOAT32U r32Out1;
6510 pfn(&State, &fMxcsr1, &r32Out1, &TestData.i64ValIn);
6511 TestData.fMxcsrIn = State.MXCSR;
6512 TestData.fMxcsrOut = fMxcsr1;
6513 TestData.r32ValOut = r32Out1;
6514 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6515
6516 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
6517 {
6518 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
6519 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
6520 uint32_t fMxcsr2; RTFLOAT32U r32Out2;
6521 pfn(&State, &fMxcsr2, &r32Out2, &TestData.i64ValIn);
6522 TestData.fMxcsrIn = State.MXCSR;
6523 TestData.fMxcsrOut = fMxcsr2;
6524 TestData.r32ValOut = r32Out2;
6525 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6526 }
6527 if (!RT_IS_POWER_OF_TWO(fXcpt))
6528 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
6529 if (fUnmasked & fXcpt)
6530 {
6531 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
6532 uint32_t fMxcsr3; RTFLOAT32U r32Out3;
6533 pfn(&State, &fMxcsr3, &r32Out3, &TestData.i64ValIn);
6534 TestData.fMxcsrIn = State.MXCSR;
6535 TestData.fMxcsrOut = fMxcsr3;
6536 TestData.r32ValOut = r32Out3;
6537 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6538 }
6539 }
6540 }
6541 }
6542 rc = RTStrmClose(pStrmOut);
6543 if (RT_FAILURE(rc))
6544 {
6545 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseBinaryR32I64[iFn].pszName, rc);
6546 return RTEXITCODE_FAILURE;
6547 }
6548 }
6549
6550 return RTEXITCODE_SUCCESS;
6551}
6552#endif
6553
6554
6555static void SseBinaryR32I64Test(void)
6556{
6557 X86FXSTATE State;
6558 RT_ZERO(State);
6559 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseBinaryR32I64); iFn++)
6560 {
6561 if (!SubTestAndCheckIfEnabled(g_aSseBinaryR32I64[iFn].pszName))
6562 continue;
6563
6564 uint32_t const cTests = *g_aSseBinaryR32I64[iFn].pcTests;
6565 SSE_BINARY_R32_I64_TEST_T const * const paTests = g_aSseBinaryR32I64[iFn].paTests;
6566 PFNIEMAIMPLSSEF2R32I64 pfn = g_aSseBinaryR32I64[iFn].pfn;
6567 uint32_t const cVars = COUNT_VARIATIONS(g_aSseBinaryR32I64[iFn]);
6568 if (!cTests) RTTestSkipped(g_hTest, "no tests");
6569 for (uint32_t iVar = 0; iVar < cVars; iVar++)
6570 {
6571 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_BINARY_R32_I64_TEST_T); iTest++)
6572 {
6573 uint32_t fMxcsr = 0;
6574 RTFLOAT32U r32Dst; RT_ZERO(r32Dst);
6575
6576 State.MXCSR = paTests[iTest].fMxcsrIn;
6577 pfn(&State, &fMxcsr, &r32Dst, &paTests[iTest].i64ValIn);
6578 if ( fMxcsr != paTests[iTest].fMxcsrOut
6579 || !RTFLOAT32U_ARE_IDENTICAL(&r32Dst, &paTests[iTest].r32ValOut))
6580 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%RI64\n"
6581 "%s -> mxcsr=%#08x %RI32\n"
6582 "%s expected %#08x %RI32%s%s (%s)\n",
6583 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
6584 &paTests[iTest].i64ValIn,
6585 iVar ? " " : "", fMxcsr, FormatR32(&r32Dst),
6586 iVar ? " " : "", paTests[iTest].fMxcsrOut, FormatR32(&paTests[iTest].r32ValOut),
6587 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
6588 !RTFLOAT32U_ARE_IDENTICAL(&r32Dst, &paTests[iTest].r32ValOut)
6589 ? " - val" : "",
6590 FormatMxcsr(paTests[iTest].fMxcsrIn) );
6591 }
6592 }
6593 }
6594}
6595
6596
6597/*
6598 * Compare SSE operations on single single-precision floating point values - outputting only EFLAGS.
6599 */
6600TYPEDEF_SUBTEST_TYPE(SSE_COMPARE_EFL_R32_R32_T, SSE_COMPARE_EFL_R32_R32_TEST_T, PFNIEMAIMPLF2EFLMXCSR128);
6601
6602static const SSE_COMPARE_EFL_R32_R32_T g_aSseCompareEflR32R32[] =
6603{
6604 ENTRY_BIN(ucomiss_u128),
6605 ENTRY_BIN(comiss_u128),
6606 ENTRY_BIN_AVX(vucomiss_u128),
6607 ENTRY_BIN_AVX(vcomiss_u128),
6608};
6609
6610#ifdef TSTIEMAIMPL_WITH_GENERATOR
6611static RTEXITCODE SseCompareEflR32R32Generate(const char *pszDataFileFmt, uint32_t cTests)
6612{
6613 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
6614
6615 static struct { RTFLOAT32U Val1, Val2; } const s_aSpecials[] =
6616 {
6617 { RTFLOAT32U_INIT_ZERO(0), RTFLOAT32U_INIT_ZERO(0) },
6618 { RTFLOAT32U_INIT_ZERO(0), RTFLOAT32U_INIT_ZERO(1) },
6619 { RTFLOAT32U_INIT_ZERO(1), RTFLOAT32U_INIT_ZERO(0) },
6620 { RTFLOAT32U_INIT_ZERO(1), RTFLOAT32U_INIT_ZERO(1) },
6621 { RTFLOAT32U_INIT_INF(0), RTFLOAT32U_INIT_INF(0) },
6622 { RTFLOAT32U_INIT_INF(0), RTFLOAT32U_INIT_INF(1) },
6623 { RTFLOAT32U_INIT_INF(1), RTFLOAT32U_INIT_INF(0) },
6624 { RTFLOAT32U_INIT_INF(1), RTFLOAT32U_INIT_INF(1) },
6625 /** @todo More specials. */
6626 };
6627
6628 uint32_t cMinNormalPairs = (cTests - 144) / 4;
6629 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseCompareEflR32R32); iFn++)
6630 {
6631 PFNIEMAIMPLF2EFLMXCSR128 const pfn = g_aSseCompareEflR32R32[iFn].pfnNative ? g_aSseCompareEflR32R32[iFn].pfnNative : g_aSseCompareEflR32R32[iFn].pfn;
6632
6633 PRTSTREAM pStrmOut = NULL;
6634 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseCompareEflR32R32[iFn].pszName);
6635 if (RT_FAILURE(rc))
6636 {
6637 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseCompareEflR32R32[iFn].pszName, rc);
6638 return RTEXITCODE_FAILURE;
6639 }
6640
6641 uint32_t cNormalInputPairs = 0;
6642 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
6643 {
6644 SSE_COMPARE_EFL_R32_R32_TEST_T TestData; RT_ZERO(TestData);
6645 X86XMMREG ValIn1; RT_ZERO(ValIn1);
6646 X86XMMREG ValIn2; RT_ZERO(ValIn2);
6647
6648 TestData.r32ValIn1 = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].Val1;
6649 TestData.r32ValIn2 = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].Val2;
6650
6651 ValIn1.ar32[0] = TestData.r32ValIn1;
6652 ValIn2.ar32[0] = TestData.r32ValIn2;
6653
6654 if ( RTFLOAT32U_IS_NORMAL(&TestData.r32ValIn1)
6655 && RTFLOAT32U_IS_NORMAL(&TestData.r32ValIn2))
6656 cNormalInputPairs++;
6657 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
6658 {
6659 iTest -= 1;
6660 continue;
6661 }
6662
6663 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
6664 uint32_t const fEFlags = RandEFlags();
6665 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
6666 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
6667 for (uint8_t iFz = 0; iFz < 2; iFz++)
6668 {
6669 uint32_t fMxcsrIn = (fMxcsr & ~X86_MXCSR_RC_MASK)
6670 | (iRounding << X86_MXCSR_RC_SHIFT)
6671 | (iDaz ? X86_MXCSR_DAZ : 0)
6672 | (iFz ? X86_MXCSR_FZ : 0)
6673 | X86_MXCSR_XCPT_MASK;
6674 uint32_t fMxcsrM = fMxcsrIn;
6675 uint32_t fEFlagsM = fEFlags;
6676 pfn(&fMxcsrM, &fEFlagsM, &ValIn1, &ValIn2);
6677 TestData.fMxcsrIn = fMxcsrIn;
6678 TestData.fMxcsrOut = fMxcsrM;
6679 TestData.fEflIn = fEFlags;
6680 TestData.fEflOut = fEFlagsM;
6681 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6682
6683 fMxcsrIn &= ~X86_MXCSR_XCPT_MASK;
6684 uint32_t fMxcsrU = fMxcsrIn;
6685 uint32_t fEFlagsU = fEFlags;
6686 pfn(&fMxcsrU, &fEFlagsU, &ValIn1, &ValIn2);
6687 TestData.fMxcsrIn = fMxcsrIn;
6688 TestData.fMxcsrOut = fMxcsrU;
6689 TestData.fEflIn = fEFlags;
6690 TestData.fEflOut = fEFlagsU;
6691 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6692
6693 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
6694 if (fXcpt)
6695 {
6696 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | fXcpt;
6697 uint32_t fMxcsr1 = fMxcsrIn;
6698 uint32_t fEFlags1 = fEFlags;
6699 pfn(&fMxcsr1, &fEFlags1, &ValIn1, &ValIn2);
6700 TestData.fMxcsrIn = fMxcsrIn;
6701 TestData.fMxcsrOut = fMxcsr1;
6702 TestData.fEflIn = fEFlags;
6703 TestData.fEflOut = fEFlags1;
6704 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6705
6706 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
6707 {
6708 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
6709 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
6710 uint32_t fMxcsr2 = fMxcsrIn;
6711 uint32_t fEFlags2 = fEFlags;
6712 pfn(&fMxcsr2, &fEFlags2, &ValIn1, &ValIn2);
6713 TestData.fMxcsrIn = fMxcsrIn;
6714 TestData.fMxcsrOut = fMxcsr2;
6715 TestData.fEflIn = fEFlags;
6716 TestData.fEflOut = fEFlags2;
6717 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6718 }
6719 if (!RT_IS_POWER_OF_TWO(fXcpt))
6720 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
6721 if (fUnmasked & fXcpt)
6722 {
6723 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
6724 uint32_t fMxcsr3 = fMxcsrIn;
6725 uint32_t fEFlags3 = fEFlags;
6726 pfn(&fMxcsr3, &fEFlags3, &ValIn1, &ValIn2);
6727 TestData.fMxcsrIn = fMxcsrIn;
6728 TestData.fMxcsrOut = fMxcsr3;
6729 TestData.fEflIn = fEFlags;
6730 TestData.fEflOut = fEFlags3;
6731 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6732 }
6733 }
6734 }
6735 }
6736 rc = RTStrmClose(pStrmOut);
6737 if (RT_FAILURE(rc))
6738 {
6739 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseCompareEflR32R32[iFn].pszName, rc);
6740 return RTEXITCODE_FAILURE;
6741 }
6742 }
6743
6744 return RTEXITCODE_SUCCESS;
6745}
6746#endif
6747
6748static void SseCompareEflR32R32Test(void)
6749{
6750 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseCompareEflR32R32); iFn++)
6751 {
6752 if (!SubTestAndCheckIfEnabled(g_aSseCompareEflR32R32[iFn].pszName))
6753 continue;
6754
6755 uint32_t const cTests = *g_aSseCompareEflR32R32[iFn].pcTests;
6756 SSE_COMPARE_EFL_R32_R32_TEST_T const * const paTests = g_aSseCompareEflR32R32[iFn].paTests;
6757 PFNIEMAIMPLF2EFLMXCSR128 pfn = g_aSseCompareEflR32R32[iFn].pfn;
6758 uint32_t const cVars = COUNT_VARIATIONS(g_aSseCompareEflR32R32[iFn]);
6759 if (!cTests) RTTestSkipped(g_hTest, "no tests");
6760 for (uint32_t iVar = 0; iVar < cVars; iVar++)
6761 {
6762 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_COMPARE_EFL_R32_R32_TEST_T); iTest++)
6763 {
6764 X86XMMREG ValIn1; RT_ZERO(ValIn1);
6765 X86XMMREG ValIn2; RT_ZERO(ValIn2);
6766
6767 ValIn1.ar32[0] = paTests[iTest].r32ValIn1;
6768 ValIn2.ar32[0] = paTests[iTest].r32ValIn2;
6769 uint32_t fMxcsr = paTests[iTest].fMxcsrIn;
6770 uint32_t fEFlags = paTests[iTest].fEflIn;
6771 pfn(&fMxcsr, &fEFlags, &ValIn1, &ValIn2);
6772 if ( fMxcsr != paTests[iTest].fMxcsrOut
6773 || fEFlags != paTests[iTest].fEflOut)
6774 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x efl=%#08x in1=%s in2=%s\n"
6775 "%s -> mxcsr=%#08x %#08x\n"
6776 "%s expected %#08x %#08x%s (%s) (EFL: %s)\n",
6777 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn, paTests[iTest].fEflIn,
6778 FormatR32(&paTests[iTest].r32ValIn1), FormatR32(&paTests[iTest].r32ValIn2),
6779 iVar ? " " : "", fMxcsr, fEFlags,
6780 iVar ? " " : "", paTests[iTest].fMxcsrOut, paTests[iTest].fEflOut,
6781 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
6782 FormatMxcsr(paTests[iTest].fMxcsrIn),
6783 EFlagsDiff(fEFlags, paTests[iTest].fEflOut));
6784 }
6785 }
6786 }
6787}
6788
6789
6790/*
6791 * Compare SSE operations on single single-precision floating point values - outputting only EFLAGS.
6792 */
6793TYPEDEF_SUBTEST_TYPE(SSE_COMPARE_EFL_R64_R64_T, SSE_COMPARE_EFL_R64_R64_TEST_T, PFNIEMAIMPLF2EFLMXCSR128);
6794
6795static const SSE_COMPARE_EFL_R64_R64_T g_aSseCompareEflR64R64[] =
6796{
6797 ENTRY_BIN(ucomisd_u128),
6798 ENTRY_BIN(comisd_u128),
6799 ENTRY_BIN_AVX(vucomisd_u128),
6800 ENTRY_BIN_AVX(vcomisd_u128)
6801};
6802
6803#ifdef TSTIEMAIMPL_WITH_GENERATOR
6804static RTEXITCODE SseCompareEflR64R64Generate(const char *pszDataFileFmt, uint32_t cTests)
6805{
6806 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
6807
6808 static struct { RTFLOAT64U Val1, Val2; } const s_aSpecials[] =
6809 {
6810 { RTFLOAT64U_INIT_ZERO(0), RTFLOAT64U_INIT_ZERO(0) },
6811 { RTFLOAT64U_INIT_ZERO(0), RTFLOAT64U_INIT_ZERO(1) },
6812 { RTFLOAT64U_INIT_ZERO(1), RTFLOAT64U_INIT_ZERO(0) },
6813 { RTFLOAT64U_INIT_ZERO(1), RTFLOAT64U_INIT_ZERO(1) },
6814 { RTFLOAT64U_INIT_INF(0), RTFLOAT64U_INIT_INF(0) },
6815 { RTFLOAT64U_INIT_INF(0), RTFLOAT64U_INIT_INF(1) },
6816 { RTFLOAT64U_INIT_INF(1), RTFLOAT64U_INIT_INF(0) },
6817 { RTFLOAT64U_INIT_INF(1), RTFLOAT64U_INIT_INF(1) },
6818 /** @todo More specials. */
6819 };
6820
6821 uint32_t cMinNormalPairs = (cTests - 144) / 4;
6822 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseCompareEflR64R64); iFn++)
6823 {
6824 PFNIEMAIMPLF2EFLMXCSR128 const pfn = g_aSseCompareEflR64R64[iFn].pfnNative ? g_aSseCompareEflR64R64[iFn].pfnNative : g_aSseCompareEflR64R64[iFn].pfn;
6825
6826 PRTSTREAM pStrmOut = NULL;
6827 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseCompareEflR64R64[iFn].pszName);
6828 if (RT_FAILURE(rc))
6829 {
6830 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseCompareEflR64R64[iFn].pszName, rc);
6831 return RTEXITCODE_FAILURE;
6832 }
6833
6834 uint32_t cNormalInputPairs = 0;
6835 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
6836 {
6837 SSE_COMPARE_EFL_R64_R64_TEST_T TestData; RT_ZERO(TestData);
6838 X86XMMREG ValIn1; RT_ZERO(ValIn1);
6839 X86XMMREG ValIn2; RT_ZERO(ValIn2);
6840
6841 TestData.r64ValIn1 = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].Val1;
6842 TestData.r64ValIn2 = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].Val2;
6843
6844 ValIn1.ar64[0] = TestData.r64ValIn1;
6845 ValIn2.ar64[0] = TestData.r64ValIn2;
6846
6847 if ( RTFLOAT64U_IS_NORMAL(&TestData.r64ValIn1)
6848 && RTFLOAT64U_IS_NORMAL(&TestData.r64ValIn2))
6849 cNormalInputPairs++;
6850 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
6851 {
6852 iTest -= 1;
6853 continue;
6854 }
6855
6856 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
6857 uint32_t const fEFlags = RandEFlags();
6858 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
6859 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
6860 for (uint8_t iFz = 0; iFz < 2; iFz++)
6861 {
6862 uint32_t fMxcsrIn = (fMxcsr & ~X86_MXCSR_RC_MASK)
6863 | (iRounding << X86_MXCSR_RC_SHIFT)
6864 | (iDaz ? X86_MXCSR_DAZ : 0)
6865 | (iFz ? X86_MXCSR_FZ : 0)
6866 | X86_MXCSR_XCPT_MASK;
6867 uint32_t fMxcsrM = fMxcsrIn;
6868 uint32_t fEFlagsM = fEFlags;
6869 pfn(&fMxcsrM, &fEFlagsM, &ValIn1, &ValIn2);
6870 TestData.fMxcsrIn = fMxcsrIn;
6871 TestData.fMxcsrOut = fMxcsrM;
6872 TestData.fEflIn = fEFlags;
6873 TestData.fEflOut = fEFlagsM;
6874 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6875
6876 fMxcsrIn &= ~X86_MXCSR_XCPT_MASK;
6877 uint32_t fMxcsrU = fMxcsrIn;
6878 uint32_t fEFlagsU = fEFlags;
6879 pfn(&fMxcsrU, &fEFlagsU, &ValIn1, &ValIn2);
6880 TestData.fMxcsrIn = fMxcsrIn;
6881 TestData.fMxcsrOut = fMxcsrU;
6882 TestData.fEflIn = fEFlags;
6883 TestData.fEflOut = fEFlagsU;
6884 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6885
6886 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
6887 if (fXcpt)
6888 {
6889 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | fXcpt;
6890 uint32_t fMxcsr1 = fMxcsrIn;
6891 uint32_t fEFlags1 = fEFlags;
6892 pfn(&fMxcsr1, &fEFlags1, &ValIn1, &ValIn2);
6893 TestData.fMxcsrIn = fMxcsrIn;
6894 TestData.fMxcsrOut = fMxcsr1;
6895 TestData.fEflIn = fEFlags;
6896 TestData.fEflOut = fEFlags1;
6897 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6898
6899 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
6900 {
6901 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
6902 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
6903 uint32_t fMxcsr2 = fMxcsrIn;
6904 uint32_t fEFlags2 = fEFlags;
6905 pfn(&fMxcsr2, &fEFlags2, &ValIn1, &ValIn2);
6906 TestData.fMxcsrIn = fMxcsrIn;
6907 TestData.fMxcsrOut = fMxcsr2;
6908 TestData.fEflIn = fEFlags;
6909 TestData.fEflOut = fEFlags2;
6910 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6911 }
6912 if (!RT_IS_POWER_OF_TWO(fXcpt))
6913 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
6914 if (fUnmasked & fXcpt)
6915 {
6916 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
6917 uint32_t fMxcsr3 = fMxcsrIn;
6918 uint32_t fEFlags3 = fEFlags;
6919 pfn(&fMxcsr3, &fEFlags3, &ValIn1, &ValIn2);
6920 TestData.fMxcsrIn = fMxcsrIn;
6921 TestData.fMxcsrOut = fMxcsr3;
6922 TestData.fEflIn = fEFlags;
6923 TestData.fEflOut = fEFlags3;
6924 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
6925 }
6926 }
6927 }
6928 }
6929 rc = RTStrmClose(pStrmOut);
6930 if (RT_FAILURE(rc))
6931 {
6932 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseCompareEflR64R64[iFn].pszName, rc);
6933 return RTEXITCODE_FAILURE;
6934 }
6935 }
6936
6937 return RTEXITCODE_SUCCESS;
6938}
6939#endif
6940
6941static void SseCompareEflR64R64Test(void)
6942{
6943 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseCompareEflR64R64); iFn++)
6944 {
6945 if (!SubTestAndCheckIfEnabled(g_aSseCompareEflR64R64[iFn].pszName))
6946 continue;
6947
6948 uint32_t const cTests = *g_aSseCompareEflR64R64[iFn].pcTests;
6949 SSE_COMPARE_EFL_R64_R64_TEST_T const * const paTests = g_aSseCompareEflR64R64[iFn].paTests;
6950 PFNIEMAIMPLF2EFLMXCSR128 pfn = g_aSseCompareEflR64R64[iFn].pfn;
6951 uint32_t const cVars = COUNT_VARIATIONS(g_aSseCompareEflR64R64[iFn]);
6952 if (!cTests) RTTestSkipped(g_hTest, "no tests");
6953 for (uint32_t iVar = 0; iVar < cVars; iVar++)
6954 {
6955 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_COMPARE_EFL_R64_R64_TEST_T); iTest++)
6956 {
6957 X86XMMREG ValIn1; RT_ZERO(ValIn1);
6958 X86XMMREG ValIn2; RT_ZERO(ValIn2);
6959
6960 ValIn1.ar64[0] = paTests[iTest].r64ValIn1;
6961 ValIn2.ar64[0] = paTests[iTest].r64ValIn2;
6962 uint32_t fMxcsr = paTests[iTest].fMxcsrIn;
6963 uint32_t fEFlags = paTests[iTest].fEflIn;
6964 pfn(&fMxcsr, &fEFlags, &ValIn1, &ValIn2);
6965 if ( fMxcsr != paTests[iTest].fMxcsrOut
6966 || fEFlags != paTests[iTest].fEflOut)
6967 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x efl=%#08x in1=%s in2=%s\n"
6968 "%s -> mxcsr=%#08x %#08x\n"
6969 "%s expected %#08x %#08x%s (%s) (EFL: %s)\n",
6970 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn, paTests[iTest].fEflIn,
6971 FormatR64(&paTests[iTest].r64ValIn1), FormatR64(&paTests[iTest].r64ValIn2),
6972 iVar ? " " : "", fMxcsr, fEFlags,
6973 iVar ? " " : "", paTests[iTest].fMxcsrOut, paTests[iTest].fEflOut,
6974 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
6975 FormatMxcsr(paTests[iTest].fMxcsrIn),
6976 EFlagsDiff(fEFlags, paTests[iTest].fEflOut));
6977 }
6978 }
6979 }
6980}
6981
6982
6983/*
6984 * Compare SSE operations on packed and single single-precision floating point values - outputting a mask.
6985 */
6986/** Maximum immediate to try to keep the testdata size under control (at least a little bit)- */
6987#define SSE_COMPARE_F2_XMM_IMM8_MAX 0x1f
6988
6989TYPEDEF_SUBTEST_TYPE(SSE_COMPARE_F2_XMM_IMM8_T, SSE_COMPARE_F2_XMM_IMM8_TEST_T, PFNIEMAIMPLMXCSRF2XMMIMM8);
6990
6991static const SSE_COMPARE_F2_XMM_IMM8_T g_aSseCompareF2XmmR32Imm8[] =
6992{
6993 ENTRY_BIN(cmpps_u128),
6994 ENTRY_BIN(cmpss_u128)
6995};
6996
6997#ifdef TSTIEMAIMPL_WITH_GENERATOR
6998static RTEXITCODE SseCompareF2XmmR32Imm8Generate(const char *pszDataFileFmt, uint32_t cTests)
6999{
7000 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
7001
7002 static struct { RTFLOAT32U Val1, Val2; } const s_aSpecials[] =
7003 {
7004 { RTFLOAT32U_INIT_ZERO(0), RTFLOAT32U_INIT_ZERO(0) },
7005 { RTFLOAT32U_INIT_ZERO(0), RTFLOAT32U_INIT_ZERO(1) },
7006 { RTFLOAT32U_INIT_ZERO(1), RTFLOAT32U_INIT_ZERO(0) },
7007 { RTFLOAT32U_INIT_ZERO(1), RTFLOAT32U_INIT_ZERO(1) },
7008 { RTFLOAT32U_INIT_INF(0), RTFLOAT32U_INIT_INF(0) },
7009 { RTFLOAT32U_INIT_INF(0), RTFLOAT32U_INIT_INF(1) },
7010 { RTFLOAT32U_INIT_INF(1), RTFLOAT32U_INIT_INF(0) },
7011 { RTFLOAT32U_INIT_INF(1), RTFLOAT32U_INIT_INF(1) },
7012 /** @todo More specials. */
7013 };
7014
7015 uint32_t cMinNormalPairs = (cTests - 144) / 4;
7016 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseCompareF2XmmR32Imm8); iFn++)
7017 {
7018 PFNIEMAIMPLMXCSRF2XMMIMM8 const pfn = g_aSseCompareF2XmmR32Imm8[iFn].pfnNative ? g_aSseCompareF2XmmR32Imm8[iFn].pfnNative : g_aSseCompareF2XmmR32Imm8[iFn].pfn;
7019
7020 PRTSTREAM pStrmOut = NULL;
7021 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseCompareF2XmmR32Imm8[iFn].pszName);
7022 if (RT_FAILURE(rc))
7023 {
7024 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseCompareF2XmmR32Imm8[iFn].pszName, rc);
7025 return RTEXITCODE_FAILURE;
7026 }
7027
7028 uint32_t cNormalInputPairs = 0;
7029 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
7030 {
7031 SSE_COMPARE_F2_XMM_IMM8_TEST_T TestData; RT_ZERO(TestData);
7032
7033 TestData.InVal1.ar32[0] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].Val1;
7034 TestData.InVal1.ar32[1] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].Val1;
7035 TestData.InVal1.ar32[2] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].Val1;
7036 TestData.InVal1.ar32[3] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].Val1;
7037
7038 TestData.InVal2.ar32[0] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].Val2;
7039 TestData.InVal2.ar32[1] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].Val2;
7040 TestData.InVal2.ar32[2] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].Val2;
7041 TestData.InVal2.ar32[3] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].Val2;
7042
7043 if ( RTFLOAT32U_IS_NORMAL(&TestData.InVal1.ar32[0])
7044 && RTFLOAT32U_IS_NORMAL(&TestData.InVal1.ar32[1])
7045 && RTFLOAT32U_IS_NORMAL(&TestData.InVal1.ar32[2])
7046 && RTFLOAT32U_IS_NORMAL(&TestData.InVal1.ar32[3])
7047 && RTFLOAT32U_IS_NORMAL(&TestData.InVal2.ar32[0])
7048 && RTFLOAT32U_IS_NORMAL(&TestData.InVal2.ar32[1])
7049 && RTFLOAT32U_IS_NORMAL(&TestData.InVal2.ar32[2])
7050 && RTFLOAT32U_IS_NORMAL(&TestData.InVal2.ar32[3]))
7051 cNormalInputPairs++;
7052 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
7053 {
7054 iTest -= 1;
7055 continue;
7056 }
7057
7058 IEMMEDIAF2XMMSRC Src;
7059 Src.uSrc1 = TestData.InVal1;
7060 Src.uSrc2 = TestData.InVal2;
7061 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
7062 for (uint8_t bImm = 0; bImm <= SSE_COMPARE_F2_XMM_IMM8_MAX; bImm++)
7063 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
7064 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
7065 for (uint8_t iFz = 0; iFz < 2; iFz++)
7066 {
7067 uint32_t fMxcsrIn = (fMxcsr & ~X86_MXCSR_RC_MASK)
7068 | (iRounding << X86_MXCSR_RC_SHIFT)
7069 | (iDaz ? X86_MXCSR_DAZ : 0)
7070 | (iFz ? X86_MXCSR_FZ : 0)
7071 | X86_MXCSR_XCPT_MASK;
7072 uint32_t fMxcsrM = fMxcsrIn;
7073 X86XMMREG ResM;
7074 pfn(&fMxcsrM, &ResM, &Src, bImm);
7075 TestData.fMxcsrIn = fMxcsrIn;
7076 TestData.fMxcsrOut = fMxcsrM;
7077 TestData.bImm = bImm;
7078 TestData.OutVal = ResM;
7079 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7080
7081 fMxcsrIn &= ~X86_MXCSR_XCPT_MASK;
7082 uint32_t fMxcsrU = fMxcsrIn;
7083 X86XMMREG ResU;
7084 pfn(&fMxcsrU, &ResU, &Src, bImm);
7085 TestData.fMxcsrIn = fMxcsrIn;
7086 TestData.fMxcsrOut = fMxcsrU;
7087 TestData.bImm = bImm;
7088 TestData.OutVal = ResU;
7089 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7090
7091 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
7092 if (fXcpt)
7093 {
7094 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | fXcpt;
7095 uint32_t fMxcsr1 = fMxcsrIn;
7096 X86XMMREG Res1;
7097 pfn(&fMxcsr1, &Res1, &Src, bImm);
7098 TestData.fMxcsrIn = fMxcsrIn;
7099 TestData.fMxcsrOut = fMxcsr1;
7100 TestData.bImm = bImm;
7101 TestData.OutVal = Res1;
7102 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7103
7104 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
7105 {
7106 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
7107 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
7108 uint32_t fMxcsr2 = fMxcsrIn;
7109 X86XMMREG Res2;
7110 pfn(&fMxcsr2, &Res2, &Src, bImm);
7111 TestData.fMxcsrIn = fMxcsrIn;
7112 TestData.fMxcsrOut = fMxcsr2;
7113 TestData.bImm = bImm;
7114 TestData.OutVal = Res2;
7115 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7116 }
7117 if (!RT_IS_POWER_OF_TWO(fXcpt))
7118 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
7119 if (fUnmasked & fXcpt)
7120 {
7121 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
7122 uint32_t fMxcsr3 = fMxcsrIn;
7123 X86XMMREG Res3;
7124 pfn(&fMxcsr3, &Res3, &Src, bImm);
7125 TestData.fMxcsrIn = fMxcsrIn;
7126 TestData.fMxcsrOut = fMxcsr3;
7127 TestData.bImm = bImm;
7128 TestData.OutVal = Res3;
7129 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7130 }
7131 }
7132 }
7133 }
7134 rc = RTStrmClose(pStrmOut);
7135 if (RT_FAILURE(rc))
7136 {
7137 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseCompareF2XmmR32Imm8[iFn].pszName, rc);
7138 return RTEXITCODE_FAILURE;
7139 }
7140 }
7141
7142 return RTEXITCODE_SUCCESS;
7143}
7144#endif
7145
7146static void SseCompareF2XmmR32Imm8Test(void)
7147{
7148 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseCompareF2XmmR32Imm8); iFn++)
7149 {
7150 if (!SubTestAndCheckIfEnabled(g_aSseCompareF2XmmR32Imm8[iFn].pszName))
7151 continue;
7152
7153 uint32_t const cTests = *g_aSseCompareF2XmmR32Imm8[iFn].pcTests;
7154 SSE_COMPARE_F2_XMM_IMM8_TEST_T const * const paTests = g_aSseCompareF2XmmR32Imm8[iFn].paTests;
7155 PFNIEMAIMPLMXCSRF2XMMIMM8 pfn = g_aSseCompareF2XmmR32Imm8[iFn].pfn;
7156 uint32_t const cVars = COUNT_VARIATIONS(g_aSseCompareF2XmmR32Imm8[iFn]);
7157 if (!cTests) RTTestSkipped(g_hTest, "no tests");
7158 for (uint32_t iVar = 0; iVar < cVars; iVar++)
7159 {
7160 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_COMPARE_F2_XMM_IMM8_TEST_T); iTest++)
7161 {
7162 IEMMEDIAF2XMMSRC Src;
7163 X86XMMREG ValOut;
7164
7165 Src.uSrc1 = paTests[iTest].InVal1;
7166 Src.uSrc2 = paTests[iTest].InVal2;
7167 uint32_t fMxcsr = paTests[iTest].fMxcsrIn;
7168 pfn(&fMxcsr, &ValOut, &Src, paTests[iTest].bImm);
7169 if ( fMxcsr != paTests[iTest].fMxcsrOut
7170 || ValOut.au32[0] != paTests[iTest].OutVal.au32[0]
7171 || ValOut.au32[1] != paTests[iTest].OutVal.au32[1]
7172 || ValOut.au32[2] != paTests[iTest].OutVal.au32[2]
7173 || ValOut.au32[3] != paTests[iTest].OutVal.au32[3])
7174 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%s'%s'%s'%s in2=%s'%s'%s'%s imm8=%x\n"
7175 "%s -> mxcsr=%#08x %RX32'%RX32'%RX32'%RX32\n"
7176 "%s expected %#08x %RX32'%RX32'%RX32'%RX32%s%s (%s)\n",
7177 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
7178 FormatR32(&paTests[iTest].InVal1.ar32[0]), FormatR32(&paTests[iTest].InVal1.ar32[1]),
7179 FormatR32(&paTests[iTest].InVal1.ar32[2]), FormatR32(&paTests[iTest].InVal1.ar32[3]),
7180 FormatR32(&paTests[iTest].InVal2.ar32[0]), FormatR32(&paTests[iTest].InVal2.ar32[1]),
7181 FormatR32(&paTests[iTest].InVal2.ar32[2]), FormatR32(&paTests[iTest].InVal2.ar32[3]),
7182 paTests[iTest].bImm,
7183 iVar ? " " : "", fMxcsr, ValOut.au32[0], ValOut.au32[1], ValOut.au32[2], ValOut.au32[3],
7184 iVar ? " " : "", paTests[iTest].fMxcsrOut,
7185 paTests[iTest].OutVal.au32[0], paTests[iTest].OutVal.au32[1],
7186 paTests[iTest].OutVal.au32[2], paTests[iTest].OutVal.au32[3],
7187 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
7188 ( ValOut.au32[0] != paTests[iTest].OutVal.au32[0]
7189 || ValOut.au32[1] != paTests[iTest].OutVal.au32[1]
7190 || ValOut.au32[2] != paTests[iTest].OutVal.au32[2]
7191 || ValOut.au32[3] != paTests[iTest].OutVal.au32[3])
7192 ? " - val" : "",
7193 FormatMxcsr(paTests[iTest].fMxcsrIn));
7194 }
7195 }
7196 }
7197}
7198
7199
7200/*
7201 * Compare SSE operations on packed and single double-precision floating point values - outputting a mask.
7202 */
7203static const SSE_COMPARE_F2_XMM_IMM8_T g_aSseCompareF2XmmR64Imm8[] =
7204{
7205 ENTRY_BIN(cmppd_u128),
7206 ENTRY_BIN(cmpsd_u128)
7207};
7208
7209#ifdef TSTIEMAIMPL_WITH_GENERATOR
7210static RTEXITCODE SseCompareF2XmmR64Imm8Generate(const char *pszDataFileFmt, uint32_t cTests)
7211{
7212 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
7213
7214 static struct { RTFLOAT64U Val1, Val2; } const s_aSpecials[] =
7215 {
7216 { RTFLOAT64U_INIT_ZERO(0), RTFLOAT64U_INIT_ZERO(0) },
7217 { RTFLOAT64U_INIT_ZERO(0), RTFLOAT64U_INIT_ZERO(1) },
7218 { RTFLOAT64U_INIT_ZERO(1), RTFLOAT64U_INIT_ZERO(0) },
7219 { RTFLOAT64U_INIT_ZERO(1), RTFLOAT64U_INIT_ZERO(1) },
7220 { RTFLOAT64U_INIT_INF(0), RTFLOAT64U_INIT_INF(0) },
7221 { RTFLOAT64U_INIT_INF(0), RTFLOAT64U_INIT_INF(1) },
7222 { RTFLOAT64U_INIT_INF(1), RTFLOAT64U_INIT_INF(0) },
7223 { RTFLOAT64U_INIT_INF(1), RTFLOAT64U_INIT_INF(1) },
7224 /** @todo More specials. */
7225 };
7226
7227 uint32_t cMinNormalPairs = (cTests - 144) / 4;
7228 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseCompareF2XmmR64Imm8); iFn++)
7229 {
7230 PFNIEMAIMPLMXCSRF2XMMIMM8 const pfn = g_aSseCompareF2XmmR64Imm8[iFn].pfnNative ? g_aSseCompareF2XmmR64Imm8[iFn].pfnNative : g_aSseCompareF2XmmR64Imm8[iFn].pfn;
7231
7232 PRTSTREAM pStrmOut = NULL;
7233 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseCompareF2XmmR64Imm8[iFn].pszName);
7234 if (RT_FAILURE(rc))
7235 {
7236 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseCompareF2XmmR64Imm8[iFn].pszName, rc);
7237 return RTEXITCODE_FAILURE;
7238 }
7239
7240 uint32_t cNormalInputPairs = 0;
7241 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
7242 {
7243 SSE_COMPARE_F2_XMM_IMM8_TEST_T TestData; RT_ZERO(TestData);
7244
7245 TestData.InVal1.ar64[0] = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].Val1;
7246 TestData.InVal1.ar64[1] = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].Val1;
7247
7248 TestData.InVal2.ar64[0] = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].Val2;
7249 TestData.InVal2.ar64[1] = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].Val2;
7250
7251 if ( RTFLOAT64U_IS_NORMAL(&TestData.InVal1.ar64[0])
7252 && RTFLOAT64U_IS_NORMAL(&TestData.InVal1.ar64[1])
7253 && RTFLOAT64U_IS_NORMAL(&TestData.InVal2.ar64[0])
7254 && RTFLOAT64U_IS_NORMAL(&TestData.InVal2.ar64[1]))
7255 cNormalInputPairs++;
7256 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
7257 {
7258 iTest -= 1;
7259 continue;
7260 }
7261
7262 IEMMEDIAF2XMMSRC Src;
7263 Src.uSrc1 = TestData.InVal1;
7264 Src.uSrc2 = TestData.InVal2;
7265 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
7266 for (uint8_t bImm = 0; bImm <= SSE_COMPARE_F2_XMM_IMM8_MAX; bImm++)
7267 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
7268 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
7269 for (uint8_t iFz = 0; iFz < 2; iFz++)
7270 {
7271 uint32_t fMxcsrIn = (fMxcsr & ~X86_MXCSR_RC_MASK)
7272 | (iRounding << X86_MXCSR_RC_SHIFT)
7273 | (iDaz ? X86_MXCSR_DAZ : 0)
7274 | (iFz ? X86_MXCSR_FZ : 0)
7275 | X86_MXCSR_XCPT_MASK;
7276 uint32_t fMxcsrM = fMxcsrIn;
7277 X86XMMREG ResM;
7278 pfn(&fMxcsrM, &ResM, &Src, bImm);
7279 TestData.fMxcsrIn = fMxcsrIn;
7280 TestData.fMxcsrOut = fMxcsrM;
7281 TestData.bImm = bImm;
7282 TestData.OutVal = ResM;
7283 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7284
7285 fMxcsrIn &= ~X86_MXCSR_XCPT_MASK;
7286 uint32_t fMxcsrU = fMxcsrIn;
7287 X86XMMREG ResU;
7288 pfn(&fMxcsrU, &ResU, &Src, bImm);
7289 TestData.fMxcsrIn = fMxcsrIn;
7290 TestData.fMxcsrOut = fMxcsrU;
7291 TestData.bImm = bImm;
7292 TestData.OutVal = ResU;
7293 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7294
7295 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
7296 if (fXcpt)
7297 {
7298 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | fXcpt;
7299 uint32_t fMxcsr1 = fMxcsrIn;
7300 X86XMMREG Res1;
7301 pfn(&fMxcsr1, &Res1, &Src, bImm);
7302 TestData.fMxcsrIn = fMxcsrIn;
7303 TestData.fMxcsrOut = fMxcsr1;
7304 TestData.bImm = bImm;
7305 TestData.OutVal = Res1;
7306 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7307
7308 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
7309 {
7310 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
7311 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
7312 uint32_t fMxcsr2 = fMxcsrIn;
7313 X86XMMREG Res2;
7314 pfn(&fMxcsr2, &Res2, &Src, bImm);
7315 TestData.fMxcsrIn = fMxcsrIn;
7316 TestData.fMxcsrOut = fMxcsr2;
7317 TestData.bImm = bImm;
7318 TestData.OutVal = Res2;
7319 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7320 }
7321 if (!RT_IS_POWER_OF_TWO(fXcpt))
7322 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
7323 if (fUnmasked & fXcpt)
7324 {
7325 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
7326 uint32_t fMxcsr3 = fMxcsrIn;
7327 X86XMMREG Res3;
7328 pfn(&fMxcsr3, &Res3, &Src, bImm);
7329 TestData.fMxcsrIn = fMxcsrIn;
7330 TestData.fMxcsrOut = fMxcsr3;
7331 TestData.bImm = bImm;
7332 TestData.OutVal = Res3;
7333 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7334 }
7335 }
7336 }
7337 }
7338 rc = RTStrmClose(pStrmOut);
7339 if (RT_FAILURE(rc))
7340 {
7341 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseCompareF2XmmR64Imm8[iFn].pszName, rc);
7342 return RTEXITCODE_FAILURE;
7343 }
7344 }
7345
7346 return RTEXITCODE_SUCCESS;
7347}
7348#endif
7349
7350static void SseCompareF2XmmR64Imm8Test(void)
7351{
7352 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseCompareF2XmmR64Imm8); iFn++)
7353 {
7354 if (!SubTestAndCheckIfEnabled(g_aSseCompareF2XmmR64Imm8[iFn].pszName))
7355 continue;
7356
7357 uint32_t const cTests = *g_aSseCompareF2XmmR64Imm8[iFn].pcTests;
7358 SSE_COMPARE_F2_XMM_IMM8_TEST_T const * const paTests = g_aSseCompareF2XmmR64Imm8[iFn].paTests;
7359 PFNIEMAIMPLMXCSRF2XMMIMM8 pfn = g_aSseCompareF2XmmR64Imm8[iFn].pfn;
7360 uint32_t const cVars = COUNT_VARIATIONS(g_aSseCompareF2XmmR64Imm8[iFn]);
7361 if (!cTests) RTTestSkipped(g_hTest, "no tests");
7362 for (uint32_t iVar = 0; iVar < cVars; iVar++)
7363 {
7364 for (uint32_t iTest = 0; iTest < cTests / sizeof(SSE_COMPARE_F2_XMM_IMM8_TEST_T); iTest++)
7365 {
7366 IEMMEDIAF2XMMSRC Src;
7367 X86XMMREG ValOut;
7368
7369 Src.uSrc1 = paTests[iTest].InVal1;
7370 Src.uSrc2 = paTests[iTest].InVal2;
7371 uint32_t fMxcsr = paTests[iTest].fMxcsrIn;
7372 pfn(&fMxcsr, &ValOut, &Src, paTests[iTest].bImm);
7373 if ( fMxcsr != paTests[iTest].fMxcsrOut
7374 || ValOut.au64[0] != paTests[iTest].OutVal.au64[0]
7375 || ValOut.au64[1] != paTests[iTest].OutVal.au64[1])
7376 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%s'%s in2=%s'%s imm8=%x\n"
7377 "%s -> mxcsr=%#08x %RX64'%RX64\n"
7378 "%s expected %#08x %RX64'%RX64%s%s (%s)\n",
7379 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
7380 FormatR64(&paTests[iTest].InVal1.ar64[0]), FormatR64(&paTests[iTest].InVal1.ar64[1]),
7381 FormatR64(&paTests[iTest].InVal2.ar64[0]), FormatR64(&paTests[iTest].InVal2.ar64[1]),
7382 paTests[iTest].bImm,
7383 iVar ? " " : "", fMxcsr, ValOut.au64[0], ValOut.au64[1],
7384 iVar ? " " : "", paTests[iTest].fMxcsrOut,
7385 paTests[iTest].OutVal.au64[0], paTests[iTest].OutVal.au64[1],
7386 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
7387 ( ValOut.au64[0] != paTests[iTest].OutVal.au64[0]
7388 || ValOut.au64[1] != paTests[iTest].OutVal.au64[1])
7389 ? " - val" : "",
7390 FormatMxcsr(paTests[iTest].fMxcsrIn));
7391 }
7392 }
7393 }
7394}
7395
7396
7397/*
7398 * Convert SSE operations converting signed double-words to single-precision floating point values.
7399 */
7400TYPEDEF_SUBTEST_TYPE(SSE_CONVERT_XMM_T, SSE_CONVERT_XMM_TEST_T, PFNIEMAIMPLFPSSEF2U128);
7401
7402static const SSE_CONVERT_XMM_T g_aSseConvertXmmI32R32[] =
7403{
7404 ENTRY_BIN(cvtdq2ps_u128)
7405};
7406
7407#ifdef TSTIEMAIMPL_WITH_GENERATOR
7408static RTEXITCODE SseConvertXmmI32R32Generate(const char *pszDataFileFmt, uint32_t cTests)
7409{
7410 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
7411
7412 static int32_t const s_aSpecials[] =
7413 {
7414 INT32_MIN,
7415 INT32_MIN / 2,
7416 0,
7417 INT32_MAX / 2,
7418 INT32_MAX,
7419 (int32_t)0x80000000
7420 /** @todo More specials. */
7421 };
7422
7423 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertXmmI32R32); iFn++)
7424 {
7425 PFNIEMAIMPLFPSSEF2U128 const pfn = g_aSseConvertXmmI32R32[iFn].pfnNative ? g_aSseConvertXmmI32R32[iFn].pfnNative : g_aSseConvertXmmI32R32[iFn].pfn;
7426
7427 PRTSTREAM pStrmOut = NULL;
7428 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseConvertXmmI32R32[iFn].pszName);
7429 if (RT_FAILURE(rc))
7430 {
7431 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseConvertXmmI32R32[iFn].pszName, rc);
7432 return RTEXITCODE_FAILURE;
7433 }
7434
7435 X86FXSTATE State;
7436 RT_ZERO(State);
7437 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
7438 {
7439 SSE_CONVERT_XMM_TEST_T TestData; RT_ZERO(TestData);
7440
7441 TestData.InVal.ai32[0] = iTest < cTests ? RandI32Src2(iTest) : s_aSpecials[iTest - cTests];
7442 TestData.InVal.ai32[1] = iTest < cTests ? RandI32Src2(iTest) : s_aSpecials[iTest - cTests];
7443 TestData.InVal.ai32[2] = iTest < cTests ? RandI32Src2(iTest) : s_aSpecials[iTest - cTests];
7444 TestData.InVal.ai32[3] = iTest < cTests ? RandI32Src2(iTest) : s_aSpecials[iTest - cTests];
7445
7446 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
7447 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
7448 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
7449 for (uint8_t iFz = 0; iFz < 2; iFz++)
7450 {
7451 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
7452 | (iRounding << X86_MXCSR_RC_SHIFT)
7453 | (iDaz ? X86_MXCSR_DAZ : 0)
7454 | (iFz ? X86_MXCSR_FZ : 0)
7455 | X86_MXCSR_XCPT_MASK;
7456 IEMSSERESULT ResM; RT_ZERO(ResM);
7457 pfn(&State, &ResM, &ResM.uResult, &TestData.InVal);
7458 TestData.fMxcsrIn = State.MXCSR;
7459 TestData.fMxcsrOut = ResM.MXCSR;
7460 TestData.OutVal = ResM.uResult;
7461 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7462
7463 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
7464 IEMSSERESULT ResU; RT_ZERO(ResU);
7465 pfn(&State, &ResU, &ResU.uResult, &TestData.InVal);
7466 TestData.fMxcsrIn = State.MXCSR;
7467 TestData.fMxcsrOut = ResU.MXCSR;
7468 TestData.OutVal = ResU.uResult;
7469 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7470
7471 uint16_t fXcpt = (ResM.MXCSR | ResU.MXCSR) & X86_MXCSR_XCPT_FLAGS;
7472 if (fXcpt)
7473 {
7474 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
7475 IEMSSERESULT Res1; RT_ZERO(Res1);
7476 pfn(&State, &Res1, &Res1.uResult, &TestData.InVal);
7477 TestData.fMxcsrIn = State.MXCSR;
7478 TestData.fMxcsrOut = Res1.MXCSR;
7479 TestData.OutVal = Res1.uResult;
7480 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7481
7482 if (((Res1.MXCSR & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (Res1.MXCSR & X86_MXCSR_XCPT_FLAGS))
7483 {
7484 fXcpt |= Res1.MXCSR & X86_MXCSR_XCPT_FLAGS;
7485 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
7486 IEMSSERESULT Res2; RT_ZERO(Res2);
7487 pfn(&State, &Res2, &Res2.uResult, &TestData.InVal);
7488 TestData.fMxcsrIn = State.MXCSR;
7489 TestData.fMxcsrOut = Res2.MXCSR;
7490 TestData.OutVal = Res2.uResult;
7491 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7492 }
7493 if (!RT_IS_POWER_OF_TWO(fXcpt))
7494 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
7495 if (fUnmasked & fXcpt)
7496 {
7497 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
7498 IEMSSERESULT Res3; RT_ZERO(Res3);
7499 pfn(&State, &Res3, &Res3.uResult, &TestData.InVal);
7500 TestData.fMxcsrIn = State.MXCSR;
7501 TestData.fMxcsrOut = Res3.MXCSR;
7502 TestData.OutVal = Res3.uResult;
7503 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7504 }
7505 }
7506 }
7507 }
7508 rc = RTStrmClose(pStrmOut);
7509 if (RT_FAILURE(rc))
7510 {
7511 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseConvertXmmI32R32[iFn].pszName, rc);
7512 return RTEXITCODE_FAILURE;
7513 }
7514 }
7515
7516 return RTEXITCODE_SUCCESS;
7517}
7518#endif
7519
7520static void SseConvertXmmI32R32Test(void)
7521{
7522 X86FXSTATE State;
7523 RT_ZERO(State);
7524
7525 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertXmmI32R32); iFn++)
7526 {
7527 if (!SubTestAndCheckIfEnabled(g_aSseConvertXmmI32R32[iFn].pszName))
7528 continue;
7529
7530 uint32_t const cTests = *g_aSseConvertXmmI32R32[iFn].pcTests;
7531 SSE_CONVERT_XMM_TEST_T const * const paTests = g_aSseConvertXmmI32R32[iFn].paTests;
7532 PFNIEMAIMPLFPSSEF2U128 pfn = g_aSseConvertXmmI32R32[iFn].pfn;
7533 uint32_t const cVars = COUNT_VARIATIONS(g_aSseConvertXmmI32R32[iFn]);
7534 if (!cTests) RTTestSkipped(g_hTest, "no tests");
7535 for (uint32_t iVar = 0; iVar < cVars; iVar++)
7536 {
7537 for (uint32_t iTest = 0; iTest < cTests / sizeof(*paTests); iTest++)
7538 {
7539 IEMSSERESULT Res; RT_ZERO(Res);
7540
7541 State.MXCSR = paTests[iTest].fMxcsrIn;
7542 pfn(&State, &Res, &Res.uResult, &paTests[iTest].InVal);
7543 if ( Res.MXCSR != paTests[iTest].fMxcsrOut
7544 || !RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[0], &paTests[iTest].OutVal.ar32[0])
7545 || !RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[1], &paTests[iTest].OutVal.ar32[1])
7546 || !RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[2], &paTests[iTest].OutVal.ar32[2])
7547 || !RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[3], &paTests[iTest].OutVal.ar32[3]))
7548 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%RI32'%RI32'%RI32'%RI32 \n"
7549 "%s -> mxcsr=%#08x %s'%s'%s'%s\n"
7550 "%s expected %#08x %s'%s'%s'%s%s%s (%s)\n",
7551 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
7552 paTests[iTest].InVal.ai32[0], paTests[iTest].InVal.ai32[1],
7553 paTests[iTest].InVal.ai32[2], paTests[iTest].InVal.ai32[3],
7554 iVar ? " " : "", Res.MXCSR,
7555 FormatR32(&Res.uResult.ar32[0]), FormatR32(&Res.uResult.ar32[1]),
7556 FormatR32(&Res.uResult.ar32[2]), FormatR32(&Res.uResult.ar32[3]),
7557 iVar ? " " : "", paTests[iTest].fMxcsrOut,
7558 FormatR32(&paTests[iTest].OutVal.ar32[0]), FormatR32(&paTests[iTest].OutVal.ar32[1]),
7559 FormatR32(&paTests[iTest].OutVal.ar32[2]), FormatR32(&paTests[iTest].OutVal.ar32[3]),
7560 MxcsrDiff(Res.MXCSR, paTests[iTest].fMxcsrOut),
7561 ( !RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[0], &paTests[iTest].OutVal.ar32[0])
7562 || !RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[1], &paTests[iTest].OutVal.ar32[1])
7563 || !RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[2], &paTests[iTest].OutVal.ar32[2])
7564 || !RTFLOAT32U_ARE_IDENTICAL(&Res.uResult.ar32[3], &paTests[iTest].OutVal.ar32[3]))
7565 ? " - val" : "",
7566 FormatMxcsr(paTests[iTest].fMxcsrIn));
7567 }
7568 }
7569 }
7570}
7571
7572
7573/*
7574 * Convert SSE operations converting signed double-words to single-precision floating point values.
7575 */
7576static const SSE_CONVERT_XMM_T g_aSseConvertXmmR32I32[] =
7577{
7578 ENTRY_BIN(cvtps2dq_u128),
7579 ENTRY_BIN(cvttps2dq_u128)
7580};
7581
7582#ifdef TSTIEMAIMPL_WITH_GENERATOR
7583static RTEXITCODE SseConvertXmmR32I32Generate(const char *pszDataFileFmt, uint32_t cTests)
7584{
7585 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
7586
7587 static struct { RTFLOAT32U aVal1[4]; } const s_aSpecials[] =
7588 {
7589 { { RTFLOAT32U_INIT_ZERO(0), RTFLOAT32U_INIT_ZERO(0), RTFLOAT32U_INIT_ZERO(0), RTFLOAT32U_INIT_ZERO(0) } },
7590 { { RTFLOAT32U_INIT_ZERO(1), RTFLOAT32U_INIT_ZERO(1), RTFLOAT32U_INIT_ZERO(1), RTFLOAT32U_INIT_ZERO(1) } },
7591 { { RTFLOAT32U_INIT_INF(0), RTFLOAT32U_INIT_INF(0), RTFLOAT32U_INIT_INF(0), RTFLOAT32U_INIT_INF(0) } },
7592 { { RTFLOAT32U_INIT_INF(1), RTFLOAT32U_INIT_INF(1), RTFLOAT32U_INIT_INF(1), RTFLOAT32U_INIT_INF(1) } }
7593 /** @todo More specials. */
7594 };
7595
7596 X86FXSTATE State;
7597 RT_ZERO(State);
7598 uint32_t cMinNormalPairs = (cTests - 144) / 4;
7599 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertXmmR32I32); iFn++)
7600 {
7601 PFNIEMAIMPLFPSSEF2U128 const pfn = g_aSseConvertXmmR32I32[iFn].pfnNative ? g_aSseConvertXmmR32I32[iFn].pfnNative : g_aSseConvertXmmR32I32[iFn].pfn;
7602
7603 PRTSTREAM pStrmOut = NULL;
7604 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseConvertXmmR32I32[iFn].pszName);
7605 if (RT_FAILURE(rc))
7606 {
7607 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseConvertXmmR32I32[iFn].pszName, rc);
7608 return RTEXITCODE_FAILURE;
7609 }
7610
7611 uint32_t cNormalInputPairs = 0;
7612 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
7613 {
7614 SSE_CONVERT_XMM_TEST_T TestData; RT_ZERO(TestData);
7615
7616 TestData.InVal.ar32[0] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].aVal1[0];
7617 TestData.InVal.ar32[1] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].aVal1[1];
7618 TestData.InVal.ar32[2] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].aVal1[2];
7619 TestData.InVal.ar32[3] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].aVal1[3];
7620
7621 if ( RTFLOAT32U_IS_NORMAL(&TestData.InVal.ar32[0])
7622 && RTFLOAT32U_IS_NORMAL(&TestData.InVal.ar32[1])
7623 && RTFLOAT32U_IS_NORMAL(&TestData.InVal.ar32[2])
7624 && RTFLOAT32U_IS_NORMAL(&TestData.InVal.ar32[3]))
7625 cNormalInputPairs++;
7626 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
7627 {
7628 iTest -= 1;
7629 continue;
7630 }
7631
7632 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
7633 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
7634 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
7635 for (uint8_t iFz = 0; iFz < 2; iFz++)
7636 {
7637 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
7638 | (iRounding << X86_MXCSR_RC_SHIFT)
7639 | (iDaz ? X86_MXCSR_DAZ : 0)
7640 | (iFz ? X86_MXCSR_FZ : 0)
7641 | X86_MXCSR_XCPT_MASK;
7642 IEMSSERESULT ResM; RT_ZERO(ResM);
7643 pfn(&State, &ResM, &ResM.uResult, &TestData.InVal);
7644 TestData.fMxcsrIn = State.MXCSR;
7645 TestData.fMxcsrOut = ResM.MXCSR;
7646 TestData.OutVal = ResM.uResult;
7647 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7648
7649 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
7650 IEMSSERESULT ResU; RT_ZERO(ResU);
7651 pfn(&State, &ResU, &ResU.uResult, &TestData.InVal);
7652 TestData.fMxcsrIn = State.MXCSR;
7653 TestData.fMxcsrOut = ResU.MXCSR;
7654 TestData.OutVal = ResU.uResult;
7655 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7656
7657 uint16_t fXcpt = (ResM.MXCSR | ResU.MXCSR) & X86_MXCSR_XCPT_FLAGS;
7658 if (fXcpt)
7659 {
7660 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
7661 IEMSSERESULT Res1; RT_ZERO(Res1);
7662 pfn(&State, &Res1, &Res1.uResult, &TestData.InVal);
7663 TestData.fMxcsrIn = State.MXCSR;
7664 TestData.fMxcsrOut = Res1.MXCSR;
7665 TestData.OutVal = Res1.uResult;
7666 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7667
7668 if (((Res1.MXCSR & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (Res1.MXCSR & X86_MXCSR_XCPT_FLAGS))
7669 {
7670 fXcpt |= Res1.MXCSR & X86_MXCSR_XCPT_FLAGS;
7671 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
7672 IEMSSERESULT Res2; RT_ZERO(Res2);
7673 pfn(&State, &Res2, &Res2.uResult, &TestData.InVal);
7674 TestData.fMxcsrIn = State.MXCSR;
7675 TestData.fMxcsrOut = Res2.MXCSR;
7676 TestData.OutVal = Res2.uResult;
7677 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7678 }
7679 if (!RT_IS_POWER_OF_TWO(fXcpt))
7680 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
7681 if (fUnmasked & fXcpt)
7682 {
7683 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
7684 IEMSSERESULT Res3; RT_ZERO(Res3);
7685 pfn(&State, &Res3, &Res3.uResult, &TestData.InVal);
7686 TestData.fMxcsrIn = State.MXCSR;
7687 TestData.fMxcsrOut = Res3.MXCSR;
7688 TestData.OutVal = Res3.uResult;
7689 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7690 }
7691 }
7692 }
7693 }
7694 rc = RTStrmClose(pStrmOut);
7695 if (RT_FAILURE(rc))
7696 {
7697 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseConvertXmmR32I32[iFn].pszName, rc);
7698 return RTEXITCODE_FAILURE;
7699 }
7700 }
7701
7702 return RTEXITCODE_SUCCESS;
7703}
7704#endif
7705
7706static void SseConvertXmmR32I32Test(void)
7707{
7708 X86FXSTATE State;
7709 RT_ZERO(State);
7710
7711 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertXmmR32I32); iFn++)
7712 {
7713 if (!SubTestAndCheckIfEnabled(g_aSseConvertXmmR32I32[iFn].pszName))
7714 continue;
7715
7716 uint32_t const cTests = *g_aSseConvertXmmR32I32[iFn].pcTests;
7717 SSE_CONVERT_XMM_TEST_T const * const paTests = g_aSseConvertXmmR32I32[iFn].paTests;
7718 PFNIEMAIMPLFPSSEF2U128 pfn = g_aSseConvertXmmR32I32[iFn].pfn;
7719 uint32_t const cVars = COUNT_VARIATIONS(g_aSseConvertXmmR32I32[iFn]);
7720 if (!cTests) RTTestSkipped(g_hTest, "no tests");
7721 for (uint32_t iVar = 0; iVar < cVars; iVar++)
7722 {
7723 for (uint32_t iTest = 0; iTest < cTests / sizeof(*paTests); iTest++)
7724 {
7725 IEMSSERESULT Res; RT_ZERO(Res);
7726
7727 State.MXCSR = paTests[iTest].fMxcsrIn;
7728 pfn(&State, &Res, &Res.uResult, &paTests[iTest].InVal);
7729 if ( Res.MXCSR != paTests[iTest].fMxcsrOut
7730 || Res.uResult.ai32[0] != paTests[iTest].OutVal.ai32[0]
7731 || Res.uResult.ai32[1] != paTests[iTest].OutVal.ai32[1]
7732 || Res.uResult.ai32[2] != paTests[iTest].OutVal.ai32[2]
7733 || Res.uResult.ai32[3] != paTests[iTest].OutVal.ai32[3])
7734 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%s'%s'%s'%s \n"
7735 "%s -> mxcsr=%#08x %RI32'%RI32'%RI32'%RI32\n"
7736 "%s expected %#08x %RI32'%RI32'%RI32'%RI32%s%s (%s)\n",
7737 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
7738 FormatR32(&paTests[iTest].InVal.ar32[0]), FormatR32(&paTests[iTest].InVal.ar32[1]),
7739 FormatR32(&paTests[iTest].InVal.ar32[2]), FormatR32(&paTests[iTest].InVal.ar32[3]),
7740 iVar ? " " : "", Res.MXCSR,
7741 Res.uResult.ai32[0], Res.uResult.ai32[1],
7742 Res.uResult.ai32[2], Res.uResult.ai32[3],
7743 iVar ? " " : "", paTests[iTest].fMxcsrOut,
7744 paTests[iTest].OutVal.ai32[0], paTests[iTest].OutVal.ai32[1],
7745 paTests[iTest].OutVal.ai32[2], paTests[iTest].OutVal.ai32[3],
7746 MxcsrDiff(Res.MXCSR, paTests[iTest].fMxcsrOut),
7747 ( Res.uResult.ai32[0] != paTests[iTest].OutVal.ai32[0]
7748 || Res.uResult.ai32[1] != paTests[iTest].OutVal.ai32[1]
7749 || Res.uResult.ai32[2] != paTests[iTest].OutVal.ai32[2]
7750 || Res.uResult.ai32[3] != paTests[iTest].OutVal.ai32[3])
7751 ? " - val" : "",
7752 FormatMxcsr(paTests[iTest].fMxcsrIn));
7753 }
7754 }
7755 }
7756}
7757
7758
7759/*
7760 * Convert SSE operations converting signed double-words to double-precision floating point values.
7761 */
7762static const SSE_CONVERT_XMM_T g_aSseConvertXmmI32R64[] =
7763{
7764 ENTRY_BIN(cvtdq2pd_u128)
7765};
7766
7767#ifdef TSTIEMAIMPL_WITH_GENERATOR
7768static RTEXITCODE SseConvertXmmI32R64Generate(const char *pszDataFileFmt, uint32_t cTests)
7769{
7770 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
7771
7772 static int32_t const s_aSpecials[] =
7773 {
7774 INT32_MIN,
7775 INT32_MIN / 2,
7776 0,
7777 INT32_MAX / 2,
7778 INT32_MAX,
7779 (int32_t)0x80000000
7780 /** @todo More specials. */
7781 };
7782
7783 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertXmmI32R64); iFn++)
7784 {
7785 PFNIEMAIMPLFPSSEF2U128 const pfn = g_aSseConvertXmmI32R64[iFn].pfnNative ? g_aSseConvertXmmI32R64[iFn].pfnNative : g_aSseConvertXmmI32R64[iFn].pfn;
7786
7787 PRTSTREAM pStrmOut = NULL;
7788 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseConvertXmmI32R64[iFn].pszName);
7789 if (RT_FAILURE(rc))
7790 {
7791 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseConvertXmmI32R64[iFn].pszName, rc);
7792 return RTEXITCODE_FAILURE;
7793 }
7794
7795 X86FXSTATE State;
7796 RT_ZERO(State);
7797 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
7798 {
7799 SSE_CONVERT_XMM_TEST_T TestData; RT_ZERO(TestData);
7800
7801 TestData.InVal.ai32[0] = iTest < cTests ? RandI32Src2(iTest) : s_aSpecials[iTest - cTests];
7802 TestData.InVal.ai32[1] = iTest < cTests ? RandI32Src2(iTest) : s_aSpecials[iTest - cTests];
7803 TestData.InVal.ai32[2] = iTest < cTests ? RandI32Src2(iTest) : s_aSpecials[iTest - cTests];
7804 TestData.InVal.ai32[3] = iTest < cTests ? RandI32Src2(iTest) : s_aSpecials[iTest - cTests];
7805
7806 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
7807 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
7808 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
7809 for (uint8_t iFz = 0; iFz < 2; iFz++)
7810 {
7811 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
7812 | (iRounding << X86_MXCSR_RC_SHIFT)
7813 | (iDaz ? X86_MXCSR_DAZ : 0)
7814 | (iFz ? X86_MXCSR_FZ : 0)
7815 | X86_MXCSR_XCPT_MASK;
7816 IEMSSERESULT ResM; RT_ZERO(ResM);
7817 pfn(&State, &ResM, &ResM.uResult, &TestData.InVal);
7818 TestData.fMxcsrIn = State.MXCSR;
7819 TestData.fMxcsrOut = ResM.MXCSR;
7820 TestData.OutVal = ResM.uResult;
7821 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7822
7823 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
7824 IEMSSERESULT ResU; RT_ZERO(ResU);
7825 pfn(&State, &ResU, &ResU.uResult, &TestData.InVal);
7826 TestData.fMxcsrIn = State.MXCSR;
7827 TestData.fMxcsrOut = ResU.MXCSR;
7828 TestData.OutVal = ResU.uResult;
7829 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7830
7831 uint16_t fXcpt = (ResM.MXCSR | ResU.MXCSR) & X86_MXCSR_XCPT_FLAGS;
7832 if (fXcpt)
7833 {
7834 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
7835 IEMSSERESULT Res1; RT_ZERO(Res1);
7836 pfn(&State, &Res1, &Res1.uResult, &TestData.InVal);
7837 TestData.fMxcsrIn = State.MXCSR;
7838 TestData.fMxcsrOut = Res1.MXCSR;
7839 TestData.OutVal = Res1.uResult;
7840 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7841
7842 if (((Res1.MXCSR & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (Res1.MXCSR & X86_MXCSR_XCPT_FLAGS))
7843 {
7844 fXcpt |= Res1.MXCSR & X86_MXCSR_XCPT_FLAGS;
7845 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
7846 IEMSSERESULT Res2; RT_ZERO(Res2);
7847 pfn(&State, &Res2, &Res2.uResult, &TestData.InVal);
7848 TestData.fMxcsrIn = State.MXCSR;
7849 TestData.fMxcsrOut = Res2.MXCSR;
7850 TestData.OutVal = Res2.uResult;
7851 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7852 }
7853 if (!RT_IS_POWER_OF_TWO(fXcpt))
7854 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
7855 if (fUnmasked & fXcpt)
7856 {
7857 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
7858 IEMSSERESULT Res3; RT_ZERO(Res3);
7859 pfn(&State, &Res3, &Res3.uResult, &TestData.InVal);
7860 TestData.fMxcsrIn = State.MXCSR;
7861 TestData.fMxcsrOut = Res3.MXCSR;
7862 TestData.OutVal = Res3.uResult;
7863 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7864 }
7865 }
7866 }
7867 }
7868 rc = RTStrmClose(pStrmOut);
7869 if (RT_FAILURE(rc))
7870 {
7871 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseConvertXmmI32R64[iFn].pszName, rc);
7872 return RTEXITCODE_FAILURE;
7873 }
7874 }
7875
7876 return RTEXITCODE_SUCCESS;
7877}
7878#endif
7879
7880static void SseConvertXmmI32R64Test(void)
7881{
7882 X86FXSTATE State;
7883 RT_ZERO(State);
7884
7885 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertXmmI32R64); iFn++)
7886 {
7887 if (!SubTestAndCheckIfEnabled(g_aSseConvertXmmI32R64[iFn].pszName))
7888 continue;
7889
7890 uint32_t const cTests = *g_aSseConvertXmmI32R64[iFn].pcTests;
7891 SSE_CONVERT_XMM_TEST_T const * const paTests = g_aSseConvertXmmI32R64[iFn].paTests;
7892 PFNIEMAIMPLFPSSEF2U128 pfn = g_aSseConvertXmmI32R64[iFn].pfn;
7893 uint32_t const cVars = COUNT_VARIATIONS(g_aSseConvertXmmI32R64[iFn]);
7894 if (!cTests) RTTestSkipped(g_hTest, "no tests");
7895 for (uint32_t iVar = 0; iVar < cVars; iVar++)
7896 {
7897 for (uint32_t iTest = 0; iTest < cTests / sizeof(*paTests); iTest++)
7898 {
7899 IEMSSERESULT Res; RT_ZERO(Res);
7900
7901 State.MXCSR = paTests[iTest].fMxcsrIn;
7902 pfn(&State, &Res, &Res.uResult, &paTests[iTest].InVal);
7903 if ( Res.MXCSR != paTests[iTest].fMxcsrOut
7904 || !RTFLOAT64U_ARE_IDENTICAL(&Res.uResult.ar64[0], &paTests[iTest].OutVal.ar64[0])
7905 || !RTFLOAT64U_ARE_IDENTICAL(&Res.uResult.ar64[1], &paTests[iTest].OutVal.ar64[1]))
7906 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%RI32'%RI32'%RI32'%RI32 \n"
7907 "%s -> mxcsr=%#08x %s'%s\n"
7908 "%s expected %#08x %s'%s%s%s (%s)\n",
7909 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
7910 paTests[iTest].InVal.ai32[0], paTests[iTest].InVal.ai32[1],
7911 paTests[iTest].InVal.ai32[2], paTests[iTest].InVal.ai32[3],
7912 iVar ? " " : "", Res.MXCSR,
7913 FormatR64(&Res.uResult.ar64[0]), FormatR64(&Res.uResult.ar64[1]),
7914 iVar ? " " : "", paTests[iTest].fMxcsrOut,
7915 FormatR64(&paTests[iTest].OutVal.ar64[0]), FormatR64(&paTests[iTest].OutVal.ar64[1]),
7916 MxcsrDiff(Res.MXCSR, paTests[iTest].fMxcsrOut),
7917 ( !RTFLOAT64U_ARE_IDENTICAL(&Res.uResult.ar64[0], &paTests[iTest].OutVal.ar64[0])
7918 || !RTFLOAT64U_ARE_IDENTICAL(&Res.uResult.ar64[1], &paTests[iTest].OutVal.ar64[1]))
7919 ? " - val" : "",
7920 FormatMxcsr(paTests[iTest].fMxcsrIn));
7921 }
7922 }
7923 }
7924}
7925
7926
7927/*
7928 * Convert SSE operations converting signed double-words to double-precision floating point values.
7929 */
7930static const SSE_CONVERT_XMM_T g_aSseConvertXmmR64I32[] =
7931{
7932 ENTRY_BIN(cvtpd2dq_u128),
7933 ENTRY_BIN(cvttpd2dq_u128)
7934};
7935
7936#ifdef TSTIEMAIMPL_WITH_GENERATOR
7937static RTEXITCODE SseConvertXmmR64I32Generate(const char *pszDataFileFmt, uint32_t cTests)
7938{
7939 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
7940
7941 static struct { RTFLOAT64U aVal1[2]; } const s_aSpecials[] =
7942 {
7943 { { RTFLOAT64U_INIT_ZERO(0), RTFLOAT64U_INIT_ZERO(0) } },
7944 { { RTFLOAT64U_INIT_ZERO(1), RTFLOAT64U_INIT_ZERO(1) } },
7945 { { RTFLOAT64U_INIT_INF(0), RTFLOAT64U_INIT_INF(0) } },
7946 { { RTFLOAT64U_INIT_INF(1), RTFLOAT64U_INIT_INF(1) } }
7947 /** @todo More specials. */
7948 };
7949
7950 X86FXSTATE State;
7951 RT_ZERO(State);
7952 uint32_t cMinNormalPairs = (cTests - 144) / 4;
7953 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertXmmR64I32); iFn++)
7954 {
7955 PFNIEMAIMPLFPSSEF2U128 const pfn = g_aSseConvertXmmR64I32[iFn].pfnNative ? g_aSseConvertXmmR64I32[iFn].pfnNative : g_aSseConvertXmmR64I32[iFn].pfn;
7956
7957 PRTSTREAM pStrmOut = NULL;
7958 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseConvertXmmR64I32[iFn].pszName);
7959 if (RT_FAILURE(rc))
7960 {
7961 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseConvertXmmR64I32[iFn].pszName, rc);
7962 return RTEXITCODE_FAILURE;
7963 }
7964
7965 uint32_t cNormalInputPairs = 0;
7966 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
7967 {
7968 SSE_CONVERT_XMM_TEST_T TestData; RT_ZERO(TestData);
7969
7970 TestData.InVal.ar64[0] = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].aVal1[0];
7971 TestData.InVal.ar64[1] = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].aVal1[1];
7972
7973 if ( RTFLOAT64U_IS_NORMAL(&TestData.InVal.ar64[0])
7974 && RTFLOAT64U_IS_NORMAL(&TestData.InVal.ar64[1]))
7975 cNormalInputPairs++;
7976 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
7977 {
7978 iTest -= 1;
7979 continue;
7980 }
7981
7982 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
7983 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
7984 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
7985 for (uint8_t iFz = 0; iFz < 2; iFz++)
7986 {
7987 State.MXCSR = (fMxcsr & ~X86_MXCSR_RC_MASK)
7988 | (iRounding << X86_MXCSR_RC_SHIFT)
7989 | (iDaz ? X86_MXCSR_DAZ : 0)
7990 | (iFz ? X86_MXCSR_FZ : 0)
7991 | X86_MXCSR_XCPT_MASK;
7992 IEMSSERESULT ResM; RT_ZERO(ResM);
7993 pfn(&State, &ResM, &ResM.uResult, &TestData.InVal);
7994 TestData.fMxcsrIn = State.MXCSR;
7995 TestData.fMxcsrOut = ResM.MXCSR;
7996 TestData.OutVal = ResM.uResult;
7997 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
7998
7999 State.MXCSR = State.MXCSR & ~X86_MXCSR_XCPT_MASK;
8000 IEMSSERESULT ResU; RT_ZERO(ResU);
8001 pfn(&State, &ResU, &ResU.uResult, &TestData.InVal);
8002 TestData.fMxcsrIn = State.MXCSR;
8003 TestData.fMxcsrOut = ResU.MXCSR;
8004 TestData.OutVal = ResU.uResult;
8005 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8006
8007 uint16_t fXcpt = (ResM.MXCSR | ResU.MXCSR) & X86_MXCSR_XCPT_FLAGS;
8008 if (fXcpt)
8009 {
8010 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | fXcpt;
8011 IEMSSERESULT Res1; RT_ZERO(Res1);
8012 pfn(&State, &Res1, &Res1.uResult, &TestData.InVal);
8013 TestData.fMxcsrIn = State.MXCSR;
8014 TestData.fMxcsrOut = Res1.MXCSR;
8015 TestData.OutVal = Res1.uResult;
8016 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8017
8018 if (((Res1.MXCSR & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (Res1.MXCSR & X86_MXCSR_XCPT_FLAGS))
8019 {
8020 fXcpt |= Res1.MXCSR & X86_MXCSR_XCPT_FLAGS;
8021 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
8022 IEMSSERESULT Res2; RT_ZERO(Res2);
8023 pfn(&State, &Res2, &Res2.uResult, &TestData.InVal);
8024 TestData.fMxcsrIn = State.MXCSR;
8025 TestData.fMxcsrOut = Res2.MXCSR;
8026 TestData.OutVal = Res2.uResult;
8027 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8028 }
8029 if (!RT_IS_POWER_OF_TWO(fXcpt))
8030 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
8031 if (fUnmasked & fXcpt)
8032 {
8033 State.MXCSR = (State.MXCSR & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
8034 IEMSSERESULT Res3; RT_ZERO(Res3);
8035 pfn(&State, &Res3, &Res3.uResult, &TestData.InVal);
8036 TestData.fMxcsrIn = State.MXCSR;
8037 TestData.fMxcsrOut = Res3.MXCSR;
8038 TestData.OutVal = Res3.uResult;
8039 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8040 }
8041 }
8042 }
8043 }
8044 rc = RTStrmClose(pStrmOut);
8045 if (RT_FAILURE(rc))
8046 {
8047 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseConvertXmmR64I32[iFn].pszName, rc);
8048 return RTEXITCODE_FAILURE;
8049 }
8050 }
8051
8052 return RTEXITCODE_SUCCESS;
8053}
8054#endif
8055
8056static void SseConvertXmmR64I32Test(void)
8057{
8058 X86FXSTATE State;
8059 RT_ZERO(State);
8060
8061 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertXmmR64I32); iFn++)
8062 {
8063 if (!SubTestAndCheckIfEnabled(g_aSseConvertXmmR64I32[iFn].pszName))
8064 continue;
8065
8066 uint32_t const cTests = *g_aSseConvertXmmR64I32[iFn].pcTests;
8067 SSE_CONVERT_XMM_TEST_T const * const paTests = g_aSseConvertXmmR64I32[iFn].paTests;
8068 PFNIEMAIMPLFPSSEF2U128 pfn = g_aSseConvertXmmR64I32[iFn].pfn;
8069 uint32_t const cVars = COUNT_VARIATIONS(g_aSseConvertXmmR64I32[iFn]);
8070 if (!cTests) RTTestSkipped(g_hTest, "no tests");
8071 for (uint32_t iVar = 0; iVar < cVars; iVar++)
8072 {
8073 for (uint32_t iTest = 0; iTest < cTests / sizeof(*paTests); iTest++)
8074 {
8075 IEMSSERESULT Res; RT_ZERO(Res);
8076
8077 State.MXCSR = paTests[iTest].fMxcsrIn;
8078 pfn(&State, &Res, &Res.uResult, &paTests[iTest].InVal);
8079 if ( Res.MXCSR != paTests[iTest].fMxcsrOut
8080 || Res.uResult.ai32[0] != paTests[iTest].OutVal.ai32[0]
8081 || Res.uResult.ai32[1] != paTests[iTest].OutVal.ai32[1]
8082 || Res.uResult.ai32[2] != paTests[iTest].OutVal.ai32[2]
8083 || Res.uResult.ai32[3] != paTests[iTest].OutVal.ai32[3])
8084 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%s'%s \n"
8085 "%s -> mxcsr=%#08x %RI32'%RI32'%RI32'%RI32\n"
8086 "%s expected %#08x %RI32'%RI32'%RI32'%RI32%s%s (%s)\n",
8087 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
8088 FormatR64(&paTests[iTest].InVal.ar64[0]), FormatR64(&paTests[iTest].InVal.ar64[1]),
8089 iVar ? " " : "", Res.MXCSR,
8090 Res.uResult.ai32[0], Res.uResult.ai32[1],
8091 Res.uResult.ai32[2], Res.uResult.ai32[3],
8092 iVar ? " " : "", paTests[iTest].fMxcsrOut,
8093 paTests[iTest].OutVal.ai32[0], paTests[iTest].OutVal.ai32[1],
8094 paTests[iTest].OutVal.ai32[2], paTests[iTest].OutVal.ai32[3],
8095 MxcsrDiff(Res.MXCSR, paTests[iTest].fMxcsrOut),
8096 ( Res.uResult.ai32[0] != paTests[iTest].OutVal.ai32[0]
8097 || Res.uResult.ai32[1] != paTests[iTest].OutVal.ai32[1]
8098 || Res.uResult.ai32[2] != paTests[iTest].OutVal.ai32[2]
8099 || Res.uResult.ai32[3] != paTests[iTest].OutVal.ai32[3])
8100 ? " - val" : "",
8101 FormatMxcsr(paTests[iTest].fMxcsrIn));
8102 }
8103 }
8104 }
8105}
8106
8107
8108/*
8109 * Convert SSE operations converting double-precision floating point values to signed double-word values.
8110 */
8111TYPEDEF_SUBTEST_TYPE(SSE_CONVERT_MM_XMM_T, SSE_CONVERT_MM_XMM_TEST_T, PFNIEMAIMPLMXCSRU64U128);
8112
8113static const SSE_CONVERT_MM_XMM_T g_aSseConvertMmXmm[] =
8114{
8115 ENTRY_BIN(cvtpd2pi_u128),
8116 ENTRY_BIN(cvttpd2pi_u128)
8117};
8118
8119#ifdef TSTIEMAIMPL_WITH_GENERATOR
8120static RTEXITCODE SseConvertMmXmmGenerate(const char *pszDataFileFmt, uint32_t cTests)
8121{
8122 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
8123
8124 static struct { RTFLOAT64U aVal1[2]; } const s_aSpecials[] =
8125 {
8126 { { RTFLOAT64U_INIT_ZERO(0), RTFLOAT64U_INIT_ZERO(0) } },
8127 { { RTFLOAT64U_INIT_ZERO(1), RTFLOAT64U_INIT_ZERO(1) } },
8128 { { RTFLOAT64U_INIT_INF(0), RTFLOAT64U_INIT_INF(0) } },
8129 { { RTFLOAT64U_INIT_INF(1), RTFLOAT64U_INIT_INF(1) } }
8130 /** @todo More specials. */
8131 };
8132
8133 uint32_t cMinNormalPairs = (cTests - 144) / 4;
8134 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertMmXmm); iFn++)
8135 {
8136 PFNIEMAIMPLMXCSRU64U128 const pfn = g_aSseConvertMmXmm[iFn].pfnNative ? g_aSseConvertMmXmm[iFn].pfnNative : g_aSseConvertMmXmm[iFn].pfn;
8137
8138 PRTSTREAM pStrmOut = NULL;
8139 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseConvertMmXmm[iFn].pszName);
8140 if (RT_FAILURE(rc))
8141 {
8142 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseConvertMmXmm[iFn].pszName, rc);
8143 return RTEXITCODE_FAILURE;
8144 }
8145
8146 uint32_t cNormalInputPairs = 0;
8147 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
8148 {
8149 SSE_CONVERT_MM_XMM_TEST_T TestData; RT_ZERO(TestData);
8150
8151 TestData.InVal.ar64[0] = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].aVal1[0];
8152 TestData.InVal.ar64[1] = iTest < cTests ? RandR64Src(iTest) : s_aSpecials[iTest - cTests].aVal1[1];
8153
8154 if ( RTFLOAT64U_IS_NORMAL(&TestData.InVal.ar64[0])
8155 && RTFLOAT64U_IS_NORMAL(&TestData.InVal.ar64[1]))
8156 cNormalInputPairs++;
8157 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
8158 {
8159 iTest -= 1;
8160 continue;
8161 }
8162
8163 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
8164 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
8165 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
8166 for (uint8_t iFz = 0; iFz < 2; iFz++)
8167 {
8168 uint32_t fMxcsrIn = (fMxcsr & ~X86_MXCSR_RC_MASK)
8169 | (iRounding << X86_MXCSR_RC_SHIFT)
8170 | (iDaz ? X86_MXCSR_DAZ : 0)
8171 | (iFz ? X86_MXCSR_FZ : 0)
8172 | X86_MXCSR_XCPT_MASK;
8173 uint32_t fMxcsrM = fMxcsrIn;
8174 uint64_t u64ResM;
8175 pfn(&fMxcsrM, &u64ResM, &TestData.InVal);
8176 TestData.fMxcsrIn = fMxcsrIn;
8177 TestData.fMxcsrOut = fMxcsrM;
8178 TestData.OutVal.u = u64ResM;
8179 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8180
8181 fMxcsrIn &= ~X86_MXCSR_XCPT_MASK;
8182 uint32_t fMxcsrU = fMxcsrIn;
8183 uint64_t u64ResU;
8184 pfn(&fMxcsrU, &u64ResU, &TestData.InVal);
8185 TestData.fMxcsrIn = fMxcsrIn;
8186 TestData.fMxcsrOut = fMxcsrU;
8187 TestData.OutVal.u = u64ResU;
8188 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8189
8190 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
8191 if (fXcpt)
8192 {
8193 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | fXcpt;
8194 uint32_t fMxcsr1 = fMxcsrIn;
8195 uint64_t u64Res1;
8196 pfn(&fMxcsr1, &u64Res1, &TestData.InVal);
8197 TestData.fMxcsrIn = fMxcsrIn;
8198 TestData.fMxcsrOut = fMxcsr1;
8199 TestData.OutVal.u = u64Res1;
8200 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8201
8202 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
8203 {
8204 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
8205 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
8206 uint32_t fMxcsr2 = fMxcsrIn;
8207 uint64_t u64Res2;
8208 pfn(&fMxcsr2, &u64Res2, &TestData.InVal);
8209 TestData.fMxcsrIn = fMxcsrIn;
8210 TestData.fMxcsrOut = fMxcsr2;
8211 TestData.OutVal.u = u64Res2;
8212 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8213 }
8214 if (!RT_IS_POWER_OF_TWO(fXcpt))
8215 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
8216 if (fUnmasked & fXcpt)
8217 {
8218 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
8219 uint32_t fMxcsr3 = fMxcsrIn;
8220 uint64_t u64Res3;
8221 pfn(&fMxcsr3, &u64Res3, &TestData.InVal);
8222 TestData.fMxcsrIn = fMxcsrIn;
8223 TestData.fMxcsrOut = fMxcsr3;
8224 TestData.OutVal.u = u64Res3;
8225 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8226 }
8227 }
8228 }
8229 }
8230 rc = RTStrmClose(pStrmOut);
8231 if (RT_FAILURE(rc))
8232 {
8233 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseConvertMmXmm[iFn].pszName, rc);
8234 return RTEXITCODE_FAILURE;
8235 }
8236 }
8237
8238 return RTEXITCODE_SUCCESS;
8239}
8240#endif
8241
8242static void SseConvertMmXmmTest(void)
8243{
8244 X86FXSTATE State;
8245 RT_ZERO(State);
8246
8247 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertMmXmm); iFn++)
8248 {
8249 if (!SubTestAndCheckIfEnabled(g_aSseConvertMmXmm[iFn].pszName))
8250 continue;
8251
8252 uint32_t const cTests = *g_aSseConvertMmXmm[iFn].pcTests;
8253 SSE_CONVERT_MM_XMM_TEST_T const * const paTests = g_aSseConvertMmXmm[iFn].paTests;
8254 PFNIEMAIMPLMXCSRU64U128 pfn = g_aSseConvertMmXmm[iFn].pfn;
8255 uint32_t const cVars = COUNT_VARIATIONS(g_aSseConvertMmXmm[iFn]);
8256 if (!cTests) RTTestSkipped(g_hTest, "no tests");
8257 for (uint32_t iVar = 0; iVar < cVars; iVar++)
8258 {
8259 for (uint32_t iTest = 0; iTest < cTests / sizeof(*paTests); iTest++)
8260 {
8261 RTUINT64U ValOut;
8262 uint32_t fMxcsr = paTests[iTest].fMxcsrIn;
8263 pfn(&fMxcsr, &ValOut.u, &paTests[iTest].InVal);
8264 if ( fMxcsr != paTests[iTest].fMxcsrOut
8265 || ValOut.ai32[0] != paTests[iTest].OutVal.ai32[0]
8266 || ValOut.ai32[1] != paTests[iTest].OutVal.ai32[1])
8267 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%s'%s\n"
8268 "%s -> mxcsr=%#08x %RI32'%RI32\n"
8269 "%s expected %#08x %RI32'%RI32%s%s (%s)\n",
8270 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
8271 FormatR64(&paTests[iTest].InVal.ar64[0]), FormatR64(&paTests[iTest].InVal.ar64[1]),
8272 iVar ? " " : "", fMxcsr, ValOut.ai32[0], ValOut.ai32[1],
8273 iVar ? " " : "", paTests[iTest].fMxcsrOut,
8274 paTests[iTest].OutVal.ai32[0], paTests[iTest].OutVal.ai32[1],
8275 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
8276 ( ValOut.ai32[0] != paTests[iTest].OutVal.ai32[0]
8277 || ValOut.ai32[1] != paTests[iTest].OutVal.ai32[1])
8278 ? " - val" : "",
8279 FormatMxcsr(paTests[iTest].fMxcsrIn));
8280 }
8281 }
8282 }
8283}
8284
8285
8286/*
8287 * Convert SSE operations converting signed double-word values to double precision floating-point values (probably only cvtpi2pd).
8288 */
8289TYPEDEF_SUBTEST_TYPE(SSE_CONVERT_XMM_R64_MM_T, SSE_CONVERT_XMM_MM_TEST_T, PFNIEMAIMPLMXCSRU128U64);
8290
8291static const SSE_CONVERT_XMM_R64_MM_T g_aSseConvertXmmR64Mm[] =
8292{
8293 ENTRY_BIN(cvtpi2pd_u128)
8294};
8295
8296#ifdef TSTIEMAIMPL_WITH_GENERATOR
8297static RTEXITCODE SseConvertXmmR64MmGenerate(const char *pszDataFileFmt, uint32_t cTests)
8298{
8299 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
8300
8301 static struct { int32_t aVal[2]; } const s_aSpecials[] =
8302 {
8303 { { INT32_MIN, INT32_MIN } },
8304 { { INT32_MAX, INT32_MAX } }
8305 /** @todo More specials. */
8306 };
8307
8308 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertXmmR64Mm); iFn++)
8309 {
8310 PFNIEMAIMPLMXCSRU128U64 const pfn = g_aSseConvertXmmR64Mm[iFn].pfnNative ? g_aSseConvertXmmR64Mm[iFn].pfnNative : g_aSseConvertXmmR64Mm[iFn].pfn;
8311
8312 PRTSTREAM pStrmOut = NULL;
8313 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseConvertXmmR64Mm[iFn].pszName);
8314 if (RT_FAILURE(rc))
8315 {
8316 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseConvertXmmR64Mm[iFn].pszName, rc);
8317 return RTEXITCODE_FAILURE;
8318 }
8319
8320 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
8321 {
8322 SSE_CONVERT_XMM_MM_TEST_T TestData; RT_ZERO(TestData);
8323
8324 TestData.InVal.ai32[0] = iTest < cTests ? RandI32Src2(iTest) : s_aSpecials[iTest - cTests].aVal[0];
8325 TestData.InVal.ai32[1] = iTest < cTests ? RandI32Src2(iTest) : s_aSpecials[iTest - cTests].aVal[1];
8326
8327 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
8328 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
8329 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
8330 for (uint8_t iFz = 0; iFz < 2; iFz++)
8331 {
8332 uint32_t fMxcsrIn = (fMxcsr & ~X86_MXCSR_RC_MASK)
8333 | (iRounding << X86_MXCSR_RC_SHIFT)
8334 | (iDaz ? X86_MXCSR_DAZ : 0)
8335 | (iFz ? X86_MXCSR_FZ : 0)
8336 | X86_MXCSR_XCPT_MASK;
8337 uint32_t fMxcsrM = fMxcsrIn;
8338 pfn(&fMxcsrM, &TestData.OutVal, TestData.InVal.u);
8339 TestData.fMxcsrIn = fMxcsrIn;
8340 TestData.fMxcsrOut = fMxcsrM;
8341 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8342
8343 fMxcsrIn &= ~X86_MXCSR_XCPT_MASK;
8344 uint32_t fMxcsrU = fMxcsrIn;
8345 pfn(&fMxcsrU, &TestData.OutVal, TestData.InVal.u);
8346 TestData.fMxcsrIn = fMxcsrIn;
8347 TestData.fMxcsrOut = fMxcsrU;
8348 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8349
8350 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
8351 if (fXcpt)
8352 {
8353 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | fXcpt;
8354 uint32_t fMxcsr1 = fMxcsrIn;
8355 pfn(&fMxcsr1, &TestData.OutVal, TestData.InVal.u);
8356 TestData.fMxcsrIn = fMxcsrIn;
8357 TestData.fMxcsrOut = fMxcsr1;
8358 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8359
8360 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
8361 {
8362 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
8363 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
8364 uint32_t fMxcsr2 = fMxcsrIn;
8365 pfn(&fMxcsr2, &TestData.OutVal, TestData.InVal.u);
8366 TestData.fMxcsrIn = fMxcsrIn;
8367 TestData.fMxcsrOut = fMxcsr2;
8368 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8369 }
8370 if (!RT_IS_POWER_OF_TWO(fXcpt))
8371 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
8372 if (fUnmasked & fXcpt)
8373 {
8374 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
8375 uint32_t fMxcsr3 = fMxcsrIn;
8376 pfn(&fMxcsr3, &TestData.OutVal, TestData.InVal.u);
8377 TestData.fMxcsrIn = fMxcsrIn;
8378 TestData.fMxcsrOut = fMxcsr3;
8379 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8380 }
8381 }
8382 }
8383 }
8384 rc = RTStrmClose(pStrmOut);
8385 if (RT_FAILURE(rc))
8386 {
8387 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseConvertXmmR64Mm[iFn].pszName, rc);
8388 return RTEXITCODE_FAILURE;
8389 }
8390 }
8391
8392 return RTEXITCODE_SUCCESS;
8393}
8394#endif
8395
8396static void SseConvertXmmR64MmTest(void)
8397{
8398 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertXmmR64Mm); iFn++)
8399 {
8400 if (!SubTestAndCheckIfEnabled(g_aSseConvertXmmR64Mm[iFn].pszName))
8401 continue;
8402
8403 uint32_t const cTests = *g_aSseConvertXmmR64Mm[iFn].pcTests;
8404 SSE_CONVERT_XMM_MM_TEST_T const * const paTests = g_aSseConvertXmmR64Mm[iFn].paTests;
8405 PFNIEMAIMPLMXCSRU128U64 pfn = g_aSseConvertXmmR64Mm[iFn].pfn;
8406 uint32_t const cVars = COUNT_VARIATIONS(g_aSseConvertXmmR64Mm[iFn]);
8407 if (!cTests) RTTestSkipped(g_hTest, "no tests");
8408 for (uint32_t iVar = 0; iVar < cVars; iVar++)
8409 {
8410 for (uint32_t iTest = 0; iTest < cTests / sizeof(*paTests); iTest++)
8411 {
8412 X86XMMREG ValOut;
8413 uint32_t fMxcsr = paTests[iTest].fMxcsrIn;
8414 pfn(&fMxcsr, &ValOut, paTests[iTest].InVal.u);
8415 if ( fMxcsr != paTests[iTest].fMxcsrOut
8416 || !RTFLOAT64U_ARE_IDENTICAL(&ValOut.ar64[0], &paTests[iTest].OutVal.ar64[0])
8417 || !RTFLOAT64U_ARE_IDENTICAL(&ValOut.ar64[1], &paTests[iTest].OutVal.ar64[1]))
8418 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%RI32'%RI32\n"
8419 "%s -> mxcsr=%#08x %s'%s\n"
8420 "%s expected %#08x %s'%s%s%s (%s)\n",
8421 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
8422 paTests[iTest].InVal.ai32[0], paTests[iTest].InVal.ai32[1],
8423 iVar ? " " : "", fMxcsr,
8424 FormatR64(&ValOut.ar64[0]), FormatR64(&ValOut.ar64[1]),
8425 iVar ? " " : "", paTests[iTest].fMxcsrOut,
8426 FormatR64(&paTests[iTest].OutVal.ar64[0]), FormatR64(&paTests[iTest].OutVal.ar64[1]),
8427 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
8428 ( !RTFLOAT64U_ARE_IDENTICAL(&ValOut.ar64[0], &paTests[iTest].OutVal.ar64[0])
8429 || !RTFLOAT64U_ARE_IDENTICAL(&ValOut.ar64[1], &paTests[iTest].OutVal.ar64[1]))
8430 ? " - val" : "",
8431 FormatMxcsr(paTests[iTest].fMxcsrIn));
8432 }
8433 }
8434 }
8435}
8436
8437
8438/*
8439 * Convert SSE operations converting signed double-word values to double precision floating-point values (probably only cvtpi2pd).
8440 */
8441TYPEDEF_SUBTEST_TYPE(SSE_CONVERT_XMM_R32_MM_T, SSE_CONVERT_XMM_MM_TEST_T, PFNIEMAIMPLMXCSRU128U64);
8442
8443static const SSE_CONVERT_XMM_R32_MM_T g_aSseConvertXmmR32Mm[] =
8444{
8445 ENTRY_BIN(cvtpi2ps_u128)
8446};
8447
8448#ifdef TSTIEMAIMPL_WITH_GENERATOR
8449static RTEXITCODE SseConvertXmmR32MmGenerate(const char *pszDataFileFmt, uint32_t cTests)
8450{
8451 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
8452
8453 static struct { int32_t aVal[2]; } const s_aSpecials[] =
8454 {
8455 { { INT32_MIN, INT32_MIN } },
8456 { { INT32_MAX, INT32_MAX } }
8457 /** @todo More specials. */
8458 };
8459
8460 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertXmmR32Mm); iFn++)
8461 {
8462 PFNIEMAIMPLMXCSRU128U64 const pfn = g_aSseConvertXmmR32Mm[iFn].pfnNative ? g_aSseConvertXmmR32Mm[iFn].pfnNative : g_aSseConvertXmmR32Mm[iFn].pfn;
8463
8464 PRTSTREAM pStrmOut = NULL;
8465 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseConvertXmmR32Mm[iFn].pszName);
8466 if (RT_FAILURE(rc))
8467 {
8468 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseConvertXmmR32Mm[iFn].pszName, rc);
8469 return RTEXITCODE_FAILURE;
8470 }
8471
8472 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
8473 {
8474 SSE_CONVERT_XMM_MM_TEST_T TestData; RT_ZERO(TestData);
8475
8476 TestData.InVal.ai32[0] = iTest < cTests ? RandI32Src2(iTest) : s_aSpecials[iTest - cTests].aVal[0];
8477 TestData.InVal.ai32[1] = iTest < cTests ? RandI32Src2(iTest) : s_aSpecials[iTest - cTests].aVal[1];
8478
8479 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
8480 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
8481 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
8482 for (uint8_t iFz = 0; iFz < 2; iFz++)
8483 {
8484 uint32_t fMxcsrIn = (fMxcsr & ~X86_MXCSR_RC_MASK)
8485 | (iRounding << X86_MXCSR_RC_SHIFT)
8486 | (iDaz ? X86_MXCSR_DAZ : 0)
8487 | (iFz ? X86_MXCSR_FZ : 0)
8488 | X86_MXCSR_XCPT_MASK;
8489 uint32_t fMxcsrM = fMxcsrIn;
8490 pfn(&fMxcsrM, &TestData.OutVal, TestData.InVal.u);
8491 TestData.fMxcsrIn = fMxcsrIn;
8492 TestData.fMxcsrOut = fMxcsrM;
8493 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8494
8495 fMxcsrIn &= ~X86_MXCSR_XCPT_MASK;
8496 uint32_t fMxcsrU = fMxcsrIn;
8497 pfn(&fMxcsrU, &TestData.OutVal, TestData.InVal.u);
8498 TestData.fMxcsrIn = fMxcsrIn;
8499 TestData.fMxcsrOut = fMxcsrU;
8500 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8501
8502 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
8503 if (fXcpt)
8504 {
8505 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | fXcpt;
8506 uint32_t fMxcsr1 = fMxcsrIn;
8507 pfn(&fMxcsr1, &TestData.OutVal, TestData.InVal.u);
8508 TestData.fMxcsrIn = fMxcsrIn;
8509 TestData.fMxcsrOut = fMxcsr1;
8510 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8511
8512 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
8513 {
8514 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
8515 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
8516 uint32_t fMxcsr2 = fMxcsrIn;
8517 pfn(&fMxcsr2, &TestData.OutVal, TestData.InVal.u);
8518 TestData.fMxcsrIn = fMxcsrIn;
8519 TestData.fMxcsrOut = fMxcsr2;
8520 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8521 }
8522 if (!RT_IS_POWER_OF_TWO(fXcpt))
8523 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
8524 if (fUnmasked & fXcpt)
8525 {
8526 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
8527 uint32_t fMxcsr3 = fMxcsrIn;
8528 pfn(&fMxcsr3, &TestData.OutVal, TestData.InVal.u);
8529 TestData.fMxcsrIn = fMxcsrIn;
8530 TestData.fMxcsrOut = fMxcsr3;
8531 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8532 }
8533 }
8534 }
8535 }
8536 rc = RTStrmClose(pStrmOut);
8537 if (RT_FAILURE(rc))
8538 {
8539 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseConvertXmmR32Mm[iFn].pszName, rc);
8540 return RTEXITCODE_FAILURE;
8541 }
8542 }
8543
8544 return RTEXITCODE_SUCCESS;
8545}
8546#endif
8547
8548static void SseConvertXmmR32MmTest(void)
8549{
8550 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertXmmR32Mm); iFn++)
8551 {
8552 if (!SubTestAndCheckIfEnabled(g_aSseConvertXmmR32Mm[iFn].pszName))
8553 continue;
8554
8555 uint32_t const cTests = *g_aSseConvertXmmR32Mm[iFn].pcTests;
8556 SSE_CONVERT_XMM_MM_TEST_T const * const paTests = g_aSseConvertXmmR32Mm[iFn].paTests;
8557 PFNIEMAIMPLMXCSRU128U64 pfn = g_aSseConvertXmmR32Mm[iFn].pfn;
8558 uint32_t const cVars = COUNT_VARIATIONS(g_aSseConvertXmmR32Mm[iFn]);
8559 if (!cTests) RTTestSkipped(g_hTest, "no tests");
8560 for (uint32_t iVar = 0; iVar < cVars; iVar++)
8561 {
8562 for (uint32_t iTest = 0; iTest < cTests / sizeof(*paTests); iTest++)
8563 {
8564 X86XMMREG ValOut;
8565 uint32_t fMxcsr = paTests[iTest].fMxcsrIn;
8566 pfn(&fMxcsr, &ValOut, paTests[iTest].InVal.u);
8567 if ( fMxcsr != paTests[iTest].fMxcsrOut
8568 || !RTFLOAT32U_ARE_IDENTICAL(&ValOut.ar32[0], &paTests[iTest].OutVal.ar32[0])
8569 || !RTFLOAT32U_ARE_IDENTICAL(&ValOut.ar32[1], &paTests[iTest].OutVal.ar32[1]))
8570 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%RI32'%RI32\n"
8571 "%s -> mxcsr=%#08x %s'%s\n"
8572 "%s expected %#08x %s'%s%s%s (%s)\n",
8573 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
8574 paTests[iTest].InVal.ai32[0], paTests[iTest].InVal.ai32[1],
8575 iVar ? " " : "", fMxcsr,
8576 FormatR32(&ValOut.ar32[0]), FormatR32(&ValOut.ar32[1]),
8577 iVar ? " " : "", paTests[iTest].fMxcsrOut,
8578 FormatR32(&paTests[iTest].OutVal.ar32[0]), FormatR32(&paTests[iTest].OutVal.ar32[1]),
8579 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
8580 ( !RTFLOAT32U_ARE_IDENTICAL(&ValOut.ar32[0], &paTests[iTest].OutVal.ar32[0])
8581 || !RTFLOAT32U_ARE_IDENTICAL(&ValOut.ar32[1], &paTests[iTest].OutVal.ar32[1]))
8582 ? " - val" : "",
8583 FormatMxcsr(paTests[iTest].fMxcsrIn));
8584 }
8585 }
8586 }
8587}
8588
8589
8590/*
8591 * Convert SSE operations converting single-precision floating point values to signed double-word values.
8592 */
8593TYPEDEF_SUBTEST_TYPE(SSE_CONVERT_MM_I32_XMM_R32_T, SSE_CONVERT_MM_R32_TEST_T, PFNIEMAIMPLMXCSRU64U64);
8594
8595static const SSE_CONVERT_MM_I32_XMM_R32_T g_aSseConvertMmI32XmmR32[] =
8596{
8597 ENTRY_BIN(cvtps2pi_u128),
8598 ENTRY_BIN(cvttps2pi_u128)
8599};
8600
8601#ifdef TSTIEMAIMPL_WITH_GENERATOR
8602static RTEXITCODE SseConvertMmI32XmmR32Generate(const char *pszDataFileFmt, uint32_t cTests)
8603{
8604 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
8605
8606 static struct { RTFLOAT32U aVal1[2]; } const s_aSpecials[] =
8607 {
8608 { { RTFLOAT32U_INIT_ZERO(0), RTFLOAT32U_INIT_ZERO(0) } },
8609 { { RTFLOAT32U_INIT_ZERO(1), RTFLOAT32U_INIT_ZERO(1) } },
8610 { { RTFLOAT32U_INIT_INF(0), RTFLOAT32U_INIT_INF(0) } },
8611 { { RTFLOAT32U_INIT_INF(1), RTFLOAT32U_INIT_INF(1) } }
8612 /** @todo More specials. */
8613 };
8614
8615 uint32_t cMinNormalPairs = (cTests - 144) / 4;
8616 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertMmI32XmmR32); iFn++)
8617 {
8618 PFNIEMAIMPLMXCSRU64U64 const pfn = g_aSseConvertMmI32XmmR32[iFn].pfnNative ? g_aSseConvertMmI32XmmR32[iFn].pfnNative : g_aSseConvertMmI32XmmR32[iFn].pfn;
8619
8620 PRTSTREAM pStrmOut = NULL;
8621 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSseConvertMmI32XmmR32[iFn].pszName);
8622 if (RT_FAILURE(rc))
8623 {
8624 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSseConvertMmI32XmmR32[iFn].pszName, rc);
8625 return RTEXITCODE_FAILURE;
8626 }
8627
8628 uint32_t cNormalInputPairs = 0;
8629 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
8630 {
8631 SSE_CONVERT_MM_R32_TEST_T TestData; RT_ZERO(TestData);
8632
8633 TestData.ar32InVal[0] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].aVal1[0];
8634 TestData.ar32InVal[1] = iTest < cTests ? RandR32Src(iTest) : s_aSpecials[iTest - cTests].aVal1[1];
8635
8636 if ( RTFLOAT32U_IS_NORMAL(&TestData.ar32InVal[0])
8637 && RTFLOAT32U_IS_NORMAL(&TestData.ar32InVal[1]))
8638 cNormalInputPairs++;
8639 else if (cNormalInputPairs < cMinNormalPairs && iTest + cMinNormalPairs >= cTests && iTest < cTests)
8640 {
8641 iTest -= 1;
8642 continue;
8643 }
8644
8645 RTFLOAT64U TestVal;
8646 TestVal.au32[0] = TestData.ar32InVal[0].u;
8647 TestVal.au32[1] = TestData.ar32InVal[1].u;
8648
8649 uint32_t const fMxcsr = RandMxcsr() & X86_MXCSR_XCPT_FLAGS;
8650 for (uint16_t iRounding = 0; iRounding < 4; iRounding++)
8651 for (uint8_t iDaz = 0; iDaz < 2; iDaz++)
8652 for (uint8_t iFz = 0; iFz < 2; iFz++)
8653 {
8654 uint32_t fMxcsrIn = (fMxcsr & ~X86_MXCSR_RC_MASK)
8655 | (iRounding << X86_MXCSR_RC_SHIFT)
8656 | (iDaz ? X86_MXCSR_DAZ : 0)
8657 | (iFz ? X86_MXCSR_FZ : 0)
8658 | X86_MXCSR_XCPT_MASK;
8659 uint32_t fMxcsrM = fMxcsrIn;
8660 uint64_t u64ResM;
8661 pfn(&fMxcsrM, &u64ResM, TestVal.u);
8662 TestData.fMxcsrIn = fMxcsrIn;
8663 TestData.fMxcsrOut = fMxcsrM;
8664 TestData.OutVal.u = u64ResM;
8665 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8666
8667 fMxcsrIn &= ~X86_MXCSR_XCPT_MASK;
8668 uint32_t fMxcsrU = fMxcsrIn;
8669 uint64_t u64ResU;
8670 pfn(&fMxcsrU, &u64ResU, TestVal.u);
8671 TestData.fMxcsrIn = fMxcsrIn;
8672 TestData.fMxcsrOut = fMxcsrU;
8673 TestData.OutVal.u = u64ResU;
8674 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8675
8676 uint16_t fXcpt = (fMxcsrM | fMxcsrU) & X86_MXCSR_XCPT_FLAGS;
8677 if (fXcpt)
8678 {
8679 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | fXcpt;
8680 uint32_t fMxcsr1 = fMxcsrIn;
8681 uint64_t u64Res1;
8682 pfn(&fMxcsr1, &u64Res1, TestVal.u);
8683 TestData.fMxcsrIn = fMxcsrIn;
8684 TestData.fMxcsrOut = fMxcsr1;
8685 TestData.OutVal.u = u64Res1;
8686 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8687
8688 if (((fMxcsr1 & X86_MXCSR_XCPT_FLAGS) & fXcpt) != (fMxcsr1 & X86_MXCSR_XCPT_FLAGS))
8689 {
8690 fXcpt |= fMxcsr1 & X86_MXCSR_XCPT_FLAGS;
8691 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | (fXcpt << X86_MXCSR_XCPT_MASK_SHIFT);
8692 uint32_t fMxcsr2 = fMxcsrIn;
8693 uint64_t u64Res2;
8694 pfn(&fMxcsr2, &u64Res2, TestVal.u);
8695 TestData.fMxcsrIn = fMxcsrIn;
8696 TestData.fMxcsrOut = fMxcsr2;
8697 TestData.OutVal.u = u64Res2;
8698 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8699 }
8700 if (!RT_IS_POWER_OF_TWO(fXcpt))
8701 for (uint16_t fUnmasked = 1; fUnmasked <= X86_MXCSR_PE; fUnmasked <<= 1)
8702 if (fUnmasked & fXcpt)
8703 {
8704 fMxcsrIn = (fMxcsrIn & ~X86_MXCSR_XCPT_MASK) | ((fXcpt & ~fUnmasked) << X86_MXCSR_XCPT_MASK_SHIFT);
8705 uint32_t fMxcsr3 = fMxcsrIn;
8706 uint64_t u64Res3;
8707 pfn(&fMxcsr3, &u64Res3, TestVal.u);
8708 TestData.fMxcsrIn = fMxcsrIn;
8709 TestData.fMxcsrOut = fMxcsr3;
8710 TestData.OutVal.u = u64Res3;
8711 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8712 }
8713 }
8714 }
8715 }
8716 rc = RTStrmClose(pStrmOut);
8717 if (RT_FAILURE(rc))
8718 {
8719 RTMsgError("Failed to close data file for %s: %Rrc", g_aSseConvertMmI32XmmR32[iFn].pszName, rc);
8720 return RTEXITCODE_FAILURE;
8721 }
8722 }
8723
8724 return RTEXITCODE_SUCCESS;
8725}
8726#endif
8727
8728static void SseConvertMmI32XmmR32Test(void)
8729{
8730 X86FXSTATE State;
8731 RT_ZERO(State);
8732
8733 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSseConvertMmI32XmmR32); iFn++)
8734 {
8735 if (!SubTestAndCheckIfEnabled(g_aSseConvertMmI32XmmR32[iFn].pszName))
8736 continue;
8737
8738 uint32_t const cTests = *g_aSseConvertMmI32XmmR32[iFn].pcTests;
8739 SSE_CONVERT_MM_R32_TEST_T const * const paTests = g_aSseConvertMmI32XmmR32[iFn].paTests;
8740 PFNIEMAIMPLMXCSRU64U64 pfn = g_aSseConvertMmI32XmmR32[iFn].pfn;
8741 uint32_t const cVars = COUNT_VARIATIONS(g_aSseConvertMmI32XmmR32[iFn]);
8742 if (!cTests) RTTestSkipped(g_hTest, "no tests");
8743 for (uint32_t iVar = 0; iVar < cVars; iVar++)
8744 {
8745 for (uint32_t iTest = 0; iTest < cTests / sizeof(*paTests); iTest++)
8746 {
8747 RTUINT64U ValOut;
8748 RTUINT64U ValIn;
8749
8750 ValIn.au32[0] = paTests[iTest].ar32InVal[0].u;
8751 ValIn.au32[1] = paTests[iTest].ar32InVal[1].u;
8752
8753 uint32_t fMxcsr = paTests[iTest].fMxcsrIn;
8754 pfn(&fMxcsr, &ValOut.u, ValIn.u);
8755 if ( fMxcsr != paTests[iTest].fMxcsrOut
8756 || ValOut.ai32[0] != paTests[iTest].OutVal.ai32[0]
8757 || ValOut.ai32[1] != paTests[iTest].OutVal.ai32[1])
8758 RTTestFailed(g_hTest, "#%04u%s: mxcsr=%#08x in1=%s'%s \n"
8759 "%s -> mxcsr=%#08x %RI32'%RI32\n"
8760 "%s expected %#08x %RI32'%RI32%s%s (%s)\n",
8761 iTest, iVar ? "/n" : "", paTests[iTest].fMxcsrIn,
8762 FormatR32(&paTests[iTest].ar32InVal[0]), FormatR32(&paTests[iTest].ar32InVal[1]),
8763 iVar ? " " : "", fMxcsr,
8764 ValOut.ai32[0], ValOut.ai32[1],
8765 iVar ? " " : "", paTests[iTest].fMxcsrOut,
8766 paTests[iTest].OutVal.ai32[0], paTests[iTest].OutVal.ai32[1],
8767 MxcsrDiff(fMxcsr, paTests[iTest].fMxcsrOut),
8768 ( ValOut.ai32[0] != paTests[iTest].OutVal.ai32[0]
8769 || ValOut.ai32[1] != paTests[iTest].OutVal.ai32[1])
8770 ? " - val" : "",
8771 FormatMxcsr(paTests[iTest].fMxcsrIn));
8772 }
8773 }
8774 }
8775}
8776
8777
8778/*
8779 * SSE 4.2 pcmpxstrx instructions.
8780 */
8781TYPEDEF_SUBTEST_TYPE(SSE_PCMPISTRI_T, SSE_PCMPISTRI_TEST_T, PFNIEMAIMPLPCMPISTRIU128IMM8);
8782
8783static const SSE_PCMPISTRI_T g_aSsePcmpistri[] =
8784{
8785 ENTRY_BIN_SSE_OPT(pcmpistri_u128),
8786};
8787
8788#ifdef TSTIEMAIMPL_WITH_GENERATOR
8789static RTEXITCODE SseComparePcmpistriGenerate(const char *pszDataFileFmt, uint32_t cTests)
8790{
8791 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
8792
8793 static struct { RTUINT128U uSrc1; RTUINT128U uSrc2; } const s_aSpecials[] =
8794 {
8795 { RTUINT128_INIT_C(0, 0), RTUINT128_INIT_C(0, 0) },
8796 /** @todo More specials. */
8797 };
8798
8799 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSsePcmpistri); iFn++)
8800 {
8801 PFNIEMAIMPLPCMPISTRIU128IMM8 const pfn = g_aSsePcmpistri[iFn].pfnNative ? g_aSsePcmpistri[iFn].pfnNative : g_aSsePcmpistri[iFn].pfn;
8802
8803 PRTSTREAM pStrmOut = NULL;
8804 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSsePcmpistri[iFn].pszName);
8805 if (RT_FAILURE(rc))
8806 {
8807 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSsePcmpistri[iFn].pszName, rc);
8808 return RTEXITCODE_FAILURE;
8809 }
8810
8811 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
8812 {
8813 SSE_PCMPISTRI_TEST_T TestData; RT_ZERO(TestData);
8814
8815 TestData.InVal1.uXmm = iTest < cTests ? RandU128() : s_aSpecials[iTest - cTests].uSrc1;
8816 TestData.InVal2.uXmm = iTest < cTests ? RandU128() : s_aSpecials[iTest - cTests].uSrc2;
8817
8818 IEMPCMPISTRXSRC TestVal;
8819 TestVal.uSrc1 = TestData.InVal1.uXmm;
8820 TestVal.uSrc2 = TestData.InVal2.uXmm;
8821
8822 uint32_t const fEFlagsIn = RandEFlags();
8823 for (uint16_t u16Imm = 0; u16Imm < 256; u16Imm++)
8824 {
8825 uint32_t fEFlagsOut = fEFlagsIn;
8826 pfn(&TestData.u32EcxOut, &fEFlagsOut, &TestVal, (uint8_t)u16Imm);
8827 TestData.fEFlagsIn = fEFlagsIn;
8828 TestData.fEFlagsOut = fEFlagsOut;
8829 TestData.bImm = (uint8_t)u16Imm;
8830 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8831 }
8832
8833 /* Repeat the test with the input value being the same. */
8834 TestData.InVal2.uXmm = TestData.InVal1.uXmm;
8835 TestVal.uSrc1 = TestData.InVal1.uXmm;
8836 TestVal.uSrc2 = TestData.InVal2.uXmm;
8837
8838 for (uint16_t u16Imm = 0; u16Imm < 256; u16Imm++)
8839 {
8840 uint32_t fEFlagsOut = fEFlagsIn;
8841 pfn(&TestData.u32EcxOut, &fEFlagsOut, &TestVal, (uint8_t)u16Imm);
8842 TestData.fEFlagsIn = fEFlagsIn;
8843 TestData.fEFlagsOut = fEFlagsOut;
8844 TestData.bImm = (uint8_t)u16Imm;
8845 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8846 }
8847 }
8848 rc = RTStrmClose(pStrmOut);
8849 if (RT_FAILURE(rc))
8850 {
8851 RTMsgError("Failed to close data file for %s: %Rrc", g_aSsePcmpistri[iFn].pszName, rc);
8852 return RTEXITCODE_FAILURE;
8853 }
8854 }
8855
8856 return RTEXITCODE_SUCCESS;
8857}
8858#endif
8859
8860static void SseComparePcmpistriTest(void)
8861{
8862 X86FXSTATE State;
8863 RT_ZERO(State);
8864
8865 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSsePcmpistri); iFn++)
8866 {
8867 if (!SubTestAndCheckIfEnabled(g_aSsePcmpistri[iFn].pszName))
8868 continue;
8869
8870 uint32_t const cTests = *g_aSsePcmpistri[iFn].pcTests;
8871 SSE_PCMPISTRI_TEST_T const * const paTests = g_aSsePcmpistri[iFn].paTests;
8872 PFNIEMAIMPLPCMPISTRIU128IMM8 pfn = g_aSsePcmpistri[iFn].pfn;
8873 uint32_t const cVars = COUNT_VARIATIONS(g_aSsePcmpistri[iFn]);
8874 if (!cTests) RTTestSkipped(g_hTest, "no tests");
8875 for (uint32_t iVar = 0; iVar < cVars; iVar++)
8876 {
8877 for (uint32_t iTest = 0; iTest < cTests / sizeof(*paTests); iTest++)
8878 {
8879 IEMPCMPISTRXSRC TestVal;
8880 TestVal.uSrc1 = paTests[iTest].InVal1.uXmm;
8881 TestVal.uSrc2 = paTests[iTest].InVal2.uXmm;
8882
8883 uint32_t fEFlags = paTests[iTest].fEFlagsIn;
8884 uint32_t u32EcxOut = 0;
8885 pfn(&u32EcxOut, &fEFlags, &TestVal, paTests[iTest].bImm);
8886 if ( fEFlags != paTests[iTest].fEFlagsOut
8887 || u32EcxOut != paTests[iTest].u32EcxOut)
8888 RTTestFailed(g_hTest, "#%04u%s: efl=%#08x in1=%s in2=%s bImm=%#x\n"
8889 "%s -> efl=%#08x %RU32\n"
8890 "%s expected %#08x %RU32%s%s\n",
8891 iTest, iVar ? "/n" : "", paTests[iTest].fEFlagsIn,
8892 FormatU128(&paTests[iTest].InVal1.uXmm), FormatU128(&paTests[iTest].InVal2.uXmm), paTests[iTest].bImm,
8893 iVar ? " " : "", fEFlags, u32EcxOut,
8894 iVar ? " " : "", paTests[iTest].fEFlagsOut, paTests[iTest].u32EcxOut,
8895 EFlagsDiff(fEFlags, paTests[iTest].fEFlagsOut),
8896 (u32EcxOut != paTests[iTest].u32EcxOut) ? " - val" : "");
8897 }
8898 }
8899 }
8900}
8901
8902
8903TYPEDEF_SUBTEST_TYPE(SSE_PCMPISTRM_T, SSE_PCMPISTRM_TEST_T, PFNIEMAIMPLPCMPISTRMU128IMM8);
8904
8905static const SSE_PCMPISTRM_T g_aSsePcmpistrm[] =
8906{
8907 ENTRY_BIN_SSE_OPT(pcmpistrm_u128),
8908};
8909
8910#ifdef TSTIEMAIMPL_WITH_GENERATOR
8911static RTEXITCODE SseComparePcmpistrmGenerate(const char *pszDataFileFmt, uint32_t cTests)
8912{
8913 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
8914
8915 static struct { RTUINT128U uSrc1; RTUINT128U uSrc2; } const s_aSpecials[] =
8916 {
8917 { RTUINT128_INIT_C(0, 0), RTUINT128_INIT_C(0, 0) },
8918 /** @todo More specials. */
8919 };
8920
8921 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSsePcmpistrm); iFn++)
8922 {
8923 PFNIEMAIMPLPCMPISTRMU128IMM8 const pfn = g_aSsePcmpistrm[iFn].pfnNative ? g_aSsePcmpistrm[iFn].pfnNative : g_aSsePcmpistrm[iFn].pfn;
8924
8925 PRTSTREAM pStrmOut = NULL;
8926 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSsePcmpistrm[iFn].pszName);
8927 if (RT_FAILURE(rc))
8928 {
8929 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSsePcmpistrm[iFn].pszName, rc);
8930 return RTEXITCODE_FAILURE;
8931 }
8932
8933 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
8934 {
8935 SSE_PCMPISTRM_TEST_T TestData; RT_ZERO(TestData);
8936
8937 TestData.InVal1.uXmm = iTest < cTests ? RandU128() : s_aSpecials[iTest - cTests].uSrc1;
8938 TestData.InVal2.uXmm = iTest < cTests ? RandU128() : s_aSpecials[iTest - cTests].uSrc2;
8939
8940 IEMPCMPISTRXSRC TestVal;
8941 TestVal.uSrc1 = TestData.InVal1.uXmm;
8942 TestVal.uSrc2 = TestData.InVal2.uXmm;
8943
8944 uint32_t const fEFlagsIn = RandEFlags();
8945 for (uint16_t u16Imm = 0; u16Imm < 256; u16Imm++)
8946 {
8947 uint32_t fEFlagsOut = fEFlagsIn;
8948 pfn(&TestData.OutVal.uXmm, &fEFlagsOut, &TestVal, (uint8_t)u16Imm);
8949 TestData.fEFlagsIn = fEFlagsIn;
8950 TestData.fEFlagsOut = fEFlagsOut;
8951 TestData.bImm = (uint8_t)u16Imm;
8952 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8953 }
8954
8955 /* Repeat the test with the input value being the same. */
8956 TestData.InVal2.uXmm = TestData.InVal1.uXmm;
8957 TestVal.uSrc1 = TestData.InVal1.uXmm;
8958 TestVal.uSrc2 = TestData.InVal2.uXmm;
8959
8960 for (uint16_t u16Imm = 0; u16Imm < 256; u16Imm++)
8961 {
8962 uint32_t fEFlagsOut = fEFlagsIn;
8963 pfn(&TestData.OutVal.uXmm, &fEFlagsOut, &TestVal, (uint8_t)u16Imm);
8964 TestData.fEFlagsIn = fEFlagsIn;
8965 TestData.fEFlagsOut = fEFlagsOut;
8966 TestData.bImm = (uint8_t)u16Imm;
8967 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
8968 }
8969 }
8970 rc = RTStrmClose(pStrmOut);
8971 if (RT_FAILURE(rc))
8972 {
8973 RTMsgError("Failed to close data file for %s: %Rrc", g_aSsePcmpistrm[iFn].pszName, rc);
8974 return RTEXITCODE_FAILURE;
8975 }
8976 }
8977
8978 return RTEXITCODE_SUCCESS;
8979}
8980#endif
8981
8982static void SseComparePcmpistrmTest(void)
8983{
8984 X86FXSTATE State;
8985 RT_ZERO(State);
8986
8987 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSsePcmpistrm); iFn++)
8988 {
8989 if (!SubTestAndCheckIfEnabled(g_aSsePcmpistrm[iFn].pszName))
8990 continue;
8991
8992 uint32_t const cTests = *g_aSsePcmpistrm[iFn].pcTests;
8993 SSE_PCMPISTRM_TEST_T const * const paTests = g_aSsePcmpistrm[iFn].paTests;
8994 PFNIEMAIMPLPCMPISTRMU128IMM8 pfn = g_aSsePcmpistrm[iFn].pfn;
8995 uint32_t const cVars = COUNT_VARIATIONS(g_aSsePcmpistrm[iFn]);
8996 if (!cTests) RTTestSkipped(g_hTest, "no tests");
8997 for (uint32_t iVar = 0; iVar < cVars; iVar++)
8998 {
8999 for (uint32_t iTest = 0; iTest < cTests / sizeof(*paTests); iTest++)
9000 {
9001 IEMPCMPISTRXSRC TestVal;
9002 TestVal.uSrc1 = paTests[iTest].InVal1.uXmm;
9003 TestVal.uSrc2 = paTests[iTest].InVal2.uXmm;
9004
9005 uint32_t fEFlags = paTests[iTest].fEFlagsIn;
9006 RTUINT128U OutVal;
9007 pfn(&OutVal, &fEFlags, &TestVal, paTests[iTest].bImm);
9008 if ( fEFlags != paTests[iTest].fEFlagsOut
9009 || OutVal.s.Hi != paTests[iTest].OutVal.uXmm.s.Hi
9010 || OutVal.s.Lo != paTests[iTest].OutVal.uXmm.s.Lo)
9011 RTTestFailed(g_hTest, "#%04u%s: efl=%#08x in1=%s in2=%s bImm=%#x\n"
9012 "%s -> efl=%#08x %s\n"
9013 "%s expected %#08x %s%s%s\n",
9014 iTest, iVar ? "/n" : "", paTests[iTest].fEFlagsIn,
9015 FormatU128(&paTests[iTest].InVal1.uXmm), FormatU128(&paTests[iTest].InVal2.uXmm), paTests[iTest].bImm,
9016 iVar ? " " : "", fEFlags, FormatU128(&OutVal),
9017 iVar ? " " : "", paTests[iTest].fEFlagsOut, FormatU128(&paTests[iTest].OutVal.uXmm),
9018 EFlagsDiff(fEFlags, paTests[iTest].fEFlagsOut),
9019 ( OutVal.s.Hi != paTests[iTest].OutVal.uXmm.s.Hi
9020 || OutVal.s.Lo != paTests[iTest].OutVal.uXmm.s.Lo) ? " - val" : "");
9021 }
9022 }
9023 }
9024}
9025
9026
9027TYPEDEF_SUBTEST_TYPE(SSE_PCMPESTRI_T, SSE_PCMPESTRI_TEST_T, PFNIEMAIMPLPCMPESTRIU128IMM8);
9028
9029static const SSE_PCMPESTRI_T g_aSsePcmpestri[] =
9030{
9031 ENTRY_BIN_SSE_OPT(pcmpestri_u128),
9032};
9033
9034#ifdef TSTIEMAIMPL_WITH_GENERATOR
9035static RTEXITCODE SseComparePcmpestriGenerate(const char *pszDataFileFmt, uint32_t cTests)
9036{
9037 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
9038
9039 static struct { RTUINT128U uSrc1; RTUINT128U uSrc2; } const s_aSpecials[] =
9040 {
9041 { RTUINT128_INIT_C(0, 0), RTUINT128_INIT_C(0, 0) },
9042 /** @todo More specials. */
9043 };
9044
9045 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSsePcmpestri); iFn++)
9046 {
9047 PFNIEMAIMPLPCMPESTRIU128IMM8 const pfn = g_aSsePcmpestri[iFn].pfnNative ? g_aSsePcmpestri[iFn].pfnNative : g_aSsePcmpestri[iFn].pfn;
9048
9049 PRTSTREAM pStrmOut = NULL;
9050 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSsePcmpestri[iFn].pszName);
9051 if (RT_FAILURE(rc))
9052 {
9053 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSsePcmpestri[iFn].pszName, rc);
9054 return RTEXITCODE_FAILURE;
9055 }
9056
9057 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
9058 {
9059 SSE_PCMPESTRI_TEST_T TestData; RT_ZERO(TestData);
9060
9061 TestData.InVal1.uXmm = iTest < cTests ? RandU128() : s_aSpecials[iTest - cTests].uSrc1;
9062 TestData.InVal2.uXmm = iTest < cTests ? RandU128() : s_aSpecials[iTest - cTests].uSrc2;
9063
9064 for (int64_t i64Rax = -20; i64Rax < 20; i64Rax += 20)
9065 for (int64_t i64Rdx = -20; i64Rdx < 20; i64Rdx += 20)
9066 {
9067 TestData.u64Rax = (uint64_t)i64Rax;
9068 TestData.u64Rdx = (uint64_t)i64Rdx;
9069
9070 IEMPCMPESTRXSRC TestVal;
9071 TestVal.uSrc1 = TestData.InVal1.uXmm;
9072 TestVal.uSrc2 = TestData.InVal2.uXmm;
9073 TestVal.u64Rax = TestData.u64Rax;
9074 TestVal.u64Rdx = TestData.u64Rdx;
9075
9076 uint32_t const fEFlagsIn = RandEFlags();
9077 for (uint16_t u16Imm = 0; u16Imm < 256; u16Imm++)
9078 {
9079 uint32_t fEFlagsOut = fEFlagsIn;
9080 pfn(&TestData.u32EcxOut, &fEFlagsOut, &TestVal, (uint8_t)u16Imm);
9081 TestData.fEFlagsIn = fEFlagsIn;
9082 TestData.fEFlagsOut = fEFlagsOut;
9083 TestData.bImm = (uint8_t)u16Imm;
9084 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
9085 }
9086
9087 /* Repeat the test with the input value being the same. */
9088 TestData.InVal2.uXmm = TestData.InVal1.uXmm;
9089 TestVal.uSrc1 = TestData.InVal1.uXmm;
9090 TestVal.uSrc2 = TestData.InVal2.uXmm;
9091
9092 for (uint16_t u16Imm = 0; u16Imm < 256; u16Imm++)
9093 {
9094 uint32_t fEFlagsOut = fEFlagsIn;
9095 pfn(&TestData.u32EcxOut, &fEFlagsOut, &TestVal, (uint8_t)u16Imm);
9096 TestData.fEFlagsIn = fEFlagsIn;
9097 TestData.fEFlagsOut = fEFlagsOut;
9098 TestData.bImm = (uint8_t)u16Imm;
9099 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
9100 }
9101 }
9102 }
9103 rc = RTStrmClose(pStrmOut);
9104 if (RT_FAILURE(rc))
9105 {
9106 RTMsgError("Failed to close data file for %s: %Rrc", g_aSsePcmpestri[iFn].pszName, rc);
9107 return RTEXITCODE_FAILURE;
9108 }
9109 }
9110
9111 return RTEXITCODE_SUCCESS;
9112}
9113#endif
9114
9115static void SseComparePcmpestriTest(void)
9116{
9117 X86FXSTATE State;
9118 RT_ZERO(State);
9119
9120 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSsePcmpestri); iFn++)
9121 {
9122 if (!SubTestAndCheckIfEnabled(g_aSsePcmpestri[iFn].pszName))
9123 continue;
9124
9125 uint32_t const cTests = *g_aSsePcmpestri[iFn].pcTests;
9126 SSE_PCMPESTRI_TEST_T const * const paTests = g_aSsePcmpestri[iFn].paTests;
9127 PFNIEMAIMPLPCMPESTRIU128IMM8 pfn = g_aSsePcmpestri[iFn].pfn;
9128 uint32_t const cVars = COUNT_VARIATIONS(g_aSsePcmpestri[iFn]);
9129 if (!cTests) RTTestSkipped(g_hTest, "no tests");
9130 for (uint32_t iVar = 0; iVar < cVars; iVar++)
9131 {
9132 for (uint32_t iTest = 0; iTest < cTests / sizeof(*paTests); iTest++)
9133 {
9134 IEMPCMPESTRXSRC TestVal;
9135 TestVal.uSrc1 = paTests[iTest].InVal1.uXmm;
9136 TestVal.uSrc2 = paTests[iTest].InVal2.uXmm;
9137 TestVal.u64Rax = paTests[iTest].u64Rax;
9138 TestVal.u64Rdx = paTests[iTest].u64Rdx;
9139
9140 uint32_t fEFlags = paTests[iTest].fEFlagsIn;
9141 uint32_t u32EcxOut = 0;
9142 pfn(&u32EcxOut, &fEFlags, &TestVal, paTests[iTest].bImm);
9143 if ( fEFlags != paTests[iTest].fEFlagsOut
9144 || u32EcxOut != paTests[iTest].u32EcxOut)
9145 RTTestFailed(g_hTest, "#%04u%s: efl=%#08x in1=%s rax1=%RI64 in2=%s rdx2=%RI64 bImm=%#x\n"
9146 "%s -> efl=%#08x %RU32\n"
9147 "%s expected %#08x %RU32%s%s\n",
9148 iTest, iVar ? "/n" : "", paTests[iTest].fEFlagsIn,
9149 FormatU128(&paTests[iTest].InVal1.uXmm), paTests[iTest].u64Rax,
9150 FormatU128(&paTests[iTest].InVal2.uXmm), paTests[iTest].u64Rdx,
9151 paTests[iTest].bImm,
9152 iVar ? " " : "", fEFlags, u32EcxOut,
9153 iVar ? " " : "", paTests[iTest].fEFlagsOut, paTests[iTest].u32EcxOut,
9154 EFlagsDiff(fEFlags, paTests[iTest].fEFlagsOut),
9155 (u32EcxOut != paTests[iTest].u32EcxOut) ? " - val" : "");
9156 }
9157 }
9158 }
9159}
9160
9161
9162TYPEDEF_SUBTEST_TYPE(SSE_PCMPESTRM_T, SSE_PCMPESTRM_TEST_T, PFNIEMAIMPLPCMPESTRMU128IMM8);
9163
9164static const SSE_PCMPESTRM_T g_aSsePcmpestrm[] =
9165{
9166 ENTRY_BIN_SSE_OPT(pcmpestrm_u128),
9167};
9168
9169#ifdef TSTIEMAIMPL_WITH_GENERATOR
9170static RTEXITCODE SseComparePcmpestrmGenerate(const char *pszDataFileFmt, uint32_t cTests)
9171{
9172 cTests = RT_MAX(192, cTests); /* there are 144 standard input variations */
9173
9174 static struct { RTUINT128U uSrc1; RTUINT128U uSrc2; } const s_aSpecials[] =
9175 {
9176 { RTUINT128_INIT_C(0, 0), RTUINT128_INIT_C(0, 0) },
9177 /** @todo More specials. */
9178 };
9179
9180 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSsePcmpestrm); iFn++)
9181 {
9182 PFNIEMAIMPLPCMPESTRMU128IMM8 const pfn = g_aSsePcmpestrm[iFn].pfnNative ? g_aSsePcmpestrm[iFn].pfnNative : g_aSsePcmpestrm[iFn].pfn;
9183
9184 PRTSTREAM pStrmOut = NULL;
9185 int rc = RTStrmOpenF("wb", &pStrmOut, pszDataFileFmt, g_aSsePcmpestrm[iFn].pszName);
9186 if (RT_FAILURE(rc))
9187 {
9188 RTMsgError("Failed to open data file for %s for writing: %Rrc", g_aSsePcmpestrm[iFn].pszName, rc);
9189 return RTEXITCODE_FAILURE;
9190 }
9191
9192 for (uint32_t iTest = 0; iTest < cTests + RT_ELEMENTS(s_aSpecials); iTest += 1)
9193 {
9194 SSE_PCMPESTRM_TEST_T TestData; RT_ZERO(TestData);
9195
9196 TestData.InVal1.uXmm = iTest < cTests ? RandU128() : s_aSpecials[iTest - cTests].uSrc1;
9197 TestData.InVal2.uXmm = iTest < cTests ? RandU128() : s_aSpecials[iTest - cTests].uSrc2;
9198
9199 for (int64_t i64Rax = -20; i64Rax < 20; i64Rax += 20)
9200 for (int64_t i64Rdx = -20; i64Rdx < 20; i64Rdx += 20)
9201 {
9202 TestData.u64Rax = (uint64_t)i64Rax;
9203 TestData.u64Rdx = (uint64_t)i64Rdx;
9204
9205 IEMPCMPESTRXSRC TestVal;
9206 TestVal.uSrc1 = TestData.InVal1.uXmm;
9207 TestVal.uSrc2 = TestData.InVal2.uXmm;
9208 TestVal.u64Rax = TestData.u64Rax;
9209 TestVal.u64Rdx = TestData.u64Rdx;
9210
9211 uint32_t const fEFlagsIn = RandEFlags();
9212 for (uint16_t u16Imm = 0; u16Imm < 256; u16Imm++)
9213 {
9214 uint32_t fEFlagsOut = fEFlagsIn;
9215 pfn(&TestData.OutVal.uXmm, &fEFlagsOut, &TestVal, (uint8_t)u16Imm);
9216 TestData.fEFlagsIn = fEFlagsIn;
9217 TestData.fEFlagsOut = fEFlagsOut;
9218 TestData.bImm = (uint8_t)u16Imm;
9219 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
9220 }
9221
9222 /* Repeat the test with the input value being the same. */
9223 TestData.InVal2.uXmm = TestData.InVal1.uXmm;
9224 TestVal.uSrc1 = TestData.InVal1.uXmm;
9225 TestVal.uSrc2 = TestData.InVal2.uXmm;
9226
9227 for (uint16_t u16Imm = 0; u16Imm < 256; u16Imm++)
9228 {
9229 uint32_t fEFlagsOut = fEFlagsIn;
9230 pfn(&TestData.OutVal.uXmm, &fEFlagsOut, &TestVal, (uint8_t)u16Imm);
9231 TestData.fEFlagsIn = fEFlagsIn;
9232 TestData.fEFlagsOut = fEFlagsOut;
9233 TestData.bImm = (uint8_t)u16Imm;
9234 RTStrmWrite(pStrmOut, &TestData, sizeof(TestData));
9235 }
9236 }
9237 }
9238 rc = RTStrmClose(pStrmOut);
9239 if (RT_FAILURE(rc))
9240 {
9241 RTMsgError("Failed to close data file for %s: %Rrc", g_aSsePcmpestrm[iFn].pszName, rc);
9242 return RTEXITCODE_FAILURE;
9243 }
9244 }
9245
9246 return RTEXITCODE_SUCCESS;
9247}
9248#endif
9249
9250static void SseComparePcmpestrmTest(void)
9251{
9252 X86FXSTATE State;
9253 RT_ZERO(State);
9254
9255 for (size_t iFn = 0; iFn < RT_ELEMENTS(g_aSsePcmpestrm); iFn++)
9256 {
9257 if (!SubTestAndCheckIfEnabled(g_aSsePcmpestrm[iFn].pszName))
9258 continue;
9259
9260 uint32_t const cTests = *g_aSsePcmpestrm[iFn].pcTests;
9261 SSE_PCMPESTRM_TEST_T const * const paTests = g_aSsePcmpestrm[iFn].paTests;
9262 PFNIEMAIMPLPCMPESTRMU128IMM8 pfn = g_aSsePcmpestrm[iFn].pfn;
9263 uint32_t const cVars = COUNT_VARIATIONS(g_aSsePcmpestrm[iFn]);
9264 if (!cTests) RTTestSkipped(g_hTest, "no tests");
9265 for (uint32_t iVar = 0; iVar < cVars; iVar++)
9266 {
9267 for (uint32_t iTest = 0; iTest < cTests / sizeof(*paTests); iTest++)
9268 {
9269 IEMPCMPESTRXSRC TestVal;
9270 TestVal.uSrc1 = paTests[iTest].InVal1.uXmm;
9271 TestVal.uSrc2 = paTests[iTest].InVal2.uXmm;
9272 TestVal.u64Rax = paTests[iTest].u64Rax;
9273 TestVal.u64Rdx = paTests[iTest].u64Rdx;
9274
9275 uint32_t fEFlags = paTests[iTest].fEFlagsIn;
9276 RTUINT128U OutVal;
9277 pfn(&OutVal, &fEFlags, &TestVal, paTests[iTest].bImm);
9278 if ( fEFlags != paTests[iTest].fEFlagsOut
9279 || OutVal.s.Hi != paTests[iTest].OutVal.uXmm.s.Hi
9280 || OutVal.s.Lo != paTests[iTest].OutVal.uXmm.s.Lo)
9281 RTTestFailed(g_hTest, "#%04u%s: efl=%#08x in1=%s rax1=%RI64 in2=%s rdx2=%RI64 bImm=%#x\n"
9282 "%s -> efl=%#08x %s\n"
9283 "%s expected %#08x %s%s%s\n",
9284 iTest, iVar ? "/n" : "", paTests[iTest].fEFlagsIn,
9285 FormatU128(&paTests[iTest].InVal1.uXmm), paTests[iTest].u64Rax,
9286 FormatU128(&paTests[iTest].InVal2.uXmm), paTests[iTest].u64Rdx,
9287 paTests[iTest].bImm,
9288 iVar ? " " : "", fEFlags, FormatU128(&OutVal),
9289 iVar ? " " : "", paTests[iTest].fEFlagsOut, FormatU128(&paTests[iTest].OutVal.uXmm),
9290 EFlagsDiff(fEFlags, paTests[iTest].fEFlagsOut),
9291 ( OutVal.s.Hi != paTests[iTest].OutVal.uXmm.s.Hi
9292 || OutVal.s.Lo != paTests[iTest].OutVal.uXmm.s.Lo) ? " - val" : "");
9293 }
9294 }
9295 }
9296}
9297
9298
9299
9300int main(int argc, char **argv)
9301{
9302 int rc = RTR3InitExe(argc, &argv, 0);
9303 if (RT_FAILURE(rc))
9304 return RTMsgInitFailure(rc);
9305
9306 /*
9307 * Determin the host CPU.
9308 * If not using the IEMAllAImpl.asm code, this will be set to Intel.
9309 */
9310#if (defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && !defined(IEM_WITHOUT_ASSEMBLY)
9311 g_idxCpuEflFlavour = ASMIsAmdCpu() || ASMIsHygonCpu()
9312 ? IEMTARGETCPU_EFL_BEHAVIOR_AMD
9313 : IEMTARGETCPU_EFL_BEHAVIOR_INTEL;
9314#else
9315 g_idxCpuEflFlavour = IEMTARGETCPU_EFL_BEHAVIOR_INTEL;
9316#endif
9317
9318 /*
9319 * Parse arguments.
9320 */
9321 enum { kModeNotSet, kModeTest, kModeGenerate }
9322 enmMode = kModeNotSet;
9323 bool fInt = true;
9324 bool fFpuLdSt = true;
9325 bool fFpuBinary1 = true;
9326 bool fFpuBinary2 = true;
9327 bool fFpuOther = true;
9328 bool fCpuData = true;
9329 bool fCommonData = true;
9330 bool fSseFpBinary = true;
9331 bool fSseFpOther = true;
9332 bool fSsePcmpxstrx = true;
9333 uint32_t const cDefaultTests = 96;
9334 uint32_t cTests = cDefaultTests;
9335 RTGETOPTDEF const s_aOptions[] =
9336 {
9337 // mode:
9338 { "--generate", 'g', RTGETOPT_REQ_NOTHING },
9339 { "--test", 't', RTGETOPT_REQ_NOTHING },
9340 // test selection (both)
9341 { "--all", 'a', RTGETOPT_REQ_NOTHING },
9342 { "--none", 'z', RTGETOPT_REQ_NOTHING },
9343 { "--zap", 'z', RTGETOPT_REQ_NOTHING },
9344 { "--fpu-ld-st", 'F', RTGETOPT_REQ_NOTHING }, /* FPU stuff is upper case */
9345 { "--fpu-load-store", 'F', RTGETOPT_REQ_NOTHING },
9346 { "--fpu-binary-1", 'B', RTGETOPT_REQ_NOTHING },
9347 { "--fpu-binary-2", 'P', RTGETOPT_REQ_NOTHING },
9348 { "--fpu-other", 'O', RTGETOPT_REQ_NOTHING },
9349 { "--sse-fp-binary", 'S', RTGETOPT_REQ_NOTHING },
9350 { "--sse-fp-other", 'T', RTGETOPT_REQ_NOTHING },
9351 { "--sse-pcmpxstrx", 'C', RTGETOPT_REQ_NOTHING },
9352 { "--int", 'i', RTGETOPT_REQ_NOTHING },
9353 { "--include", 'I', RTGETOPT_REQ_STRING },
9354 { "--exclude", 'X', RTGETOPT_REQ_STRING },
9355 // generation parameters
9356 { "--common", 'm', RTGETOPT_REQ_NOTHING },
9357 { "--cpu", 'c', RTGETOPT_REQ_NOTHING },
9358 { "--number-of-tests", 'n', RTGETOPT_REQ_UINT32 },
9359 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
9360 { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
9361 };
9362
9363 RTGETOPTSTATE State;
9364 rc = RTGetOptInit(&State, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
9365 AssertRCReturn(rc, RTEXITCODE_FAILURE);
9366
9367 RTGETOPTUNION ValueUnion;
9368 while ((rc = RTGetOpt(&State, &ValueUnion)))
9369 {
9370 switch (rc)
9371 {
9372 case 'g':
9373 enmMode = kModeGenerate;
9374 break;
9375 case 't':
9376 enmMode = kModeTest;
9377 break;
9378
9379 case 'a':
9380 fCpuData = true;
9381 fCommonData = true;
9382 fInt = true;
9383 fFpuLdSt = true;
9384 fFpuBinary1 = true;
9385 fFpuBinary2 = true;
9386 fFpuOther = true;
9387 fSseFpBinary = true;
9388 fSseFpOther = true;
9389 fSsePcmpxstrx = true;
9390 break;
9391 case 'z':
9392 fCpuData = false;
9393 fCommonData = false;
9394 fInt = false;
9395 fFpuLdSt = false;
9396 fFpuBinary1 = false;
9397 fFpuBinary2 = false;
9398 fFpuOther = false;
9399 fSseFpBinary = false;
9400 fSseFpOther = false;
9401 fSsePcmpxstrx = false;
9402 break;
9403
9404 case 'F':
9405 fFpuLdSt = true;
9406 break;
9407 case 'O':
9408 fFpuOther = true;
9409 break;
9410 case 'B':
9411 fFpuBinary1 = true;
9412 break;
9413 case 'P':
9414 fFpuBinary2 = true;
9415 break;
9416 case 'S':
9417 fSseFpBinary = true;
9418 break;
9419 case 'T':
9420 fSseFpOther = true;
9421 break;
9422 case 'C':
9423 fSsePcmpxstrx = true;
9424 break;
9425 case 'i':
9426 fInt = true;
9427 break;
9428
9429 case 'I':
9430 if (g_cIncludeTestPatterns >= RT_ELEMENTS(g_apszIncludeTestPatterns))
9431 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many include patterns (max %zu)",
9432 RT_ELEMENTS(g_apszIncludeTestPatterns));
9433 g_apszIncludeTestPatterns[g_cIncludeTestPatterns++] = ValueUnion.psz;
9434 break;
9435 case 'X':
9436 if (g_cExcludeTestPatterns >= RT_ELEMENTS(g_apszExcludeTestPatterns))
9437 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many exclude patterns (max %zu)",
9438 RT_ELEMENTS(g_apszExcludeTestPatterns));
9439 g_apszExcludeTestPatterns[g_cExcludeTestPatterns++] = ValueUnion.psz;
9440 break;
9441
9442 case 'm':
9443 fCommonData = true;
9444 break;
9445 case 'c':
9446 fCpuData = true;
9447 break;
9448 case 'n':
9449 cTests = ValueUnion.u32;
9450 break;
9451
9452 case 'q':
9453 g_cVerbosity = 0;
9454 break;
9455 case 'v':
9456 g_cVerbosity++;
9457 break;
9458
9459 case 'h':
9460 RTPrintf("usage: %s <-g|-t> [options]\n"
9461 "\n"
9462 "Mode:\n"
9463 " -g, --generate\n"
9464 " Generate test data.\n"
9465 " -t, --test\n"
9466 " Execute tests.\n"
9467 "\n"
9468 "Test selection (both modes):\n"
9469 " -a, --all\n"
9470 " Enable all tests and generated test data. (default)\n"
9471 " -z, --zap, --none\n"
9472 " Disable all tests and test data types.\n"
9473 " -i, --int\n"
9474 " Enable non-FPU tests.\n"
9475 " -F, --fpu-ld-st\n"
9476 " Enable FPU load and store tests.\n"
9477 " -B, --fpu-binary-1\n"
9478 " Enable FPU binary 80-bit FP tests.\n"
9479 " -P, --fpu-binary-2\n"
9480 " Enable FPU binary 64- and 32-bit FP tests.\n"
9481 " -O, --fpu-other\n"
9482 " Enable FPU binary 64- and 32-bit FP tests.\n"
9483 " -S, --sse-fp-binary\n"
9484 " Enable SSE binary 64- and 32-bit FP tests.\n"
9485 " -T, --sse-fp-other\n"
9486 " Enable misc SSE 64- and 32-bit FP tests.\n"
9487 " -C, --sse-pcmpxstrx\n"
9488 " Enable SSE pcmpxstrx tests.\n"
9489 " -I,--include=<test-patter>\n"
9490 " Enable tests matching the given pattern.\n"
9491 " -X,--exclude=<test-patter>\n"
9492 " Skip tests matching the given pattern (overrides --include).\n"
9493 "\n"
9494 "Generation:\n"
9495 " -m, --common\n"
9496 " Enable generating common test data.\n"
9497 " -c, --only-cpu\n"
9498 " Enable generating CPU specific test data.\n"
9499 " -n, --number-of-test <count>\n"
9500 " Number of tests to generate. Default: %u\n"
9501 "\n"
9502 "Other:\n"
9503 " -v, --verbose\n"
9504 " -q, --quiet\n"
9505 " Noise level. Default: --quiet\n"
9506 , argv[0], cDefaultTests);
9507 return RTEXITCODE_SUCCESS;
9508 default:
9509 return RTGetOptPrintError(rc, &ValueUnion);
9510 }
9511 }
9512
9513 /*
9514 * Generate data?
9515 */
9516 if (enmMode == kModeGenerate)
9517 {
9518#ifdef TSTIEMAIMPL_WITH_GENERATOR
9519 char szCpuDesc[256] = {0};
9520 RTMpGetDescription(NIL_RTCPUID, szCpuDesc, sizeof(szCpuDesc));
9521 const char * const pszCpuType = g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD ? "Amd" : "Intel";
9522# if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
9523 const char * const pszBitBucket = "NUL";
9524# else
9525 const char * const pszBitBucket = "/dev/null";
9526# endif
9527
9528 if (cTests == 0)
9529 cTests = cDefaultTests;
9530 g_cZeroDstTests = RT_MIN(cTests / 16, 32);
9531 g_cZeroSrcTests = g_cZeroDstTests * 2;
9532
9533 if (fInt)
9534 {
9535 const char *pszDataFile = fCommonData ? "tstIEMAImplDataInt.cpp" : pszBitBucket;
9536 PRTSTREAM pStrmData = GenerateOpenWithHdr(pszDataFile, szCpuDesc, NULL);
9537 const char *pszDataCpuFile = !fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
9538 ? "tstIEMAImplDataInt-Amd.cpp" : "tstIEMAImplDataInt-Intel.cpp";
9539 PRTSTREAM pStrmDataCpu = GenerateOpenWithHdr(pszDataCpuFile, szCpuDesc, pszCpuType);
9540 if (!pStrmData || !pStrmDataCpu)
9541 return RTEXITCODE_FAILURE;
9542
9543 BinU8Generate( pStrmData, pStrmDataCpu, cTests);
9544 BinU16Generate(pStrmData, pStrmDataCpu, cTests);
9545 BinU32Generate(pStrmData, pStrmDataCpu, cTests);
9546 BinU64Generate(pStrmData, pStrmDataCpu, cTests);
9547 ShiftDblGenerate(pStrmDataCpu, RT_MAX(cTests, 128));
9548 UnaryGenerate(pStrmData, cTests);
9549 ShiftGenerate(pStrmDataCpu, cTests);
9550 MulDivGenerate(pStrmDataCpu, cTests);
9551
9552 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile,
9553 GenerateFooterAndClose(pStrmData, pszDataFile, RTEXITCODE_SUCCESS));
9554 if (rcExit != RTEXITCODE_SUCCESS)
9555 return rcExit;
9556 }
9557
9558 if (fFpuLdSt)
9559 {
9560 const char *pszDataFile = fCommonData ? "tstIEMAImplDataFpuLdSt.cpp" : pszBitBucket;
9561 PRTSTREAM pStrmData = GenerateOpenWithHdr(pszDataFile, szCpuDesc, NULL);
9562 const char *pszDataCpuFile = !fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
9563 ? "tstIEMAImplDataFpuLdSt-Amd.cpp" : "tstIEMAImplDataFpuLdSt-Intel.cpp";
9564 PRTSTREAM pStrmDataCpu = GenerateOpenWithHdr(pszDataCpuFile, szCpuDesc, pszCpuType);
9565 if (!pStrmData || !pStrmDataCpu)
9566 return RTEXITCODE_FAILURE;
9567
9568 FpuLdConstGenerate(pStrmData, cTests);
9569 FpuLdIntGenerate(pStrmData, cTests);
9570 FpuLdD80Generate(pStrmData, cTests);
9571 FpuStIntGenerate(pStrmData, pStrmDataCpu, cTests);
9572 FpuStD80Generate(pStrmData, cTests);
9573 uint32_t const cTests2 = RT_MAX(cTests, 384); /* need better coverage for the next ones. */
9574 FpuLdMemGenerate(pStrmData, cTests2);
9575 FpuStMemGenerate(pStrmData, cTests2);
9576
9577 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile,
9578 GenerateFooterAndClose(pStrmData, pszDataFile, RTEXITCODE_SUCCESS));
9579 if (rcExit != RTEXITCODE_SUCCESS)
9580 return rcExit;
9581 }
9582
9583 if (fFpuBinary1)
9584 {
9585 const char *pszDataFile = fCommonData ? "tstIEMAImplDataFpuBinary1.cpp" : pszBitBucket;
9586 PRTSTREAM pStrmData = GenerateOpenWithHdr(pszDataFile, szCpuDesc, NULL);
9587 const char *pszDataCpuFile = !fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
9588 ? "tstIEMAImplDataFpuBinary1-Amd.cpp" : "tstIEMAImplDataFpuBinary1-Intel.cpp";
9589 PRTSTREAM pStrmDataCpu = GenerateOpenWithHdr(pszDataCpuFile, szCpuDesc, pszCpuType);
9590 if (!pStrmData || !pStrmDataCpu)
9591 return RTEXITCODE_FAILURE;
9592
9593 FpuBinaryR80Generate(pStrmData, pStrmDataCpu, cTests);
9594 FpuBinaryFswR80Generate(pStrmData, cTests);
9595 FpuBinaryEflR80Generate(pStrmData, cTests);
9596
9597 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile,
9598 GenerateFooterAndClose(pStrmData, pszDataFile, RTEXITCODE_SUCCESS));
9599 if (rcExit != RTEXITCODE_SUCCESS)
9600 return rcExit;
9601 }
9602
9603 if (fFpuBinary2)
9604 {
9605 const char *pszDataFile = fCommonData ? "tstIEMAImplDataFpuBinary2.cpp" : pszBitBucket;
9606 PRTSTREAM pStrmData = GenerateOpenWithHdr(pszDataFile, szCpuDesc, NULL);
9607 const char *pszDataCpuFile = pszBitBucket; /*!fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
9608 ? "tstIEMAImplDataFpuBinary2-Amd.cpp" : "tstIEMAImplDataFpuBinary2-Intel.cpp"; */
9609 PRTSTREAM pStrmDataCpu = GenerateOpenWithHdr(pszDataCpuFile, szCpuDesc, pszCpuType);
9610 if (!pStrmData || !pStrmDataCpu)
9611 return RTEXITCODE_FAILURE;
9612
9613 FpuBinaryR64Generate(pStrmData, cTests);
9614 FpuBinaryR32Generate(pStrmData, cTests);
9615 FpuBinaryI32Generate(pStrmData, cTests);
9616 FpuBinaryI16Generate(pStrmData, cTests);
9617 FpuBinaryFswR64Generate(pStrmData, cTests);
9618 FpuBinaryFswR32Generate(pStrmData, cTests);
9619 FpuBinaryFswI32Generate(pStrmData, cTests);
9620 FpuBinaryFswI16Generate(pStrmData, cTests);
9621
9622 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile,
9623 GenerateFooterAndClose(pStrmData, pszDataFile, RTEXITCODE_SUCCESS));
9624 if (rcExit != RTEXITCODE_SUCCESS)
9625 return rcExit;
9626 }
9627
9628 if (fFpuOther)
9629 {
9630 const char *pszDataFile = fCommonData ? "tstIEMAImplDataFpuOther.cpp" : pszBitBucket;
9631 PRTSTREAM pStrmData = GenerateOpenWithHdr(pszDataFile, szCpuDesc, NULL);
9632 const char *pszDataCpuFile = !fCpuData ? pszBitBucket : g_idxCpuEflFlavour == IEMTARGETCPU_EFL_BEHAVIOR_AMD
9633 ? "tstIEMAImplDataFpuOther-Amd.cpp" : "tstIEMAImplDataFpuOther-Intel.cpp";
9634 PRTSTREAM pStrmDataCpu = GenerateOpenWithHdr(pszDataCpuFile, szCpuDesc, pszCpuType);
9635 if (!pStrmData || !pStrmDataCpu)
9636 return RTEXITCODE_FAILURE;
9637
9638 FpuUnaryR80Generate(pStrmData, pStrmDataCpu, cTests);
9639 FpuUnaryFswR80Generate(pStrmData, pStrmDataCpu, cTests);
9640 FpuUnaryTwoR80Generate(pStrmData, pStrmDataCpu, cTests);
9641
9642 RTEXITCODE rcExit = GenerateFooterAndClose(pStrmDataCpu, pszDataCpuFile,
9643 GenerateFooterAndClose(pStrmData, pszDataFile, RTEXITCODE_SUCCESS));
9644 if (rcExit != RTEXITCODE_SUCCESS)
9645 return rcExit;
9646 }
9647
9648 if (fSseFpBinary)
9649 {
9650 const char *pszDataFileFmt = fCommonData ? "tstIEMAImplDataSseBinary-%s.bin" : pszBitBucket;
9651
9652 RTEXITCODE rcExit = SseBinaryR32Generate(pszDataFileFmt, cTests);
9653 if (rcExit == RTEXITCODE_SUCCESS)
9654 rcExit = SseBinaryR64Generate(pszDataFileFmt, cTests);
9655 if (rcExit == RTEXITCODE_SUCCESS)
9656 rcExit = SseBinaryU128R32Generate(pszDataFileFmt, cTests);
9657 if (rcExit == RTEXITCODE_SUCCESS)
9658 rcExit = SseBinaryU128R64Generate(pszDataFileFmt, cTests);
9659
9660 if (rcExit == RTEXITCODE_SUCCESS)
9661 rcExit = SseBinaryI32R64Generate(pszDataFileFmt, cTests);
9662 if (rcExit == RTEXITCODE_SUCCESS)
9663 rcExit = SseBinaryI64R64Generate(pszDataFileFmt, cTests);
9664 if (rcExit == RTEXITCODE_SUCCESS)
9665 rcExit = SseBinaryI32R32Generate(pszDataFileFmt, cTests);
9666 if (rcExit == RTEXITCODE_SUCCESS)
9667 rcExit = SseBinaryI64R32Generate(pszDataFileFmt, cTests);
9668
9669 if (rcExit == RTEXITCODE_SUCCESS)
9670 rcExit = SseBinaryR64I32Generate(pszDataFileFmt, cTests);
9671 if (rcExit == RTEXITCODE_SUCCESS)
9672 rcExit = SseBinaryR64I64Generate(pszDataFileFmt, cTests);
9673 if (rcExit == RTEXITCODE_SUCCESS)
9674 rcExit = SseBinaryR32I32Generate(pszDataFileFmt, cTests);
9675 if (rcExit == RTEXITCODE_SUCCESS)
9676 rcExit = SseBinaryR32I64Generate(pszDataFileFmt, cTests);
9677 if (rcExit != RTEXITCODE_SUCCESS)
9678 return rcExit;
9679 }
9680
9681 if (fSseFpOther)
9682 {
9683 const char *pszDataFileFmtCmp = fCommonData ? "tstIEMAImplDataSseCompare-%s.bin" : pszBitBucket;
9684 const char *pszDataFileFmtConv = fCommonData ? "tstIEMAImplDataSseConvert-%s.bin" : pszBitBucket;
9685
9686 RTEXITCODE rcExit = SseCompareEflR32R32Generate(pszDataFileFmtCmp, cTests);
9687 if (rcExit == RTEXITCODE_SUCCESS)
9688 rcExit = SseCompareEflR64R64Generate(pszDataFileFmtCmp, cTests);
9689 if (rcExit == RTEXITCODE_SUCCESS)
9690 rcExit = SseCompareF2XmmR32Imm8Generate(pszDataFileFmtCmp, cTests);
9691 if (rcExit == RTEXITCODE_SUCCESS)
9692 rcExit = SseCompareF2XmmR64Imm8Generate(pszDataFileFmtCmp, cTests);
9693 if (rcExit == RTEXITCODE_SUCCESS)
9694 rcExit = SseConvertXmmI32R32Generate(pszDataFileFmtConv, cTests);
9695 if (rcExit == RTEXITCODE_SUCCESS)
9696 rcExit = SseConvertXmmR32I32Generate(pszDataFileFmtConv, cTests);
9697 if (rcExit == RTEXITCODE_SUCCESS)
9698 rcExit = SseConvertXmmI32R64Generate(pszDataFileFmtConv, cTests);
9699 if (rcExit == RTEXITCODE_SUCCESS)
9700 rcExit = SseConvertXmmR64I32Generate(pszDataFileFmtConv, cTests);
9701 if (rcExit == RTEXITCODE_SUCCESS)
9702 rcExit = SseConvertMmXmmGenerate(pszDataFileFmtConv, cTests);
9703 if (rcExit == RTEXITCODE_SUCCESS)
9704 rcExit = SseConvertXmmR32MmGenerate(pszDataFileFmtConv, cTests);
9705 if (rcExit == RTEXITCODE_SUCCESS)
9706 rcExit = SseConvertXmmR64MmGenerate(pszDataFileFmtConv, cTests);
9707 if (rcExit == RTEXITCODE_SUCCESS)
9708 rcExit = SseConvertMmI32XmmR32Generate(pszDataFileFmtConv, cTests);
9709 if (rcExit != RTEXITCODE_SUCCESS)
9710 return rcExit;
9711 }
9712
9713 if (fSsePcmpxstrx)
9714 {
9715 const char *pszDataFileFmtCmp = fCommonData ? "tstIEMAImplDataSsePcmpxstrx-%s.bin" : pszBitBucket;
9716
9717 RTEXITCODE rcExit = SseComparePcmpistriGenerate(pszDataFileFmtCmp, cTests);
9718 if (rcExit == RTEXITCODE_SUCCESS)
9719 rcExit = SseComparePcmpistrmGenerate(pszDataFileFmtCmp, cTests);
9720 if (rcExit == RTEXITCODE_SUCCESS)
9721 rcExit = SseComparePcmpestriGenerate(pszDataFileFmtCmp, cTests);
9722 if (rcExit == RTEXITCODE_SUCCESS)
9723 rcExit = SseComparePcmpestrmGenerate(pszDataFileFmtCmp, cTests);
9724 if (rcExit != RTEXITCODE_SUCCESS)
9725 return rcExit;
9726 }
9727
9728 return RTEXITCODE_SUCCESS;
9729#else
9730 return RTMsgErrorExitFailure("Test data generator not compiled in!");
9731#endif
9732 }
9733
9734 /*
9735 * Do testing. Currrently disabled by default as data needs to be checked
9736 * on both intel and AMD systems first.
9737 */
9738 rc = RTTestCreate("tstIEMAimpl", &g_hTest);
9739 AssertRCReturn(rc, RTEXITCODE_FAILURE);
9740 if (enmMode == kModeTest)
9741 {
9742 RTTestBanner(g_hTest);
9743
9744 /* Allocate guarded memory for use in the tests. */
9745#define ALLOC_GUARDED_VAR(a_puVar) do { \
9746 rc = RTTestGuardedAlloc(g_hTest, sizeof(*a_puVar), sizeof(*a_puVar), false /*fHead*/, (void **)&a_puVar); \
9747 if (RT_FAILURE(rc)) RTTestFailed(g_hTest, "Failed to allocate guarded mem: " #a_puVar); \
9748 } while (0)
9749 ALLOC_GUARDED_VAR(g_pu8);
9750 ALLOC_GUARDED_VAR(g_pu16);
9751 ALLOC_GUARDED_VAR(g_pu32);
9752 ALLOC_GUARDED_VAR(g_pu64);
9753 ALLOC_GUARDED_VAR(g_pu128);
9754 ALLOC_GUARDED_VAR(g_pu8Two);
9755 ALLOC_GUARDED_VAR(g_pu16Two);
9756 ALLOC_GUARDED_VAR(g_pu32Two);
9757 ALLOC_GUARDED_VAR(g_pu64Two);
9758 ALLOC_GUARDED_VAR(g_pu128Two);
9759 ALLOC_GUARDED_VAR(g_pfEfl);
9760 if (RTTestErrorCount(g_hTest) == 0)
9761 {
9762 if (fInt)
9763 {
9764 BinU8Test();
9765 BinU16Test();
9766 BinU32Test();
9767 BinU64Test();
9768 XchgTest();
9769 XaddTest();
9770 CmpXchgTest();
9771 CmpXchg8bTest();
9772 CmpXchg16bTest();
9773 ShiftDblTest();
9774 UnaryTest();
9775 ShiftTest();
9776 MulDivTest();
9777 BswapTest();
9778 }
9779
9780 if (fFpuLdSt)
9781 {
9782 FpuLoadConstTest();
9783 FpuLdMemTest();
9784 FpuLdIntTest();
9785 FpuLdD80Test();
9786 FpuStMemTest();
9787 FpuStIntTest();
9788 FpuStD80Test();
9789 }
9790
9791 if (fFpuBinary1)
9792 {
9793 FpuBinaryR80Test();
9794 FpuBinaryFswR80Test();
9795 FpuBinaryEflR80Test();
9796 }
9797
9798 if (fFpuBinary2)
9799 {
9800 FpuBinaryR64Test();
9801 FpuBinaryR32Test();
9802 FpuBinaryI32Test();
9803 FpuBinaryI16Test();
9804 FpuBinaryFswR64Test();
9805 FpuBinaryFswR32Test();
9806 FpuBinaryFswI32Test();
9807 FpuBinaryFswI16Test();
9808 }
9809
9810 if (fFpuOther)
9811 {
9812 FpuUnaryR80Test();
9813 FpuUnaryFswR80Test();
9814 FpuUnaryTwoR80Test();
9815 }
9816
9817 if (fSseFpBinary)
9818 {
9819 SseBinaryR32Test();
9820 SseBinaryR64Test();
9821 SseBinaryU128R32Test();
9822 SseBinaryU128R64Test();
9823
9824 SseBinaryI32R64Test();
9825 SseBinaryI64R64Test();
9826 SseBinaryI32R32Test();
9827 SseBinaryI64R32Test();
9828
9829 SseBinaryR64I32Test();
9830 SseBinaryR64I64Test();
9831 SseBinaryR32I32Test();
9832 SseBinaryR32I64Test();
9833 }
9834
9835 if (fSseFpOther)
9836 {
9837 SseCompareEflR32R32Test();
9838 SseCompareEflR64R64Test();
9839 SseCompareEflR64R64Test();
9840 SseCompareF2XmmR32Imm8Test();
9841 SseCompareF2XmmR64Imm8Test();
9842 SseConvertXmmI32R32Test();
9843 SseConvertXmmR32I32Test();
9844 SseConvertXmmI32R64Test();
9845 SseConvertXmmR64I32Test();
9846 SseConvertMmXmmTest();
9847 SseConvertXmmR32MmTest();
9848 SseConvertXmmR64MmTest();
9849 SseConvertMmI32XmmR32Test();
9850 }
9851
9852 if (fSsePcmpxstrx)
9853 {
9854 SseComparePcmpistriTest();
9855 SseComparePcmpistrmTest();
9856 SseComparePcmpestriTest();
9857 SseComparePcmpestrmTest();
9858 }
9859 }
9860 return RTTestSummaryAndDestroy(g_hTest);
9861 }
9862 return RTTestSkipAndDestroy(g_hTest, "unfinished testcase");
9863}
9864
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