VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTInlineAsm.cpp@ 71674

Last change on this file since 71674 was 71674, checked in by vboxsync, 7 years ago

tstRTInlineAsm.cpp: leavs 0x0f and 0x10 also depend on ECX input..

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 73.9 KB
Line 
1/* $Id: tstRTInlineAsm.cpp 71674 2018-04-05 11:39:15Z vboxsync $ */
2/** @file
3 * IPRT Testcase - inline assembly.
4 */
5
6/*
7 * Copyright (C) 2006-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/asm.h>
32#include <iprt/asm-math.h>
33
34/* See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44018. Only gcc version 4.4
35 * is affected. No harm for the VBox code: If the cpuid code compiles, it works
36 * fine. */
37#if defined(__GNUC__) && defined(RT_ARCH_X86) && defined(__PIC__)
38# if __GNUC__ == 4 && __GNUC_MINOR__ == 4
39# define GCC44_32BIT_PIC
40# endif
41#endif
42
43#if !defined(GCC44_32BIT_PIC) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86))
44# include <iprt/asm-amd64-x86.h>
45# include <iprt/x86.h>
46#else
47# include <iprt/time.h>
48#endif
49#include <iprt/rand.h>
50#include <iprt/stream.h>
51#include <iprt/string.h>
52#include <iprt/param.h>
53#include <iprt/thread.h>
54#include <iprt/test.h>
55#include <iprt/time.h>
56
57
58
59/*********************************************************************************************************************************
60* Defined Constants And Macros *
61*********************************************************************************************************************************/
62#define CHECKVAL(val, expect, fmt) \
63 do \
64 { \
65 if ((val) != (expect)) \
66 { \
67 RTTestFailed(g_hTest, "%s, %d: " #val ": expected " fmt " got " fmt "\n", __FUNCTION__, __LINE__, (expect), (val)); \
68 } \
69 } while (0)
70
71#define CHECKOP(op, expect, fmt, type) \
72 do \
73 { \
74 type val = op; \
75 if (val != (type)(expect)) \
76 { \
77 RTTestFailed(g_hTest, "%s, %d: " #op ": expected " fmt " got " fmt "\n", __FUNCTION__, __LINE__, (type)(expect), val); \
78 } \
79 } while (0)
80
81/**
82 * Calls a worker function with different worker variable storage types.
83 */
84#define DO_SIMPLE_TEST(name, type) \
85 do \
86 { \
87 RTTestISub(#name); \
88 type StackVar; \
89 tst ## name ## Worker(&StackVar); \
90 \
91 type *pVar = (type *)RTTestGuardedAllocHead(g_hTest, sizeof(type)); \
92 RTTEST_CHECK_BREAK(g_hTest, pVar); \
93 tst ## name ## Worker(pVar); \
94 RTTestGuardedFree(g_hTest, pVar); \
95 \
96 pVar = (type *)RTTestGuardedAllocTail(g_hTest, sizeof(type)); \
97 RTTEST_CHECK_BREAK(g_hTest, pVar); \
98 tst ## name ## Worker(pVar); \
99 RTTestGuardedFree(g_hTest, pVar); \
100 } while (0)
101
102
103/*********************************************************************************************************************************
104* Global Variables *
105*********************************************************************************************************************************/
106/** The test instance. */
107static RTTEST g_hTest;
108
109
110
111#if !defined(GCC44_32BIT_PIC) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86))
112
113const char *getCacheAss(unsigned u)
114{
115 if (u == 0)
116 return "res0 ";
117 if (u == 1)
118 return "direct";
119 if (u >= 256)
120 return "???";
121
122 char *pszRet;
123 RTStrAPrintf(&pszRet, "%d way", u); /* intentional leak! */
124 return pszRet;
125}
126
127
128const char *getL2CacheAss(unsigned u)
129{
130 switch (u)
131 {
132 case 0: return "off ";
133 case 1: return "direct";
134 case 2: return "2 way ";
135 case 3: return "res3 ";
136 case 4: return "4 way ";
137 case 5: return "res5 ";
138 case 6: return "8 way ";
139 case 7: return "res7 ";
140 case 8: return "16 way";
141 case 9: return "res9 ";
142 case 10: return "res10 ";
143 case 11: return "res11 ";
144 case 12: return "res12 ";
145 case 13: return "res13 ";
146 case 14: return "res14 ";
147 case 15: return "fully ";
148 default:
149 return "????";
150 }
151}
152
153
154/**
155 * Test and dump all possible info from the CPUID instruction.
156 *
157 * @remark Bits shared with the libc cpuid.c program. This all written by me, so no worries.
158 * @todo transform the dumping into a generic runtime function. We'll need it for logging!
159 */
160void tstASMCpuId(void)
161{
162 RTTestISub("ASMCpuId");
163
164 unsigned iBit;
165 struct
166 {
167 uint32_t uEBX, uEAX, uEDX, uECX;
168 } s;
169 if (!ASMHasCpuId())
170 {
171 RTTestIPrintf(RTTESTLVL_ALWAYS, "warning! CPU doesn't support CPUID\n");
172 return;
173 }
174
175 /*
176 * Try the 0 function and use that for checking the ASMCpuId_* variants.
177 */
178 ASMCpuId(0, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
179
180 uint32_t u32;
181
182 u32 = ASMCpuId_EAX(0);
183 CHECKVAL(u32, s.uEAX, "%x");
184 u32 = ASMCpuId_EBX(0);
185 CHECKVAL(u32, s.uEBX, "%x");
186 u32 = ASMCpuId_ECX(0);
187 CHECKVAL(u32, s.uECX, "%x");
188 u32 = ASMCpuId_EDX(0);
189 CHECKVAL(u32, s.uEDX, "%x");
190
191 uint32_t uECX2 = s.uECX - 1;
192 uint32_t uEDX2 = s.uEDX - 1;
193 ASMCpuId_ECX_EDX(0, &uECX2, &uEDX2);
194 CHECKVAL(uECX2, s.uECX, "%x");
195 CHECKVAL(uEDX2, s.uEDX, "%x");
196
197 uint32_t uEAX2 = s.uEAX - 1;
198 uint32_t uEBX2 = s.uEBX - 1;
199 uECX2 = s.uECX - 1;
200 uEDX2 = s.uEDX - 1;
201 ASMCpuIdExSlow(0, 0, 0, 0, &uEAX2, &uEBX2, &uECX2, &uEDX2);
202 CHECKVAL(uEAX2, s.uEAX, "%x");
203 CHECKVAL(uEBX2, s.uEBX, "%x");
204 CHECKVAL(uECX2, s.uECX, "%x");
205 CHECKVAL(uEDX2, s.uEDX, "%x");
206
207 /*
208 * Done testing, dump the information.
209 */
210 RTTestIPrintf(RTTESTLVL_ALWAYS, "CPUID Dump\n");
211 ASMCpuId(0, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
212 const uint32_t cFunctions = s.uEAX;
213
214 /* raw dump */
215 RTTestIPrintf(RTTESTLVL_ALWAYS,
216 "\n"
217 " RAW Standard CPUIDs\n"
218 "Function eax ebx ecx edx\n");
219 for (unsigned iStd = 0; iStd <= cFunctions + 3; iStd++)
220 {
221 ASMCpuId_Idx_ECX(iStd, 0, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
222 RTTestIPrintf(RTTESTLVL_ALWAYS, "%08x %08x %08x %08x %08x%s\n",
223 iStd, s.uEAX, s.uEBX, s.uECX, s.uEDX, iStd <= cFunctions ? "" : "*");
224
225 /* Some leafs output depend on the initial value of ECX.
226 * The same seems to apply to invalid standard functions */
227 if (iStd > cFunctions)
228 continue;
229 if ( iStd != 0x04 /* Deterministic Cache Parameters Leaf */
230 && iStd != 0x07 /* Structured Extended Feature Flags */
231 && iStd != 0x0b /* Extended Topology Enumeration Leafs */
232 && iStd != 0x0d /* Extended State Enumeration Leafs */
233 && iStd != 0x0f /* Platform qualifity of service monitoring (PQM) */
234 && iStd != 0x10 /* Platform qualifity of service enforcement (PQE) */
235 && iStd != 0x14 /* Trace Enumeration Leafs */)
236 {
237 u32 = ASMCpuId_EAX(iStd);
238 CHECKVAL(u32, s.uEAX, "%x");
239
240 uint32_t u32EbxMask = UINT32_MAX;
241 if (iStd == 1)
242 u32EbxMask = UINT32_C(0x00ffffff); /* Omit the local apic ID in case we're rescheduled. */
243 u32 = ASMCpuId_EBX(iStd);
244 CHECKVAL(u32 & u32EbxMask, s.uEBX & u32EbxMask, "%x");
245
246 u32 = ASMCpuId_ECX(iStd);
247 CHECKVAL(u32, s.uECX, "%x");
248 u32 = ASMCpuId_EDX(iStd);
249 CHECKVAL(u32, s.uEDX, "%x");
250
251 uECX2 = s.uECX - 1;
252 uEDX2 = s.uEDX - 1;
253 ASMCpuId_ECX_EDX(iStd, &uECX2, &uEDX2);
254 CHECKVAL(uECX2, s.uECX, "%x");
255 CHECKVAL(uEDX2, s.uEDX, "%x");
256 }
257
258 if (iStd == 0x04)
259 for (uint32_t uECX = 1; s.uEAX & 0x1f; uECX++)
260 {
261 ASMCpuId_Idx_ECX(iStd, uECX, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
262 RTTestIPrintf(RTTESTLVL_ALWAYS, " [%02x] %08x %08x %08x %08x\n", uECX, s.uEAX, s.uEBX, s.uECX, s.uEDX);
263 RTTESTI_CHECK_BREAK(uECX < 128);
264 }
265 else if (iStd == 0x07)
266 {
267 uint32_t uMax = s.uEAX;
268 for (uint32_t uECX = 1; uECX < uMax; uECX++)
269 {
270 ASMCpuId_Idx_ECX(iStd, uECX, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
271 RTTestIPrintf(RTTESTLVL_ALWAYS, " [%02x] %08x %08x %08x %08x\n", uECX, s.uEAX, s.uEBX, s.uECX, s.uEDX);
272 RTTESTI_CHECK_BREAK(uECX < 128);
273 }
274 }
275 else if (iStd == 0x0b)
276 for (uint32_t uECX = 1; (s.uEAX & 0x1f) && (s.uEBX & 0xffff); uECX++)
277 {
278 ASMCpuId_Idx_ECX(iStd, uECX, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
279 RTTestIPrintf(RTTESTLVL_ALWAYS, " [%02x] %08x %08x %08x %08x\n", uECX, s.uEAX, s.uEBX, s.uECX, s.uEDX);
280 RTTESTI_CHECK_BREAK(uECX < 128);
281 }
282 else if (iStd == 0x0d)
283 for (uint32_t uECX = 1; s.uEAX != 0 || s.uEBX != 0 || s.uECX != 0 || s.uEDX != 0; uECX++)
284 {
285 ASMCpuId_Idx_ECX(iStd, uECX, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
286 RTTestIPrintf(RTTESTLVL_ALWAYS, " [%02x] %08x %08x %08x %08x\n", uECX, s.uEAX, s.uEBX, s.uECX, s.uEDX);
287 RTTESTI_CHECK_BREAK(uECX < 128);
288 }
289 }
290
291 /*
292 * Understandable output
293 */
294 ASMCpuId(0, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
295 RTTestIPrintf(RTTESTLVL_ALWAYS,
296 "Name: %.04s%.04s%.04s\n"
297 "Support: 0-%u\n",
298 &s.uEBX, &s.uEDX, &s.uECX, s.uEAX);
299 bool const fIntel = ASMIsIntelCpuEx(s.uEBX, s.uECX, s.uEDX);
300
301 /*
302 * Get Features.
303 */
304 if (cFunctions >= 1)
305 {
306 static const char * const s_apszTypes[4] = { "primary", "overdrive", "MP", "reserved" };
307 ASMCpuId(1, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
308 RTTestIPrintf(RTTESTLVL_ALWAYS,
309 "Family: %#x \tExtended: %#x \tEffective: %#x\n"
310 "Model: %#x \tExtended: %#x \tEffective: %#x\n"
311 "Stepping: %d\n"
312 "Type: %d (%s)\n"
313 "APIC ID: %#04x\n"
314 "Logical CPUs: %d\n"
315 "CLFLUSH Size: %d\n"
316 "Brand ID: %#04x\n",
317 (s.uEAX >> 8) & 0xf, (s.uEAX >> 20) & 0x7f, ASMGetCpuFamily(s.uEAX),
318 (s.uEAX >> 4) & 0xf, (s.uEAX >> 16) & 0x0f, ASMGetCpuModel(s.uEAX, fIntel),
319 ASMGetCpuStepping(s.uEAX),
320 (s.uEAX >> 12) & 0x3, s_apszTypes[(s.uEAX >> 12) & 0x3],
321 (s.uEBX >> 24) & 0xff,
322 (s.uEBX >> 16) & 0xff,
323 (s.uEBX >> 8) & 0xff,
324 (s.uEBX >> 0) & 0xff);
325
326 RTTestIPrintf(RTTESTLVL_ALWAYS, "Features EDX: ");
327 if (s.uEDX & RT_BIT(0)) RTTestIPrintf(RTTESTLVL_ALWAYS, " FPU");
328 if (s.uEDX & RT_BIT(1)) RTTestIPrintf(RTTESTLVL_ALWAYS, " VME");
329 if (s.uEDX & RT_BIT(2)) RTTestIPrintf(RTTESTLVL_ALWAYS, " DE");
330 if (s.uEDX & RT_BIT(3)) RTTestIPrintf(RTTESTLVL_ALWAYS, " PSE");
331 if (s.uEDX & RT_BIT(4)) RTTestIPrintf(RTTESTLVL_ALWAYS, " TSC");
332 if (s.uEDX & RT_BIT(5)) RTTestIPrintf(RTTESTLVL_ALWAYS, " MSR");
333 if (s.uEDX & RT_BIT(6)) RTTestIPrintf(RTTESTLVL_ALWAYS, " PAE");
334 if (s.uEDX & RT_BIT(7)) RTTestIPrintf(RTTESTLVL_ALWAYS, " MCE");
335 if (s.uEDX & RT_BIT(8)) RTTestIPrintf(RTTESTLVL_ALWAYS, " CX8");
336 if (s.uEDX & RT_BIT(9)) RTTestIPrintf(RTTESTLVL_ALWAYS, " APIC");
337 if (s.uEDX & RT_BIT(10)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 10");
338 if (s.uEDX & RT_BIT(11)) RTTestIPrintf(RTTESTLVL_ALWAYS, " SEP");
339 if (s.uEDX & RT_BIT(12)) RTTestIPrintf(RTTESTLVL_ALWAYS, " MTRR");
340 if (s.uEDX & RT_BIT(13)) RTTestIPrintf(RTTESTLVL_ALWAYS, " PGE");
341 if (s.uEDX & RT_BIT(14)) RTTestIPrintf(RTTESTLVL_ALWAYS, " MCA");
342 if (s.uEDX & RT_BIT(15)) RTTestIPrintf(RTTESTLVL_ALWAYS, " CMOV");
343 if (s.uEDX & RT_BIT(16)) RTTestIPrintf(RTTESTLVL_ALWAYS, " PAT");
344 if (s.uEDX & RT_BIT(17)) RTTestIPrintf(RTTESTLVL_ALWAYS, " PSE36");
345 if (s.uEDX & RT_BIT(18)) RTTestIPrintf(RTTESTLVL_ALWAYS, " PSN");
346 if (s.uEDX & RT_BIT(19)) RTTestIPrintf(RTTESTLVL_ALWAYS, " CLFSH");
347 if (s.uEDX & RT_BIT(20)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 20");
348 if (s.uEDX & RT_BIT(21)) RTTestIPrintf(RTTESTLVL_ALWAYS, " DS");
349 if (s.uEDX & RT_BIT(22)) RTTestIPrintf(RTTESTLVL_ALWAYS, " ACPI");
350 if (s.uEDX & RT_BIT(23)) RTTestIPrintf(RTTESTLVL_ALWAYS, " MMX");
351 if (s.uEDX & RT_BIT(24)) RTTestIPrintf(RTTESTLVL_ALWAYS, " FXSR");
352 if (s.uEDX & RT_BIT(25)) RTTestIPrintf(RTTESTLVL_ALWAYS, " SSE");
353 if (s.uEDX & RT_BIT(26)) RTTestIPrintf(RTTESTLVL_ALWAYS, " SSE2");
354 if (s.uEDX & RT_BIT(27)) RTTestIPrintf(RTTESTLVL_ALWAYS, " SS");
355 if (s.uEDX & RT_BIT(28)) RTTestIPrintf(RTTESTLVL_ALWAYS, " HTT");
356 if (s.uEDX & RT_BIT(29)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 29");
357 if (s.uEDX & RT_BIT(30)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 30");
358 if (s.uEDX & RT_BIT(31)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 31");
359 RTTestIPrintf(RTTESTLVL_ALWAYS, "\n");
360
361 /** @todo check intel docs. */
362 RTTestIPrintf(RTTESTLVL_ALWAYS, "Features ECX: ");
363 if (s.uECX & RT_BIT(0)) RTTestIPrintf(RTTESTLVL_ALWAYS, " SSE3");
364 for (iBit = 1; iBit < 13; iBit++)
365 if (s.uECX & RT_BIT(iBit))
366 RTTestIPrintf(RTTESTLVL_ALWAYS, " %d", iBit);
367 if (s.uECX & RT_BIT(13)) RTTestIPrintf(RTTESTLVL_ALWAYS, " CX16");
368 for (iBit = 14; iBit < 32; iBit++)
369 if (s.uECX & RT_BIT(iBit))
370 RTTestIPrintf(RTTESTLVL_ALWAYS, " %d", iBit);
371 RTTestIPrintf(RTTESTLVL_ALWAYS, "\n");
372 }
373
374 /*
375 * Extended.
376 * Implemented after AMD specs.
377 */
378 /** @todo check out the intel specs. */
379 ASMCpuId(0x80000000, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
380 if (!s.uEAX && !s.uEBX && !s.uECX && !s.uEDX)
381 {
382 RTTestIPrintf(RTTESTLVL_ALWAYS, "No extended CPUID info? Check the manual on how to detect this...\n");
383 return;
384 }
385 const uint32_t cExtFunctions = s.uEAX | 0x80000000;
386
387 /* raw dump */
388 RTTestIPrintf(RTTESTLVL_ALWAYS,
389 "\n"
390 " RAW Extended CPUIDs\n"
391 "Function eax ebx ecx edx\n");
392 for (unsigned iExt = 0x80000000; iExt <= cExtFunctions + 3; iExt++)
393 {
394 ASMCpuId(iExt, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
395 RTTestIPrintf(RTTESTLVL_ALWAYS, "%08x %08x %08x %08x %08x%s\n",
396 iExt, s.uEAX, s.uEBX, s.uECX, s.uEDX, iExt <= cExtFunctions ? "" : "*");
397
398 if (iExt > cExtFunctions)
399 continue; /* Invalid extended functions seems change the value if ECX changes */
400 if (iExt == 0x8000001d)
401 continue; /* Takes cache level in ecx. */
402
403 u32 = ASMCpuId_EAX(iExt);
404 CHECKVAL(u32, s.uEAX, "%x");
405 u32 = ASMCpuId_EBX(iExt);
406 CHECKVAL(u32, s.uEBX, "%x");
407 u32 = ASMCpuId_ECX(iExt);
408 CHECKVAL(u32, s.uECX, "%x");
409 u32 = ASMCpuId_EDX(iExt);
410 CHECKVAL(u32, s.uEDX, "%x");
411
412 uECX2 = s.uECX - 1;
413 uEDX2 = s.uEDX - 1;
414 ASMCpuId_ECX_EDX(iExt, &uECX2, &uEDX2);
415 CHECKVAL(uECX2, s.uECX, "%x");
416 CHECKVAL(uEDX2, s.uEDX, "%x");
417 }
418
419 /*
420 * Understandable output
421 */
422 ASMCpuId(0x80000000, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
423 RTTestIPrintf(RTTESTLVL_ALWAYS,
424 "Ext Name: %.4s%.4s%.4s\n"
425 "Ext Supports: 0x80000000-%#010x\n",
426 &s.uEBX, &s.uEDX, &s.uECX, s.uEAX);
427
428 if (cExtFunctions >= 0x80000001)
429 {
430 ASMCpuId(0x80000001, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
431 RTTestIPrintf(RTTESTLVL_ALWAYS,
432 "Family: %#x \tExtended: %#x \tEffective: %#x\n"
433 "Model: %#x \tExtended: %#x \tEffective: %#x\n"
434 "Stepping: %d\n"
435 "Brand ID: %#05x\n",
436 (s.uEAX >> 8) & 0xf, (s.uEAX >> 20) & 0x7f, ASMGetCpuFamily(s.uEAX),
437 (s.uEAX >> 4) & 0xf, (s.uEAX >> 16) & 0x0f, ASMGetCpuModel(s.uEAX, fIntel),
438 ASMGetCpuStepping(s.uEAX),
439 s.uEBX & 0xfff);
440
441 RTTestIPrintf(RTTESTLVL_ALWAYS, "Features EDX: ");
442 if (s.uEDX & RT_BIT(0)) RTTestIPrintf(RTTESTLVL_ALWAYS, " FPU");
443 if (s.uEDX & RT_BIT(1)) RTTestIPrintf(RTTESTLVL_ALWAYS, " VME");
444 if (s.uEDX & RT_BIT(2)) RTTestIPrintf(RTTESTLVL_ALWAYS, " DE");
445 if (s.uEDX & RT_BIT(3)) RTTestIPrintf(RTTESTLVL_ALWAYS, " PSE");
446 if (s.uEDX & RT_BIT(4)) RTTestIPrintf(RTTESTLVL_ALWAYS, " TSC");
447 if (s.uEDX & RT_BIT(5)) RTTestIPrintf(RTTESTLVL_ALWAYS, " MSR");
448 if (s.uEDX & RT_BIT(6)) RTTestIPrintf(RTTESTLVL_ALWAYS, " PAE");
449 if (s.uEDX & RT_BIT(7)) RTTestIPrintf(RTTESTLVL_ALWAYS, " MCE");
450 if (s.uEDX & RT_BIT(8)) RTTestIPrintf(RTTESTLVL_ALWAYS, " CMPXCHG8B");
451 if (s.uEDX & RT_BIT(9)) RTTestIPrintf(RTTESTLVL_ALWAYS, " APIC");
452 if (s.uEDX & RT_BIT(10)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 10");
453 if (s.uEDX & RT_BIT(11)) RTTestIPrintf(RTTESTLVL_ALWAYS, " SysCallSysRet");
454 if (s.uEDX & RT_BIT(12)) RTTestIPrintf(RTTESTLVL_ALWAYS, " MTRR");
455 if (s.uEDX & RT_BIT(13)) RTTestIPrintf(RTTESTLVL_ALWAYS, " PGE");
456 if (s.uEDX & RT_BIT(14)) RTTestIPrintf(RTTESTLVL_ALWAYS, " MCA");
457 if (s.uEDX & RT_BIT(15)) RTTestIPrintf(RTTESTLVL_ALWAYS, " CMOV");
458 if (s.uEDX & RT_BIT(16)) RTTestIPrintf(RTTESTLVL_ALWAYS, " PAT");
459 if (s.uEDX & RT_BIT(17)) RTTestIPrintf(RTTESTLVL_ALWAYS, " PSE36");
460 if (s.uEDX & RT_BIT(18)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 18");
461 if (s.uEDX & RT_BIT(19)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 19");
462 if (s.uEDX & RT_BIT(20)) RTTestIPrintf(RTTESTLVL_ALWAYS, " NX");
463 if (s.uEDX & RT_BIT(21)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 21");
464 if (s.uEDX & RT_BIT(22)) RTTestIPrintf(RTTESTLVL_ALWAYS, " MmxExt");
465 if (s.uEDX & RT_BIT(23)) RTTestIPrintf(RTTESTLVL_ALWAYS, " MMX");
466 if (s.uEDX & RT_BIT(24)) RTTestIPrintf(RTTESTLVL_ALWAYS, " FXSR");
467 if (s.uEDX & RT_BIT(25)) RTTestIPrintf(RTTESTLVL_ALWAYS, " FastFXSR");
468 if (s.uEDX & RT_BIT(26)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 26");
469 if (s.uEDX & RT_BIT(27)) RTTestIPrintf(RTTESTLVL_ALWAYS, " RDTSCP");
470 if (s.uEDX & RT_BIT(28)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 28");
471 if (s.uEDX & RT_BIT(29)) RTTestIPrintf(RTTESTLVL_ALWAYS, " LongMode");
472 if (s.uEDX & RT_BIT(30)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 3DNowExt");
473 if (s.uEDX & RT_BIT(31)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 3DNow");
474 RTTestIPrintf(RTTESTLVL_ALWAYS, "\n");
475
476 RTTestIPrintf(RTTESTLVL_ALWAYS, "Features ECX: ");
477 if (s.uECX & RT_BIT(0)) RTTestIPrintf(RTTESTLVL_ALWAYS, " LahfSahf");
478 if (s.uECX & RT_BIT(1)) RTTestIPrintf(RTTESTLVL_ALWAYS, " CmpLegacy");
479 if (s.uECX & RT_BIT(2)) RTTestIPrintf(RTTESTLVL_ALWAYS, " SVM");
480 if (s.uECX & RT_BIT(3)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 3");
481 if (s.uECX & RT_BIT(4)) RTTestIPrintf(RTTESTLVL_ALWAYS, " AltMovCr8");
482 for (iBit = 5; iBit < 32; iBit++)
483 if (s.uECX & RT_BIT(iBit))
484 RTTestIPrintf(RTTESTLVL_ALWAYS, " %d", iBit);
485 RTTestIPrintf(RTTESTLVL_ALWAYS, "\n");
486 }
487
488 char szString[4*4*3+1] = {0};
489 if (cExtFunctions >= 0x80000002)
490 ASMCpuId(0x80000002, &szString[0 + 0], &szString[0 + 4], &szString[0 + 8], &szString[0 + 12]);
491 if (cExtFunctions >= 0x80000003)
492 ASMCpuId(0x80000003, &szString[16 + 0], &szString[16 + 4], &szString[16 + 8], &szString[16 + 12]);
493 if (cExtFunctions >= 0x80000004)
494 ASMCpuId(0x80000004, &szString[32 + 0], &szString[32 + 4], &szString[32 + 8], &szString[32 + 12]);
495 if (cExtFunctions >= 0x80000002)
496 RTTestIPrintf(RTTESTLVL_ALWAYS, "Full Name: %s\n", szString);
497
498 if (cExtFunctions >= 0x80000005)
499 {
500 ASMCpuId(0x80000005, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
501 RTTestIPrintf(RTTESTLVL_ALWAYS,
502 "TLB 2/4M Instr/Uni: %s %3d entries\n"
503 "TLB 2/4M Data: %s %3d entries\n",
504 getCacheAss((s.uEAX >> 8) & 0xff), (s.uEAX >> 0) & 0xff,
505 getCacheAss((s.uEAX >> 24) & 0xff), (s.uEAX >> 16) & 0xff);
506 RTTestIPrintf(RTTESTLVL_ALWAYS,
507 "TLB 4K Instr/Uni: %s %3d entries\n"
508 "TLB 4K Data: %s %3d entries\n",
509 getCacheAss((s.uEBX >> 8) & 0xff), (s.uEBX >> 0) & 0xff,
510 getCacheAss((s.uEBX >> 24) & 0xff), (s.uEBX >> 16) & 0xff);
511 RTTestIPrintf(RTTESTLVL_ALWAYS,
512 "L1 Instr Cache Line Size: %d bytes\n"
513 "L1 Instr Cache Lines Per Tag: %d\n"
514 "L1 Instr Cache Associativity: %s\n"
515 "L1 Instr Cache Size: %d KB\n",
516 (s.uEDX >> 0) & 0xff,
517 (s.uEDX >> 8) & 0xff,
518 getCacheAss((s.uEDX >> 16) & 0xff),
519 (s.uEDX >> 24) & 0xff);
520 RTTestIPrintf(RTTESTLVL_ALWAYS,
521 "L1 Data Cache Line Size: %d bytes\n"
522 "L1 Data Cache Lines Per Tag: %d\n"
523 "L1 Data Cache Associativity: %s\n"
524 "L1 Data Cache Size: %d KB\n",
525 (s.uECX >> 0) & 0xff,
526 (s.uECX >> 8) & 0xff,
527 getCacheAss((s.uECX >> 16) & 0xff),
528 (s.uECX >> 24) & 0xff);
529 }
530
531 if (cExtFunctions >= 0x80000006)
532 {
533 ASMCpuId(0x80000006, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
534 RTTestIPrintf(RTTESTLVL_ALWAYS,
535 "L2 TLB 2/4M Instr/Uni: %s %4d entries\n"
536 "L2 TLB 2/4M Data: %s %4d entries\n",
537 getL2CacheAss((s.uEAX >> 12) & 0xf), (s.uEAX >> 0) & 0xfff,
538 getL2CacheAss((s.uEAX >> 28) & 0xf), (s.uEAX >> 16) & 0xfff);
539 RTTestIPrintf(RTTESTLVL_ALWAYS,
540 "L2 TLB 4K Instr/Uni: %s %4d entries\n"
541 "L2 TLB 4K Data: %s %4d entries\n",
542 getL2CacheAss((s.uEBX >> 12) & 0xf), (s.uEBX >> 0) & 0xfff,
543 getL2CacheAss((s.uEBX >> 28) & 0xf), (s.uEBX >> 16) & 0xfff);
544 RTTestIPrintf(RTTESTLVL_ALWAYS,
545 "L2 Cache Line Size: %d bytes\n"
546 "L2 Cache Lines Per Tag: %d\n"
547 "L2 Cache Associativity: %s\n"
548 "L2 Cache Size: %d KB\n",
549 (s.uEDX >> 0) & 0xff,
550 (s.uEDX >> 8) & 0xf,
551 getL2CacheAss((s.uEDX >> 12) & 0xf),
552 (s.uEDX >> 16) & 0xffff);
553 }
554
555 if (cExtFunctions >= 0x80000007)
556 {
557 ASMCpuId(0x80000007, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
558 RTTestIPrintf(RTTESTLVL_ALWAYS, "APM Features: ");
559 if (s.uEDX & RT_BIT(0)) RTTestIPrintf(RTTESTLVL_ALWAYS, " TS");
560 if (s.uEDX & RT_BIT(1)) RTTestIPrintf(RTTESTLVL_ALWAYS, " FID");
561 if (s.uEDX & RT_BIT(2)) RTTestIPrintf(RTTESTLVL_ALWAYS, " VID");
562 if (s.uEDX & RT_BIT(3)) RTTestIPrintf(RTTESTLVL_ALWAYS, " TTP");
563 if (s.uEDX & RT_BIT(4)) RTTestIPrintf(RTTESTLVL_ALWAYS, " TM");
564 if (s.uEDX & RT_BIT(5)) RTTestIPrintf(RTTESTLVL_ALWAYS, " STC");
565 if (s.uEDX & RT_BIT(6)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 6");
566 if (s.uEDX & RT_BIT(7)) RTTestIPrintf(RTTESTLVL_ALWAYS, " 7");
567 if (s.uEDX & RT_BIT(8)) RTTestIPrintf(RTTESTLVL_ALWAYS, " TscInvariant");
568 for (iBit = 9; iBit < 32; iBit++)
569 if (s.uEDX & RT_BIT(iBit))
570 RTTestIPrintf(RTTESTLVL_ALWAYS, " %d", iBit);
571 RTTestIPrintf(RTTESTLVL_ALWAYS, "\n");
572 }
573
574 if (cExtFunctions >= 0x80000008)
575 {
576 ASMCpuId(0x80000008, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
577 RTTestIPrintf(RTTESTLVL_ALWAYS,
578 "Physical Address Width: %d bits\n"
579 "Virtual Address Width: %d bits\n"
580 "Guest Physical Address Width: %d bits\n",
581 (s.uEAX >> 0) & 0xff,
582 (s.uEAX >> 8) & 0xff,
583 (s.uEAX >> 16) & 0xff);
584 RTTestIPrintf(RTTESTLVL_ALWAYS,
585 "Physical Core Count: %d\n",
586 ((s.uECX >> 0) & 0xff) + 1);
587 if ((s.uECX >> 12) & 0xf)
588 RTTestIPrintf(RTTESTLVL_ALWAYS, "ApicIdCoreIdSize: %d bits\n", (s.uECX >> 12) & 0xf);
589 }
590
591 if (cExtFunctions >= 0x8000000a)
592 {
593 ASMCpuId(0x8000000a, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
594 RTTestIPrintf(RTTESTLVL_ALWAYS,
595 "SVM Revision: %d (%#x)\n"
596 "Number of Address Space IDs: %d (%#x)\n",
597 s.uEAX & 0xff, s.uEAX & 0xff,
598 s.uEBX, s.uEBX);
599 }
600}
601
602# if 0
603static void bruteForceCpuId(void)
604{
605 RTTestISub("brute force CPUID leafs");
606 uint32_t auPrevValues[4] = { 0, 0, 0, 0};
607 uint32_t uLeaf = 0;
608 do
609 {
610 uint32_t auValues[4];
611 ASMCpuIdExSlow(uLeaf, 0, 0, 0, &auValues[0], &auValues[1], &auValues[2], &auValues[3]);
612 if ( (auValues[0] != auPrevValues[0] && auValues[0] != uLeaf)
613 || (auValues[1] != auPrevValues[1] && auValues[1] != 0)
614 || (auValues[2] != auPrevValues[2] && auValues[2] != 0)
615 || (auValues[3] != auPrevValues[3] && auValues[3] != 0)
616 || (uLeaf & (UINT32_C(0x08000000) - UINT32_C(1))) == 0)
617 {
618 RTTestIPrintf(RTTESTLVL_ALWAYS,
619 "%08x: %08x %08x %08x %08x\n", uLeaf,
620 auValues[0], auValues[1], auValues[2], auValues[3]);
621 }
622 auPrevValues[0] = auValues[0];
623 auPrevValues[1] = auValues[1];
624 auPrevValues[2] = auValues[2];
625 auPrevValues[3] = auValues[3];
626
627 //uint32_t uSubLeaf = 0;
628 //do
629 //{
630 //
631 //
632 //} while (false);
633 } while (uLeaf++ < UINT32_MAX);
634}
635# endif
636
637#endif /* AMD64 || X86 */
638
639DECLINLINE(void) tstASMAtomicXchgU8Worker(uint8_t volatile *pu8)
640{
641 *pu8 = 0;
642 CHECKOP(ASMAtomicXchgU8(pu8, 1), 0, "%#x", uint8_t);
643 CHECKVAL(*pu8, 1, "%#x");
644
645 CHECKOP(ASMAtomicXchgU8(pu8, 0), 1, "%#x", uint8_t);
646 CHECKVAL(*pu8, 0, "%#x");
647
648 CHECKOP(ASMAtomicXchgU8(pu8, UINT8_C(0xff)), 0, "%#x", uint8_t);
649 CHECKVAL(*pu8, 0xff, "%#x");
650
651 CHECKOP(ASMAtomicXchgU8(pu8, UINT8_C(0x87)), UINT8_C(0xff), "%#x", uint8_t);
652 CHECKVAL(*pu8, 0x87, "%#x");
653}
654
655
656static void tstASMAtomicXchgU8(void)
657{
658 DO_SIMPLE_TEST(ASMAtomicXchgU8, uint8_t);
659}
660
661
662DECLINLINE(void) tstASMAtomicXchgU16Worker(uint16_t volatile *pu16)
663{
664 *pu16 = 0;
665
666 CHECKOP(ASMAtomicXchgU16(pu16, 1), 0, "%#x", uint16_t);
667 CHECKVAL(*pu16, 1, "%#x");
668
669 CHECKOP(ASMAtomicXchgU16(pu16, 0), 1, "%#x", uint16_t);
670 CHECKVAL(*pu16, 0, "%#x");
671
672 CHECKOP(ASMAtomicXchgU16(pu16, 0xffff), 0, "%#x", uint16_t);
673 CHECKVAL(*pu16, 0xffff, "%#x");
674
675 CHECKOP(ASMAtomicXchgU16(pu16, 0x8765), 0xffff, "%#x", uint16_t);
676 CHECKVAL(*pu16, 0x8765, "%#x");
677}
678
679
680static void tstASMAtomicXchgU16(void)
681{
682 DO_SIMPLE_TEST(ASMAtomicXchgU16, uint16_t);
683}
684
685
686DECLINLINE(void) tstASMAtomicXchgU32Worker(uint32_t volatile *pu32)
687{
688 *pu32 = 0;
689
690 CHECKOP(ASMAtomicXchgU32(pu32, 1), 0, "%#x", uint32_t);
691 CHECKVAL(*pu32, 1, "%#x");
692
693 CHECKOP(ASMAtomicXchgU32(pu32, 0), 1, "%#x", uint32_t);
694 CHECKVAL(*pu32, 0, "%#x");
695
696 CHECKOP(ASMAtomicXchgU32(pu32, ~UINT32_C(0)), 0, "%#x", uint32_t);
697 CHECKVAL(*pu32, ~UINT32_C(0), "%#x");
698
699 CHECKOP(ASMAtomicXchgU32(pu32, 0x87654321), ~UINT32_C(0), "%#x", uint32_t);
700 CHECKVAL(*pu32, 0x87654321, "%#x");
701}
702
703
704static void tstASMAtomicXchgU32(void)
705{
706 DO_SIMPLE_TEST(ASMAtomicXchgU32, uint32_t);
707}
708
709
710DECLINLINE(void) tstASMAtomicXchgU64Worker(uint64_t volatile *pu64)
711{
712 *pu64 = 0;
713
714 CHECKOP(ASMAtomicXchgU64(pu64, 1), UINT64_C(0), "%#llx", uint64_t);
715 CHECKVAL(*pu64, UINT64_C(1), "%#llx");
716
717 CHECKOP(ASMAtomicXchgU64(pu64, 0), UINT64_C(1), "%#llx", uint64_t);
718 CHECKVAL(*pu64, UINT64_C(0), "%#llx");
719
720 CHECKOP(ASMAtomicXchgU64(pu64, ~UINT64_C(0)), UINT64_C(0), "%#llx", uint64_t);
721 CHECKVAL(*pu64, ~UINT64_C(0), "%#llx");
722
723 CHECKOP(ASMAtomicXchgU64(pu64, UINT64_C(0xfedcba0987654321)), ~UINT64_C(0), "%#llx", uint64_t);
724 CHECKVAL(*pu64, UINT64_C(0xfedcba0987654321), "%#llx");
725}
726
727
728static void tstASMAtomicXchgU64(void)
729{
730 DO_SIMPLE_TEST(ASMAtomicXchgU64, uint64_t);
731}
732
733
734DECLINLINE(void) tstASMAtomicXchgPtrWorker(void * volatile *ppv)
735{
736 *ppv = NULL;
737
738 CHECKOP(ASMAtomicXchgPtr(ppv, (void *)(~(uintptr_t)0)), NULL, "%p", void *);
739 CHECKVAL(*ppv, (void *)(~(uintptr_t)0), "%p");
740
741 CHECKOP(ASMAtomicXchgPtr(ppv, (void *)(uintptr_t)0x87654321), (void *)(~(uintptr_t)0), "%p", void *);
742 CHECKVAL(*ppv, (void *)(uintptr_t)0x87654321, "%p");
743
744 CHECKOP(ASMAtomicXchgPtr(ppv, NULL), (void *)(uintptr_t)0x87654321, "%p", void *);
745 CHECKVAL(*ppv, NULL, "%p");
746}
747
748
749static void tstASMAtomicXchgPtr(void)
750{
751 DO_SIMPLE_TEST(ASMAtomicXchgPtr, void *);
752}
753
754
755DECLINLINE(void) tstASMAtomicCmpXchgU8Worker(uint8_t volatile *pu8)
756{
757 *pu8 = 0xff;
758
759 CHECKOP(ASMAtomicCmpXchgU8(pu8, 0, 0), false, "%d", bool);
760 CHECKVAL(*pu8, 0xff, "%x");
761
762 CHECKOP(ASMAtomicCmpXchgU8(pu8, 0, 0xff), true, "%d", bool);
763 CHECKVAL(*pu8, 0, "%x");
764
765 CHECKOP(ASMAtomicCmpXchgU8(pu8, 0x79, 0xff), false, "%d", bool);
766 CHECKVAL(*pu8, 0, "%x");
767
768 CHECKOP(ASMAtomicCmpXchgU8(pu8, 0x97, 0), true, "%d", bool);
769 CHECKVAL(*pu8, 0x97, "%x");
770}
771
772
773static void tstASMAtomicCmpXchgU8(void)
774{
775 DO_SIMPLE_TEST(ASMAtomicCmpXchgU8, uint8_t);
776}
777
778
779DECLINLINE(void) tstASMAtomicCmpXchgU32Worker(uint32_t volatile *pu32)
780{
781 *pu32 = UINT32_C(0xffffffff);
782
783 CHECKOP(ASMAtomicCmpXchgU32(pu32, 0, 0), false, "%d", bool);
784 CHECKVAL(*pu32, UINT32_C(0xffffffff), "%x");
785
786 CHECKOP(ASMAtomicCmpXchgU32(pu32, 0, UINT32_C(0xffffffff)), true, "%d", bool);
787 CHECKVAL(*pu32, 0, "%x");
788
789 CHECKOP(ASMAtomicCmpXchgU32(pu32, UINT32_C(0x8008efd), UINT32_C(0xffffffff)), false, "%d", bool);
790 CHECKVAL(*pu32, 0, "%x");
791
792 CHECKOP(ASMAtomicCmpXchgU32(pu32, UINT32_C(0x8008efd), 0), true, "%d", bool);
793 CHECKVAL(*pu32, UINT32_C(0x8008efd), "%x");
794}
795
796
797static void tstASMAtomicCmpXchgU32(void)
798{
799 DO_SIMPLE_TEST(ASMAtomicCmpXchgU32, uint32_t);
800}
801
802
803
804DECLINLINE(void) tstASMAtomicCmpXchgU64Worker(uint64_t volatile *pu64)
805{
806 *pu64 = UINT64_C(0xffffffffffffff);
807
808 CHECKOP(ASMAtomicCmpXchgU64(pu64, 0, 0), false, "%d", bool);
809 CHECKVAL(*pu64, UINT64_C(0xffffffffffffff), "%#llx");
810
811 CHECKOP(ASMAtomicCmpXchgU64(pu64, 0, UINT64_C(0xffffffffffffff)), true, "%d", bool);
812 CHECKVAL(*pu64, 0, "%x");
813
814 CHECKOP(ASMAtomicCmpXchgU64(pu64, UINT64_C(0x80040008008efd), UINT64_C(0xffffffff)), false, "%d", bool);
815 CHECKVAL(*pu64, 0, "%x");
816
817 CHECKOP(ASMAtomicCmpXchgU64(pu64, UINT64_C(0x80040008008efd), UINT64_C(0xffffffff00000000)), false, "%d", bool);
818 CHECKVAL(*pu64, 0, "%x");
819
820 CHECKOP(ASMAtomicCmpXchgU64(pu64, UINT64_C(0x80040008008efd), 0), true, "%d", bool);
821 CHECKVAL(*pu64, UINT64_C(0x80040008008efd), "%#llx");
822}
823
824
825static void tstASMAtomicCmpXchgU64(void)
826{
827 DO_SIMPLE_TEST(ASMAtomicCmpXchgU64, uint64_t);
828}
829
830
831DECLINLINE(void) tstASMAtomicCmpXchgExU32Worker(uint32_t volatile *pu32)
832{
833 *pu32 = UINT32_C(0xffffffff);
834 uint32_t u32Old = UINT32_C(0x80005111);
835
836 CHECKOP(ASMAtomicCmpXchgExU32(pu32, 0, 0, &u32Old), false, "%d", bool);
837 CHECKVAL(*pu32, UINT32_C(0xffffffff), "%x");
838 CHECKVAL(u32Old, UINT32_C(0xffffffff), "%x");
839
840 CHECKOP(ASMAtomicCmpXchgExU32(pu32, 0, UINT32_C(0xffffffff), &u32Old), true, "%d", bool);
841 CHECKVAL(*pu32, 0, "%x");
842 CHECKVAL(u32Old, UINT32_C(0xffffffff), "%x");
843
844 CHECKOP(ASMAtomicCmpXchgExU32(pu32, UINT32_C(0x8008efd), UINT32_C(0xffffffff), &u32Old), false, "%d", bool);
845 CHECKVAL(*pu32, 0, "%x");
846 CHECKVAL(u32Old, 0, "%x");
847
848 CHECKOP(ASMAtomicCmpXchgExU32(pu32, UINT32_C(0x8008efd), 0, &u32Old), true, "%d", bool);
849 CHECKVAL(*pu32, UINT32_C(0x8008efd), "%x");
850 CHECKVAL(u32Old, 0, "%x");
851
852 CHECKOP(ASMAtomicCmpXchgExU32(pu32, 0, UINT32_C(0x8008efd), &u32Old), true, "%d", bool);
853 CHECKVAL(*pu32, 0, "%x");
854 CHECKVAL(u32Old, UINT32_C(0x8008efd), "%x");
855}
856
857
858static void tstASMAtomicCmpXchgExU32(void)
859{
860 DO_SIMPLE_TEST(ASMAtomicCmpXchgExU32, uint32_t);
861}
862
863
864DECLINLINE(void) tstASMAtomicCmpXchgExU64Worker(uint64_t volatile *pu64)
865{
866 *pu64 = UINT64_C(0xffffffffffffffff);
867 uint64_t u64Old = UINT64_C(0x8000000051111111);
868
869 CHECKOP(ASMAtomicCmpXchgExU64(pu64, 0, 0, &u64Old), false, "%d", bool);
870 CHECKVAL(*pu64, UINT64_C(0xffffffffffffffff), "%llx");
871 CHECKVAL(u64Old, UINT64_C(0xffffffffffffffff), "%llx");
872
873 CHECKOP(ASMAtomicCmpXchgExU64(pu64, 0, UINT64_C(0xffffffffffffffff), &u64Old), true, "%d", bool);
874 CHECKVAL(*pu64, UINT64_C(0), "%llx");
875 CHECKVAL(u64Old, UINT64_C(0xffffffffffffffff), "%llx");
876
877 CHECKOP(ASMAtomicCmpXchgExU64(pu64, UINT64_C(0x80040008008efd), 0xffffffff, &u64Old), false, "%d", bool);
878 CHECKVAL(*pu64, UINT64_C(0), "%llx");
879 CHECKVAL(u64Old, UINT64_C(0), "%llx");
880
881 CHECKOP(ASMAtomicCmpXchgExU64(pu64, UINT64_C(0x80040008008efd), UINT64_C(0xffffffff00000000), &u64Old), false, "%d", bool);
882 CHECKVAL(*pu64, UINT64_C(0), "%llx");
883 CHECKVAL(u64Old, UINT64_C(0), "%llx");
884
885 CHECKOP(ASMAtomicCmpXchgExU64(pu64, UINT64_C(0x80040008008efd), 0, &u64Old), true, "%d", bool);
886 CHECKVAL(*pu64, UINT64_C(0x80040008008efd), "%llx");
887 CHECKVAL(u64Old, UINT64_C(0), "%llx");
888
889 CHECKOP(ASMAtomicCmpXchgExU64(pu64, 0, UINT64_C(0x80040008008efd), &u64Old), true, "%d", bool);
890 CHECKVAL(*pu64, UINT64_C(0), "%llx");
891 CHECKVAL(u64Old, UINT64_C(0x80040008008efd), "%llx");
892}
893
894
895static void tstASMAtomicCmpXchgExU64(void)
896{
897 DO_SIMPLE_TEST(ASMAtomicCmpXchgExU64, uint64_t);
898}
899
900
901DECLINLINE(void) tstASMAtomicReadU64Worker(uint64_t volatile *pu64)
902{
903 *pu64 = 0;
904
905 CHECKOP(ASMAtomicReadU64(pu64), UINT64_C(0), "%#llx", uint64_t);
906 CHECKVAL(*pu64, UINT64_C(0), "%#llx");
907
908 *pu64 = ~UINT64_C(0);
909 CHECKOP(ASMAtomicReadU64(pu64), ~UINT64_C(0), "%#llx", uint64_t);
910 CHECKVAL(*pu64, ~UINT64_C(0), "%#llx");
911
912 *pu64 = UINT64_C(0xfedcba0987654321);
913 CHECKOP(ASMAtomicReadU64(pu64), UINT64_C(0xfedcba0987654321), "%#llx", uint64_t);
914 CHECKVAL(*pu64, UINT64_C(0xfedcba0987654321), "%#llx");
915}
916
917
918static void tstASMAtomicReadU64(void)
919{
920 DO_SIMPLE_TEST(ASMAtomicReadU64, uint64_t);
921}
922
923
924DECLINLINE(void) tstASMAtomicUoReadU64Worker(uint64_t volatile *pu64)
925{
926 *pu64 = 0;
927
928 CHECKOP(ASMAtomicUoReadU64(pu64), UINT64_C(0), "%#llx", uint64_t);
929 CHECKVAL(*pu64, UINT64_C(0), "%#llx");
930
931 *pu64 = ~UINT64_C(0);
932 CHECKOP(ASMAtomicUoReadU64(pu64), ~UINT64_C(0), "%#llx", uint64_t);
933 CHECKVAL(*pu64, ~UINT64_C(0), "%#llx");
934
935 *pu64 = UINT64_C(0xfedcba0987654321);
936 CHECKOP(ASMAtomicUoReadU64(pu64), UINT64_C(0xfedcba0987654321), "%#llx", uint64_t);
937 CHECKVAL(*pu64, UINT64_C(0xfedcba0987654321), "%#llx");
938}
939
940
941static void tstASMAtomicUoReadU64(void)
942{
943 DO_SIMPLE_TEST(ASMAtomicUoReadU64, uint64_t);
944}
945
946
947DECLINLINE(void) tstASMAtomicAddS32Worker(int32_t *pi32)
948{
949 int32_t i32Rc;
950 *pi32 = 10;
951#define MYCHECK(op, rc, val) \
952 do { \
953 i32Rc = op; \
954 if (i32Rc != (rc)) \
955 RTTestFailed(g_hTest, "%s, %d: FAILURE: %s -> %d expected %d\n", __FUNCTION__, __LINE__, #op, i32Rc, rc); \
956 if (*pi32 != (val)) \
957 RTTestFailed(g_hTest, "%s, %d: FAILURE: %s => *pi32=%d expected %d\n", __FUNCTION__, __LINE__, #op, *pi32, val); \
958 } while (0)
959 MYCHECK(ASMAtomicAddS32(pi32, 1), 10, 11);
960 MYCHECK(ASMAtomicAddS32(pi32, -2), 11, 9);
961 MYCHECK(ASMAtomicAddS32(pi32, -9), 9, 0);
962 MYCHECK(ASMAtomicAddS32(pi32, -0x7fffffff), 0, -0x7fffffff);
963 MYCHECK(ASMAtomicAddS32(pi32, 0), -0x7fffffff, -0x7fffffff);
964 MYCHECK(ASMAtomicAddS32(pi32, 0x7fffffff), -0x7fffffff, 0);
965 MYCHECK(ASMAtomicAddS32(pi32, 0), 0, 0);
966#undef MYCHECK
967}
968
969
970static void tstASMAtomicAddS32(void)
971{
972 DO_SIMPLE_TEST(ASMAtomicAddS32, int32_t);
973}
974
975
976DECLINLINE(void) tstASMAtomicUoIncU32Worker(uint32_t volatile *pu32)
977{
978 *pu32 = 0;
979
980 CHECKOP(ASMAtomicUoIncU32(pu32), UINT32_C(1), "%#x", uint32_t);
981 CHECKVAL(*pu32, UINT32_C(1), "%#x");
982
983 *pu32 = ~UINT32_C(0);
984 CHECKOP(ASMAtomicUoIncU32(pu32), 0, "%#x", uint32_t);
985 CHECKVAL(*pu32, 0, "%#x");
986
987 *pu32 = UINT32_C(0x7fffffff);
988 CHECKOP(ASMAtomicUoIncU32(pu32), UINT32_C(0x80000000), "%#x", uint32_t);
989 CHECKVAL(*pu32, UINT32_C(0x80000000), "%#x");
990}
991
992
993static void tstASMAtomicUoIncU32(void)
994{
995 DO_SIMPLE_TEST(ASMAtomicUoIncU32, uint32_t);
996}
997
998
999DECLINLINE(void) tstASMAtomicUoDecU32Worker(uint32_t volatile *pu32)
1000{
1001 *pu32 = 0;
1002
1003 CHECKOP(ASMAtomicUoDecU32(pu32), ~UINT32_C(0), "%#x", uint32_t);
1004 CHECKVAL(*pu32, ~UINT32_C(0), "%#x");
1005
1006 *pu32 = ~UINT32_C(0);
1007 CHECKOP(ASMAtomicUoDecU32(pu32), UINT32_C(0xfffffffe), "%#x", uint32_t);
1008 CHECKVAL(*pu32, UINT32_C(0xfffffffe), "%#x");
1009
1010 *pu32 = UINT32_C(0x80000000);
1011 CHECKOP(ASMAtomicUoDecU32(pu32), UINT32_C(0x7fffffff), "%#x", uint32_t);
1012 CHECKVAL(*pu32, UINT32_C(0x7fffffff), "%#x");
1013}
1014
1015
1016static void tstASMAtomicUoDecU32(void)
1017{
1018 DO_SIMPLE_TEST(ASMAtomicUoDecU32, uint32_t);
1019}
1020
1021
1022DECLINLINE(void) tstASMAtomicAddS64Worker(int64_t volatile *pi64)
1023{
1024 int64_t i64Rc;
1025 *pi64 = 10;
1026#define MYCHECK(op, rc, val) \
1027 do { \
1028 i64Rc = op; \
1029 if (i64Rc != (rc)) \
1030 RTTestFailed(g_hTest, "%s, %d: FAILURE: %s -> %llx expected %llx\n", __FUNCTION__, __LINE__, #op, i64Rc, (int64_t)rc); \
1031 if (*pi64 != (val)) \
1032 RTTestFailed(g_hTest, "%s, %d: FAILURE: %s => *pi64=%llx expected %llx\n", __FUNCTION__, __LINE__, #op, *pi64, (int64_t)(val)); \
1033 } while (0)
1034 MYCHECK(ASMAtomicAddS64(pi64, 1), 10, 11);
1035 MYCHECK(ASMAtomicAddS64(pi64, -2), 11, 9);
1036 MYCHECK(ASMAtomicAddS64(pi64, -9), 9, 0);
1037 MYCHECK(ASMAtomicAddS64(pi64, -INT64_MAX), 0, -INT64_MAX);
1038 MYCHECK(ASMAtomicAddS64(pi64, 0), -INT64_MAX, -INT64_MAX);
1039 MYCHECK(ASMAtomicAddS64(pi64, -1), -INT64_MAX, INT64_MIN);
1040 MYCHECK(ASMAtomicAddS64(pi64, INT64_MAX), INT64_MIN, -1);
1041 MYCHECK(ASMAtomicAddS64(pi64, 1), -1, 0);
1042 MYCHECK(ASMAtomicAddS64(pi64, 0), 0, 0);
1043#undef MYCHECK
1044}
1045
1046
1047static void tstASMAtomicAddS64(void)
1048{
1049 DO_SIMPLE_TEST(ASMAtomicAddS64, int64_t);
1050}
1051
1052
1053DECLINLINE(void) tstASMAtomicDecIncS32Worker(int32_t volatile *pi32)
1054{
1055 int32_t i32Rc;
1056 *pi32 = 10;
1057#define MYCHECK(op, rc) \
1058 do { \
1059 i32Rc = op; \
1060 if (i32Rc != (rc)) \
1061 RTTestFailed(g_hTest, "%s, %d: FAILURE: %s -> %d expected %d\n", __FUNCTION__, __LINE__, #op, i32Rc, rc); \
1062 if (*pi32 != (rc)) \
1063 RTTestFailed(g_hTest, "%s, %d: FAILURE: %s => *pi32=%d expected %d\n", __FUNCTION__, __LINE__, #op, *pi32, rc); \
1064 } while (0)
1065 MYCHECK(ASMAtomicDecS32(pi32), 9);
1066 MYCHECK(ASMAtomicDecS32(pi32), 8);
1067 MYCHECK(ASMAtomicDecS32(pi32), 7);
1068 MYCHECK(ASMAtomicDecS32(pi32), 6);
1069 MYCHECK(ASMAtomicDecS32(pi32), 5);
1070 MYCHECK(ASMAtomicDecS32(pi32), 4);
1071 MYCHECK(ASMAtomicDecS32(pi32), 3);
1072 MYCHECK(ASMAtomicDecS32(pi32), 2);
1073 MYCHECK(ASMAtomicDecS32(pi32), 1);
1074 MYCHECK(ASMAtomicDecS32(pi32), 0);
1075 MYCHECK(ASMAtomicDecS32(pi32), -1);
1076 MYCHECK(ASMAtomicDecS32(pi32), -2);
1077 MYCHECK(ASMAtomicIncS32(pi32), -1);
1078 MYCHECK(ASMAtomicIncS32(pi32), 0);
1079 MYCHECK(ASMAtomicIncS32(pi32), 1);
1080 MYCHECK(ASMAtomicIncS32(pi32), 2);
1081 MYCHECK(ASMAtomicIncS32(pi32), 3);
1082 MYCHECK(ASMAtomicDecS32(pi32), 2);
1083 MYCHECK(ASMAtomicIncS32(pi32), 3);
1084 MYCHECK(ASMAtomicDecS32(pi32), 2);
1085 MYCHECK(ASMAtomicIncS32(pi32), 3);
1086#undef MYCHECK
1087}
1088
1089
1090static void tstASMAtomicDecIncS32(void)
1091{
1092 DO_SIMPLE_TEST(ASMAtomicDecIncS32, int32_t);
1093}
1094
1095
1096DECLINLINE(void) tstASMAtomicDecIncS64Worker(int64_t volatile *pi64)
1097{
1098 int64_t i64Rc;
1099 *pi64 = 10;
1100#define MYCHECK(op, rc) \
1101 do { \
1102 i64Rc = op; \
1103 if (i64Rc != (rc)) \
1104 RTTestFailed(g_hTest, "%s, %d: FAILURE: %s -> %lld expected %lld\n", __FUNCTION__, __LINE__, #op, i64Rc, rc); \
1105 if (*pi64 != (rc)) \
1106 RTTestFailed(g_hTest, "%s, %d: FAILURE: %s => *pi64=%lld expected %lld\n", __FUNCTION__, __LINE__, #op, *pi64, rc); \
1107 } while (0)
1108 MYCHECK(ASMAtomicDecS64(pi64), 9);
1109 MYCHECK(ASMAtomicDecS64(pi64), 8);
1110 MYCHECK(ASMAtomicDecS64(pi64), 7);
1111 MYCHECK(ASMAtomicDecS64(pi64), 6);
1112 MYCHECK(ASMAtomicDecS64(pi64), 5);
1113 MYCHECK(ASMAtomicDecS64(pi64), 4);
1114 MYCHECK(ASMAtomicDecS64(pi64), 3);
1115 MYCHECK(ASMAtomicDecS64(pi64), 2);
1116 MYCHECK(ASMAtomicDecS64(pi64), 1);
1117 MYCHECK(ASMAtomicDecS64(pi64), 0);
1118 MYCHECK(ASMAtomicDecS64(pi64), -1);
1119 MYCHECK(ASMAtomicDecS64(pi64), -2);
1120 MYCHECK(ASMAtomicIncS64(pi64), -1);
1121 MYCHECK(ASMAtomicIncS64(pi64), 0);
1122 MYCHECK(ASMAtomicIncS64(pi64), 1);
1123 MYCHECK(ASMAtomicIncS64(pi64), 2);
1124 MYCHECK(ASMAtomicIncS64(pi64), 3);
1125 MYCHECK(ASMAtomicDecS64(pi64), 2);
1126 MYCHECK(ASMAtomicIncS64(pi64), 3);
1127 MYCHECK(ASMAtomicDecS64(pi64), 2);
1128 MYCHECK(ASMAtomicIncS64(pi64), 3);
1129#undef MYCHECK
1130}
1131
1132
1133static void tstASMAtomicDecIncS64(void)
1134{
1135 DO_SIMPLE_TEST(ASMAtomicDecIncS64, int64_t);
1136}
1137
1138
1139DECLINLINE(void) tstASMAtomicAndOrU32Worker(uint32_t volatile *pu32)
1140{
1141 *pu32 = UINT32_C(0xffffffff);
1142
1143 ASMAtomicOrU32(pu32, UINT32_C(0xffffffff));
1144 CHECKVAL(*pu32, UINT32_C(0xffffffff), "%x");
1145
1146 ASMAtomicAndU32(pu32, UINT32_C(0xffffffff));
1147 CHECKVAL(*pu32, UINT32_C(0xffffffff), "%x");
1148
1149 ASMAtomicAndU32(pu32, UINT32_C(0x8f8f8f8f));
1150 CHECKVAL(*pu32, UINT32_C(0x8f8f8f8f), "%x");
1151
1152 ASMAtomicOrU32(pu32, UINT32_C(0x70707070));
1153 CHECKVAL(*pu32, UINT32_C(0xffffffff), "%x");
1154
1155 ASMAtomicAndU32(pu32, UINT32_C(1));
1156 CHECKVAL(*pu32, UINT32_C(1), "%x");
1157
1158 ASMAtomicOrU32(pu32, UINT32_C(0x80000000));
1159 CHECKVAL(*pu32, UINT32_C(0x80000001), "%x");
1160
1161 ASMAtomicAndU32(pu32, UINT32_C(0x80000000));
1162 CHECKVAL(*pu32, UINT32_C(0x80000000), "%x");
1163
1164 ASMAtomicAndU32(pu32, UINT32_C(0));
1165 CHECKVAL(*pu32, UINT32_C(0), "%x");
1166
1167 ASMAtomicOrU32(pu32, UINT32_C(0x42424242));
1168 CHECKVAL(*pu32, UINT32_C(0x42424242), "%x");
1169}
1170
1171
1172static void tstASMAtomicAndOrU32(void)
1173{
1174 DO_SIMPLE_TEST(ASMAtomicAndOrU32, uint32_t);
1175}
1176
1177
1178DECLINLINE(void) tstASMAtomicAndOrU64Worker(uint64_t volatile *pu64)
1179{
1180 *pu64 = UINT64_C(0xffffffff);
1181
1182 ASMAtomicOrU64(pu64, UINT64_C(0xffffffff));
1183 CHECKVAL(*pu64, UINT64_C(0xffffffff), "%x");
1184
1185 ASMAtomicAndU64(pu64, UINT64_C(0xffffffff));
1186 CHECKVAL(*pu64, UINT64_C(0xffffffff), "%x");
1187
1188 ASMAtomicAndU64(pu64, UINT64_C(0x8f8f8f8f));
1189 CHECKVAL(*pu64, UINT64_C(0x8f8f8f8f), "%x");
1190
1191 ASMAtomicOrU64(pu64, UINT64_C(0x70707070));
1192 CHECKVAL(*pu64, UINT64_C(0xffffffff), "%x");
1193
1194 ASMAtomicAndU64(pu64, UINT64_C(1));
1195 CHECKVAL(*pu64, UINT64_C(1), "%x");
1196
1197 ASMAtomicOrU64(pu64, UINT64_C(0x80000000));
1198 CHECKVAL(*pu64, UINT64_C(0x80000001), "%x");
1199
1200 ASMAtomicAndU64(pu64, UINT64_C(0x80000000));
1201 CHECKVAL(*pu64, UINT64_C(0x80000000), "%x");
1202
1203 ASMAtomicAndU64(pu64, UINT64_C(0));
1204 CHECKVAL(*pu64, UINT64_C(0), "%x");
1205
1206 ASMAtomicOrU64(pu64, UINT64_C(0x42424242));
1207 CHECKVAL(*pu64, UINT64_C(0x42424242), "%x");
1208
1209 // Same as above, but now 64-bit wide.
1210 ASMAtomicAndU64(pu64, UINT64_C(0));
1211 CHECKVAL(*pu64, UINT64_C(0), "%x");
1212
1213 ASMAtomicOrU64(pu64, UINT64_C(0xffffffffffffffff));
1214 CHECKVAL(*pu64, UINT64_C(0xffffffffffffffff), "%x");
1215
1216 ASMAtomicAndU64(pu64, UINT64_C(0xffffffffffffffff));
1217 CHECKVAL(*pu64, UINT64_C(0xffffffffffffffff), "%x");
1218
1219 ASMAtomicAndU64(pu64, UINT64_C(0x8f8f8f8f8f8f8f8f));
1220 CHECKVAL(*pu64, UINT64_C(0x8f8f8f8f8f8f8f8f), "%x");
1221
1222 ASMAtomicOrU64(pu64, UINT64_C(0x7070707070707070));
1223 CHECKVAL(*pu64, UINT64_C(0xffffffffffffffff), "%x");
1224
1225 ASMAtomicAndU64(pu64, UINT64_C(1));
1226 CHECKVAL(*pu64, UINT64_C(1), "%x");
1227
1228 ASMAtomicOrU64(pu64, UINT64_C(0x8000000000000000));
1229 CHECKVAL(*pu64, UINT64_C(0x8000000000000001), "%x");
1230
1231 ASMAtomicAndU64(pu64, UINT64_C(0x8000000000000000));
1232 CHECKVAL(*pu64, UINT64_C(0x8000000000000000), "%x");
1233
1234 ASMAtomicAndU64(pu64, UINT64_C(0));
1235 CHECKVAL(*pu64, UINT64_C(0), "%x");
1236
1237 ASMAtomicOrU64(pu64, UINT64_C(0x4242424242424242));
1238 CHECKVAL(*pu64, UINT64_C(0x4242424242424242), "%x");
1239}
1240
1241
1242static void tstASMAtomicAndOrU64(void)
1243{
1244 DO_SIMPLE_TEST(ASMAtomicAndOrU64, uint64_t);
1245}
1246
1247
1248DECLINLINE(void) tstASMAtomicUoAndOrU32Worker(uint32_t volatile *pu32)
1249{
1250 *pu32 = UINT32_C(0xffffffff);
1251
1252 ASMAtomicUoOrU32(pu32, UINT32_C(0xffffffff));
1253 CHECKVAL(*pu32, UINT32_C(0xffffffff), "%#x");
1254
1255 ASMAtomicUoAndU32(pu32, UINT32_C(0xffffffff));
1256 CHECKVAL(*pu32, UINT32_C(0xffffffff), "%#x");
1257
1258 ASMAtomicUoAndU32(pu32, UINT32_C(0x8f8f8f8f));
1259 CHECKVAL(*pu32, UINT32_C(0x8f8f8f8f), "%#x");
1260
1261 ASMAtomicUoOrU32(pu32, UINT32_C(0x70707070));
1262 CHECKVAL(*pu32, UINT32_C(0xffffffff), "%#x");
1263
1264 ASMAtomicUoAndU32(pu32, UINT32_C(1));
1265 CHECKVAL(*pu32, UINT32_C(1), "%#x");
1266
1267 ASMAtomicUoOrU32(pu32, UINT32_C(0x80000000));
1268 CHECKVAL(*pu32, UINT32_C(0x80000001), "%#x");
1269
1270 ASMAtomicUoAndU32(pu32, UINT32_C(0x80000000));
1271 CHECKVAL(*pu32, UINT32_C(0x80000000), "%#x");
1272
1273 ASMAtomicUoAndU32(pu32, UINT32_C(0));
1274 CHECKVAL(*pu32, UINT32_C(0), "%#x");
1275
1276 ASMAtomicUoOrU32(pu32, UINT32_C(0x42424242));
1277 CHECKVAL(*pu32, UINT32_C(0x42424242), "%#x");
1278}
1279
1280
1281static void tstASMAtomicUoAndOrU32(void)
1282{
1283 DO_SIMPLE_TEST(ASMAtomicUoAndOrU32, uint32_t);
1284}
1285
1286
1287typedef struct
1288{
1289 uint8_t ab[PAGE_SIZE];
1290} TSTPAGE;
1291
1292
1293DECLINLINE(void) tstASMMemZeroPageWorker(TSTPAGE *pPage)
1294{
1295 for (unsigned j = 0; j < 16; j++)
1296 {
1297 memset(pPage, 0x11 * j, sizeof(*pPage));
1298 ASMMemZeroPage(pPage);
1299 for (unsigned i = 0; i < sizeof(pPage->ab); i++)
1300 if (pPage->ab[i])
1301 RTTestFailed(g_hTest, "ASMMemZeroPage didn't clear byte at offset %#x!\n", i);
1302 }
1303}
1304
1305
1306static void tstASMMemZeroPage(void)
1307{
1308 DO_SIMPLE_TEST(ASMMemZeroPage, TSTPAGE);
1309}
1310
1311
1312void tstASMMemIsZeroPage(RTTEST hTest)
1313{
1314 RTTestSub(hTest, "ASMMemIsZeroPage");
1315
1316 void *pvPage1 = RTTestGuardedAllocHead(hTest, PAGE_SIZE);
1317 void *pvPage2 = RTTestGuardedAllocTail(hTest, PAGE_SIZE);
1318 RTTESTI_CHECK_RETV(pvPage1 && pvPage2);
1319
1320 memset(pvPage1, 0, PAGE_SIZE);
1321 memset(pvPage2, 0, PAGE_SIZE);
1322 RTTESTI_CHECK(ASMMemIsZeroPage(pvPage1));
1323 RTTESTI_CHECK(ASMMemIsZeroPage(pvPage2));
1324
1325 memset(pvPage1, 0xff, PAGE_SIZE);
1326 memset(pvPage2, 0xff, PAGE_SIZE);
1327 RTTESTI_CHECK(!ASMMemIsZeroPage(pvPage1));
1328 RTTESTI_CHECK(!ASMMemIsZeroPage(pvPage2));
1329
1330 memset(pvPage1, 0, PAGE_SIZE);
1331 memset(pvPage2, 0, PAGE_SIZE);
1332 for (unsigned off = 0; off < PAGE_SIZE; off++)
1333 {
1334 ((uint8_t *)pvPage1)[off] = 1;
1335 RTTESTI_CHECK(!ASMMemIsZeroPage(pvPage1));
1336 ((uint8_t *)pvPage1)[off] = 0;
1337
1338 ((uint8_t *)pvPage2)[off] = 0x80;
1339 RTTESTI_CHECK(!ASMMemIsZeroPage(pvPage2));
1340 ((uint8_t *)pvPage2)[off] = 0;
1341 }
1342
1343 RTTestSubDone(hTest);
1344}
1345
1346
1347void tstASMMemFirstMismatchingU8(RTTEST hTest)
1348{
1349 RTTestSub(hTest, "ASMMemFirstMismatchingU8");
1350
1351 uint8_t *pbPage1 = (uint8_t *)RTTestGuardedAllocHead(hTest, PAGE_SIZE);
1352 uint8_t *pbPage2 = (uint8_t *)RTTestGuardedAllocTail(hTest, PAGE_SIZE);
1353 RTTESTI_CHECK_RETV(pbPage1 && pbPage2);
1354
1355 memset(pbPage1, 0, PAGE_SIZE);
1356 memset(pbPage2, 0, PAGE_SIZE);
1357 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage1, PAGE_SIZE, 0) == NULL);
1358 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage2, PAGE_SIZE, 0) == NULL);
1359 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage1, PAGE_SIZE, 1) == pbPage1);
1360 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage2, PAGE_SIZE, 1) == pbPage2);
1361 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage1, PAGE_SIZE, 0x87) == pbPage1);
1362 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage2, PAGE_SIZE, 0x87) == pbPage2);
1363 RTTESTI_CHECK(ASMMemIsZero(pbPage1, PAGE_SIZE));
1364 RTTESTI_CHECK(ASMMemIsZero(pbPage2, PAGE_SIZE));
1365 RTTESTI_CHECK(ASMMemIsAllU8(pbPage1, PAGE_SIZE, 0));
1366 RTTESTI_CHECK(ASMMemIsAllU8(pbPage2, PAGE_SIZE, 0));
1367 RTTESTI_CHECK(!ASMMemIsAllU8(pbPage1, PAGE_SIZE, 0x34));
1368 RTTESTI_CHECK(!ASMMemIsAllU8(pbPage2, PAGE_SIZE, 0x88));
1369 unsigned cbSub = 32;
1370 while (cbSub-- > 0)
1371 {
1372 RTTESTI_CHECK(ASMMemFirstMismatchingU8(&pbPage1[PAGE_SIZE - cbSub], cbSub, 0) == NULL);
1373 RTTESTI_CHECK(ASMMemFirstMismatchingU8(&pbPage2[PAGE_SIZE - cbSub], cbSub, 0) == NULL);
1374 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage1, cbSub, 0) == NULL);
1375 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage2, cbSub, 0) == NULL);
1376
1377 RTTESTI_CHECK(ASMMemFirstMismatchingU8(&pbPage1[PAGE_SIZE - cbSub], cbSub, 0x34) == &pbPage1[PAGE_SIZE - cbSub] || !cbSub);
1378 RTTESTI_CHECK(ASMMemFirstMismatchingU8(&pbPage2[PAGE_SIZE - cbSub], cbSub, 0x99) == &pbPage2[PAGE_SIZE - cbSub] || !cbSub);
1379 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage1, cbSub, 0x42) == pbPage1 || !cbSub);
1380 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage2, cbSub, 0x88) == pbPage2 || !cbSub);
1381 }
1382
1383 memset(pbPage1, 0xff, PAGE_SIZE);
1384 memset(pbPage2, 0xff, PAGE_SIZE);
1385 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage1, PAGE_SIZE, 0xff) == NULL);
1386 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage2, PAGE_SIZE, 0xff) == NULL);
1387 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage1, PAGE_SIZE, 0xfe) == pbPage1);
1388 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage2, PAGE_SIZE, 0xfe) == pbPage2);
1389 RTTESTI_CHECK(!ASMMemIsZero(pbPage1, PAGE_SIZE));
1390 RTTESTI_CHECK(!ASMMemIsZero(pbPage2, PAGE_SIZE));
1391 RTTESTI_CHECK(ASMMemIsAllU8(pbPage1, PAGE_SIZE, 0xff));
1392 RTTESTI_CHECK(ASMMemIsAllU8(pbPage2, PAGE_SIZE, 0xff));
1393 RTTESTI_CHECK(!ASMMemIsAllU8(pbPage1, PAGE_SIZE, 0));
1394 RTTESTI_CHECK(!ASMMemIsAllU8(pbPage2, PAGE_SIZE, 0));
1395 cbSub = 32;
1396 while (cbSub-- > 0)
1397 {
1398 RTTESTI_CHECK(ASMMemFirstMismatchingU8(&pbPage1[PAGE_SIZE - cbSub], cbSub, 0xff) == NULL);
1399 RTTESTI_CHECK(ASMMemFirstMismatchingU8(&pbPage2[PAGE_SIZE - cbSub], cbSub, 0xff) == NULL);
1400 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage1, cbSub, 0xff) == NULL);
1401 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage2, cbSub, 0xff) == NULL);
1402
1403 RTTESTI_CHECK(ASMMemFirstMismatchingU8(&pbPage1[PAGE_SIZE - cbSub], cbSub, 0xfe) == &pbPage1[PAGE_SIZE - cbSub] || !cbSub);
1404 RTTESTI_CHECK(ASMMemFirstMismatchingU8(&pbPage2[PAGE_SIZE - cbSub], cbSub, 0xfe) == &pbPage2[PAGE_SIZE - cbSub] || !cbSub);
1405 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage1, cbSub, 0xfe) == pbPage1 || !cbSub);
1406 RTTESTI_CHECK(ASMMemFirstMismatchingU8(pbPage2, cbSub, 0xfe) == pbPage2 || !cbSub);
1407 }
1408
1409
1410 /*
1411 * Various alignments and sizes.
1412 */
1413 uint8_t const bFiller1 = 0x00;
1414 uint8_t const bFiller2 = 0xf6;
1415 size_t const cbBuf = 128;
1416 uint8_t *pbBuf1 = pbPage1;
1417 uint8_t *pbBuf2 = &pbPage2[PAGE_SIZE - cbBuf]; /* Put it up against the tail guard */
1418 memset(pbPage1, ~bFiller1, PAGE_SIZE);
1419 memset(pbPage2, ~bFiller2, PAGE_SIZE);
1420 memset(pbBuf1, bFiller1, cbBuf);
1421 memset(pbBuf2, bFiller2, cbBuf);
1422 for (size_t offNonZero = 0; offNonZero < cbBuf; offNonZero++)
1423 {
1424 uint8_t bRand = (uint8_t)RTRandU32();
1425 pbBuf1[offNonZero] = bRand | 1;
1426 pbBuf2[offNonZero] = (0x80 | bRand) ^ 0xf6;
1427
1428 for (size_t offStart = 0; offStart < 32; offStart++)
1429 {
1430 size_t const cbMax = cbBuf - offStart;
1431 for (size_t cb = 0; cb < cbMax; cb++)
1432 {
1433 size_t const offEnd = offStart + cb;
1434 uint8_t bSaved1, bSaved2;
1435 if (offEnd < PAGE_SIZE)
1436 {
1437 bSaved1 = pbBuf1[offEnd];
1438 bSaved2 = pbBuf2[offEnd];
1439 pbBuf1[offEnd] = 0xff;
1440 pbBuf2[offEnd] = 0xff;
1441 }
1442#ifdef _MSC_VER /* simple stupid compiler warnings */
1443 else
1444 bSaved1 = bSaved2 = 0;
1445#endif
1446
1447 uint8_t *pbRet = (uint8_t *)ASMMemFirstMismatchingU8(pbBuf1 + offStart, cb, bFiller1);
1448 RTTESTI_CHECK(offNonZero - offStart < cb ? pbRet == &pbBuf1[offNonZero] : pbRet == NULL);
1449
1450 pbRet = (uint8_t *)ASMMemFirstMismatchingU8(pbBuf2 + offStart, cb, bFiller2);
1451 RTTESTI_CHECK(offNonZero - offStart < cb ? pbRet == &pbBuf2[offNonZero] : pbRet == NULL);
1452
1453 if (offEnd < PAGE_SIZE)
1454 {
1455 pbBuf1[offEnd] = bSaved1;
1456 pbBuf2[offEnd] = bSaved2;
1457 }
1458 }
1459 }
1460
1461 pbBuf1[offNonZero] = 0;
1462 pbBuf2[offNonZero] = 0xf6;
1463 }
1464
1465 RTTestSubDone(hTest);
1466}
1467
1468
1469void tstASMMemZero32(void)
1470{
1471 RTTestSub(g_hTest, "ASMMemFill32");
1472
1473 struct
1474 {
1475 uint64_t u64Magic1;
1476 uint8_t abPage[PAGE_SIZE - 32];
1477 uint64_t u64Magic2;
1478 } Buf1, Buf2, Buf3;
1479
1480 Buf1.u64Magic1 = UINT64_C(0xffffffffffffffff);
1481 memset(Buf1.abPage, 0x55, sizeof(Buf1.abPage));
1482 Buf1.u64Magic2 = UINT64_C(0xffffffffffffffff);
1483 Buf2.u64Magic1 = UINT64_C(0xffffffffffffffff);
1484 memset(Buf2.abPage, 0x77, sizeof(Buf2.abPage));
1485 Buf2.u64Magic2 = UINT64_C(0xffffffffffffffff);
1486 Buf3.u64Magic1 = UINT64_C(0xffffffffffffffff);
1487 memset(Buf3.abPage, 0x99, sizeof(Buf3.abPage));
1488 Buf3.u64Magic2 = UINT64_C(0xffffffffffffffff);
1489 ASMMemZero32(Buf1.abPage, sizeof(Buf1.abPage));
1490 ASMMemZero32(Buf2.abPage, sizeof(Buf2.abPage));
1491 ASMMemZero32(Buf3.abPage, sizeof(Buf3.abPage));
1492 if ( Buf1.u64Magic1 != UINT64_C(0xffffffffffffffff)
1493 || Buf1.u64Magic2 != UINT64_C(0xffffffffffffffff)
1494 || Buf2.u64Magic1 != UINT64_C(0xffffffffffffffff)
1495 || Buf2.u64Magic2 != UINT64_C(0xffffffffffffffff)
1496 || Buf3.u64Magic1 != UINT64_C(0xffffffffffffffff)
1497 || Buf3.u64Magic2 != UINT64_C(0xffffffffffffffff))
1498 {
1499 RTTestFailed(g_hTest, "ASMMemZero32 violated one/both magic(s)!\n");
1500 }
1501 for (unsigned i = 0; i < RT_ELEMENTS(Buf1.abPage); i++)
1502 if (Buf1.abPage[i])
1503 RTTestFailed(g_hTest, "ASMMemZero32 didn't clear byte at offset %#x!\n", i);
1504 for (unsigned i = 0; i < RT_ELEMENTS(Buf2.abPage); i++)
1505 if (Buf2.abPage[i])
1506 RTTestFailed(g_hTest, "ASMMemZero32 didn't clear byte at offset %#x!\n", i);
1507 for (unsigned i = 0; i < RT_ELEMENTS(Buf3.abPage); i++)
1508 if (Buf3.abPage[i])
1509 RTTestFailed(g_hTest, "ASMMemZero32 didn't clear byte at offset %#x!\n", i);
1510}
1511
1512
1513void tstASMMemFill32(void)
1514{
1515 RTTestSub(g_hTest, "ASMMemFill32");
1516
1517 struct
1518 {
1519 uint64_t u64Magic1;
1520 uint32_t au32Page[PAGE_SIZE / 4];
1521 uint64_t u64Magic2;
1522 } Buf1;
1523 struct
1524 {
1525 uint64_t u64Magic1;
1526 uint32_t au32Page[(PAGE_SIZE / 4) - 3];
1527 uint64_t u64Magic2;
1528 } Buf2;
1529 struct
1530 {
1531 uint64_t u64Magic1;
1532 uint32_t au32Page[(PAGE_SIZE / 4) - 1];
1533 uint64_t u64Magic2;
1534 } Buf3;
1535
1536 Buf1.u64Magic1 = UINT64_C(0xffffffffffffffff);
1537 memset(Buf1.au32Page, 0x55, sizeof(Buf1.au32Page));
1538 Buf1.u64Magic2 = UINT64_C(0xffffffffffffffff);
1539 Buf2.u64Magic1 = UINT64_C(0xffffffffffffffff);
1540 memset(Buf2.au32Page, 0x77, sizeof(Buf2.au32Page));
1541 Buf2.u64Magic2 = UINT64_C(0xffffffffffffffff);
1542 Buf3.u64Magic1 = UINT64_C(0xffffffffffffffff);
1543 memset(Buf3.au32Page, 0x99, sizeof(Buf3.au32Page));
1544 Buf3.u64Magic2 = UINT64_C(0xffffffffffffffff);
1545 ASMMemFill32(Buf1.au32Page, sizeof(Buf1.au32Page), 0xdeadbeef);
1546 ASMMemFill32(Buf2.au32Page, sizeof(Buf2.au32Page), 0xcafeff01);
1547 ASMMemFill32(Buf3.au32Page, sizeof(Buf3.au32Page), 0xf00dd00f);
1548 if ( Buf1.u64Magic1 != UINT64_C(0xffffffffffffffff)
1549 || Buf1.u64Magic2 != UINT64_C(0xffffffffffffffff)
1550 || Buf2.u64Magic1 != UINT64_C(0xffffffffffffffff)
1551 || Buf2.u64Magic2 != UINT64_C(0xffffffffffffffff)
1552 || Buf3.u64Magic1 != UINT64_C(0xffffffffffffffff)
1553 || Buf3.u64Magic2 != UINT64_C(0xffffffffffffffff))
1554 RTTestFailed(g_hTest, "ASMMemFill32 violated one/both magic(s)!\n");
1555 for (unsigned i = 0; i < RT_ELEMENTS(Buf1.au32Page); i++)
1556 if (Buf1.au32Page[i] != 0xdeadbeef)
1557 RTTestFailed(g_hTest, "ASMMemFill32 %#x: %#x exepcted %#x\n", i, Buf1.au32Page[i], 0xdeadbeef);
1558 for (unsigned i = 0; i < RT_ELEMENTS(Buf2.au32Page); i++)
1559 if (Buf2.au32Page[i] != 0xcafeff01)
1560 RTTestFailed(g_hTest, "ASMMemFill32 %#x: %#x exepcted %#x\n", i, Buf2.au32Page[i], 0xcafeff01);
1561 for (unsigned i = 0; i < RT_ELEMENTS(Buf3.au32Page); i++)
1562 if (Buf3.au32Page[i] != 0xf00dd00f)
1563 RTTestFailed(g_hTest, "ASMMemFill32 %#x: %#x exepcted %#x\n", i, Buf3.au32Page[i], 0xf00dd00f);
1564}
1565
1566
1567
1568void tstASMMath(void)
1569{
1570 RTTestSub(g_hTest, "Math");
1571
1572 uint64_t u64 = ASMMult2xU32RetU64(UINT32_C(0x80000000), UINT32_C(0x10000000));
1573 CHECKVAL(u64, UINT64_C(0x0800000000000000), "%#018RX64");
1574
1575 uint32_t u32 = ASMDivU64ByU32RetU32(UINT64_C(0x0800000000000000), UINT32_C(0x10000000));
1576 CHECKVAL(u32, UINT32_C(0x80000000), "%#010RX32");
1577
1578 u32 = ASMMultU32ByU32DivByU32(UINT32_C(0x00000001), UINT32_C(0x00000001), UINT32_C(0x00000001));
1579 CHECKVAL(u32, UINT32_C(0x00000001), "%#018RX32");
1580 u32 = ASMMultU32ByU32DivByU32(UINT32_C(0x10000000), UINT32_C(0x80000000), UINT32_C(0x20000000));
1581 CHECKVAL(u32, UINT32_C(0x40000000), "%#018RX32");
1582 u32 = ASMMultU32ByU32DivByU32(UINT32_C(0x76543210), UINT32_C(0xffffffff), UINT32_C(0xffffffff));
1583 CHECKVAL(u32, UINT32_C(0x76543210), "%#018RX32");
1584 u32 = ASMMultU32ByU32DivByU32(UINT32_C(0xffffffff), UINT32_C(0xffffffff), UINT32_C(0xffffffff));
1585 CHECKVAL(u32, UINT32_C(0xffffffff), "%#018RX32");
1586 u32 = ASMMultU32ByU32DivByU32(UINT32_C(0xffffffff), UINT32_C(0xfffffff0), UINT32_C(0xffffffff));
1587 CHECKVAL(u32, UINT32_C(0xfffffff0), "%#018RX32");
1588 u32 = ASMMultU32ByU32DivByU32(UINT32_C(0x10359583), UINT32_C(0x58734981), UINT32_C(0xf8694045));
1589 CHECKVAL(u32, UINT32_C(0x05c584ce), "%#018RX32");
1590 u32 = ASMMultU32ByU32DivByU32(UINT32_C(0x10359583), UINT32_C(0xf8694045), UINT32_C(0x58734981));
1591 CHECKVAL(u32, UINT32_C(0x2d860795), "%#018RX32");
1592
1593#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
1594 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x0000000000000001), UINT32_C(0x00000001), UINT32_C(0x00000001));
1595 CHECKVAL(u64, UINT64_C(0x0000000000000001), "%#018RX64");
1596 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x0000000100000000), UINT32_C(0x80000000), UINT32_C(0x00000002));
1597 CHECKVAL(u64, UINT64_C(0x4000000000000000), "%#018RX64");
1598 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xfedcba9876543210), UINT32_C(0xffffffff), UINT32_C(0xffffffff));
1599 CHECKVAL(u64, UINT64_C(0xfedcba9876543210), "%#018RX64");
1600 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xffffffffffffffff), UINT32_C(0xffffffff), UINT32_C(0xffffffff));
1601 CHECKVAL(u64, UINT64_C(0xffffffffffffffff), "%#018RX64");
1602 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xffffffffffffffff), UINT32_C(0xfffffff0), UINT32_C(0xffffffff));
1603 CHECKVAL(u64, UINT64_C(0xfffffff0fffffff0), "%#018RX64");
1604 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x3415934810359583), UINT32_C(0x58734981), UINT32_C(0xf8694045));
1605 CHECKVAL(u64, UINT64_C(0x128b9c3d43184763), "%#018RX64");
1606 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x3415934810359583), UINT32_C(0xf8694045), UINT32_C(0x58734981));
1607 CHECKVAL(u64, UINT64_C(0x924719355cd35a27), "%#018RX64");
1608
1609# if 0 /* bird: question is whether this should trap or not:
1610 *
1611 * frank: Of course it must trap:
1612 *
1613 * 0xfffffff8 * 0x77d7daf8 = 0x77d7daf441412840
1614 *
1615 * During the following division, the quotient must fit into a 32-bit register.
1616 * Therefore the smallest valid divisor is
1617 *
1618 * (0x77d7daf441412840 >> 32) + 1 = 0x77d7daf5
1619 *
1620 * which is definitely greater than 0x3b9aca00.
1621 *
1622 * bird: No, the C version does *not* crash. So, the question is whether there's any
1623 * code depending on it not crashing.
1624 *
1625 * Of course the assembly versions of the code crash right now for the reasons you've
1626 * given, but the 32-bit MSC version does not crash.
1627 *
1628 * frank: The C version does not crash but delivers incorrect results for this case.
1629 * The reason is
1630 *
1631 * u.s.Hi = (unsigned long)(u64Hi / u32C);
1632 *
1633 * Here the division is actually 64-bit by 64-bit but the 64-bit result is truncated
1634 * to 32 bit. If using this (optimized and fast) function we should just be sure that
1635 * the operands are in a valid range.
1636 */
1637 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xfffffff8c65d6731), UINT32_C(0x77d7daf8), UINT32_C(0x3b9aca00));
1638 CHECKVAL(u64, UINT64_C(0x02b8f9a2aa74e3dc), "%#018RX64");
1639# endif
1640#endif /* AMD64 || X86 */
1641
1642 u32 = ASMModU64ByU32RetU32(UINT64_C(0x0ffffff8c65d6731), UINT32_C(0x77d7daf8));
1643 CHECKVAL(u32, UINT32_C(0x3B642451), "%#010RX32");
1644
1645 int32_t i32;
1646 i32 = ASMModS64ByS32RetS32(INT64_C(-11), INT32_C(-2));
1647 CHECKVAL(i32, INT32_C(-1), "%010RI32");
1648 i32 = ASMModS64ByS32RetS32(INT64_C(-11), INT32_C(2));
1649 CHECKVAL(i32, INT32_C(-1), "%010RI32");
1650 i32 = ASMModS64ByS32RetS32(INT64_C(11), INT32_C(-2));
1651 CHECKVAL(i32, INT32_C(1), "%010RI32");
1652
1653 i32 = ASMModS64ByS32RetS32(INT64_C(92233720368547758), INT32_C(2147483647));
1654 CHECKVAL(i32, INT32_C(2104533974), "%010RI32");
1655 i32 = ASMModS64ByS32RetS32(INT64_C(-92233720368547758), INT32_C(2147483647));
1656 CHECKVAL(i32, INT32_C(-2104533974), "%010RI32");
1657}
1658
1659
1660void tstASMByteSwap(void)
1661{
1662 RTTestSub(g_hTest, "ASMByteSwap*");
1663
1664 uint64_t u64In = UINT64_C(0x0011223344556677);
1665 uint64_t u64Out = ASMByteSwapU64(u64In);
1666 CHECKVAL(u64In, UINT64_C(0x0011223344556677), "%#018RX64");
1667 CHECKVAL(u64Out, UINT64_C(0x7766554433221100), "%#018RX64");
1668 u64Out = ASMByteSwapU64(u64Out);
1669 CHECKVAL(u64Out, u64In, "%#018RX64");
1670 u64In = UINT64_C(0x0123456789abcdef);
1671 u64Out = ASMByteSwapU64(u64In);
1672 CHECKVAL(u64In, UINT64_C(0x0123456789abcdef), "%#018RX64");
1673 CHECKVAL(u64Out, UINT64_C(0xefcdab8967452301), "%#018RX64");
1674 u64Out = ASMByteSwapU64(u64Out);
1675 CHECKVAL(u64Out, u64In, "%#018RX64");
1676 u64In = 0;
1677 u64Out = ASMByteSwapU64(u64In);
1678 CHECKVAL(u64Out, u64In, "%#018RX64");
1679 u64In = UINT64_MAX;
1680 u64Out = ASMByteSwapU64(u64In);
1681 CHECKVAL(u64Out, u64In, "%#018RX64");
1682
1683 uint32_t u32In = UINT32_C(0x00112233);
1684 uint32_t u32Out = ASMByteSwapU32(u32In);
1685 CHECKVAL(u32In, UINT32_C(0x00112233), "%#010RX32");
1686 CHECKVAL(u32Out, UINT32_C(0x33221100), "%#010RX32");
1687 u32Out = ASMByteSwapU32(u32Out);
1688 CHECKVAL(u32Out, u32In, "%#010RX32");
1689 u32In = UINT32_C(0x12345678);
1690 u32Out = ASMByteSwapU32(u32In);
1691 CHECKVAL(u32In, UINT32_C(0x12345678), "%#010RX32");
1692 CHECKVAL(u32Out, UINT32_C(0x78563412), "%#010RX32");
1693 u32Out = ASMByteSwapU32(u32Out);
1694 CHECKVAL(u32Out, u32In, "%#010RX32");
1695 u32In = 0;
1696 u32Out = ASMByteSwapU32(u32In);
1697 CHECKVAL(u32Out, u32In, "%#010RX32");
1698 u32In = UINT32_MAX;
1699 u32Out = ASMByteSwapU32(u32In);
1700 CHECKVAL(u32Out, u32In, "%#010RX32");
1701
1702 uint16_t u16In = UINT16_C(0x0011);
1703 uint16_t u16Out = ASMByteSwapU16(u16In);
1704 CHECKVAL(u16In, UINT16_C(0x0011), "%#06RX16");
1705 CHECKVAL(u16Out, UINT16_C(0x1100), "%#06RX16");
1706 u16Out = ASMByteSwapU16(u16Out);
1707 CHECKVAL(u16Out, u16In, "%#06RX16");
1708 u16In = UINT16_C(0x1234);
1709 u16Out = ASMByteSwapU16(u16In);
1710 CHECKVAL(u16In, UINT16_C(0x1234), "%#06RX16");
1711 CHECKVAL(u16Out, UINT16_C(0x3412), "%#06RX16");
1712 u16Out = ASMByteSwapU16(u16Out);
1713 CHECKVAL(u16Out, u16In, "%#06RX16");
1714 u16In = 0;
1715 u16Out = ASMByteSwapU16(u16In);
1716 CHECKVAL(u16Out, u16In, "%#06RX16");
1717 u16In = UINT16_MAX;
1718 u16Out = ASMByteSwapU16(u16In);
1719 CHECKVAL(u16Out, u16In, "%#06RX16");
1720}
1721
1722
1723void tstASMBench(void)
1724{
1725 /*
1726 * Make this static. We don't want to have this located on the stack.
1727 */
1728 static uint8_t volatile s_u8;
1729 static int8_t volatile s_i8;
1730 static uint16_t volatile s_u16;
1731 static int16_t volatile s_i16;
1732 static uint32_t volatile s_u32;
1733 static int32_t volatile s_i32;
1734 static uint64_t volatile s_u64;
1735 static int64_t volatile s_i64;
1736 register unsigned i;
1737 const unsigned cRounds = _2M; /* Must be multiple of 8 */
1738 register uint64_t u64Elapsed;
1739
1740 RTTestSub(g_hTest, "Benchmarking");
1741
1742#if 0 && !defined(GCC44_32BIT_PIC) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86))
1743# define BENCH(op, str) \
1744 do { \
1745 RTThreadYield(); \
1746 u64Elapsed = ASMReadTSC(); \
1747 for (i = cRounds; i > 0; i--) \
1748 op; \
1749 u64Elapsed = ASMReadTSC() - u64Elapsed; \
1750 RTTestValue(g_hTest, str, u64Elapsed / cRounds, RTTESTUNIT_TICKS_PER_CALL); \
1751 } while (0)
1752#else
1753# define BENCH(op, str) \
1754 do { \
1755 RTThreadYield(); \
1756 u64Elapsed = RTTimeNanoTS(); \
1757 for (i = cRounds / 8; i > 0; i--) \
1758 { \
1759 op; \
1760 op; \
1761 op; \
1762 op; \
1763 op; \
1764 op; \
1765 op; \
1766 op; \
1767 } \
1768 u64Elapsed = RTTimeNanoTS() - u64Elapsed; \
1769 RTTestValue(g_hTest, str, u64Elapsed / cRounds, RTTESTUNIT_NS_PER_CALL); \
1770 } while (0)
1771#endif
1772#if (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) && !defined(GCC44_32BIT_PIC)
1773# define BENCH_TSC(op, str) \
1774 do { \
1775 RTThreadYield(); \
1776 u64Elapsed = ASMReadTSC(); \
1777 for (i = cRounds / 8; i > 0; i--) \
1778 { \
1779 op; \
1780 op; \
1781 op; \
1782 op; \
1783 op; \
1784 op; \
1785 op; \
1786 op; \
1787 } \
1788 u64Elapsed = ASMReadTSC() - u64Elapsed; \
1789 RTTestValue(g_hTest, str, u64Elapsed / cRounds, /*RTTESTUNIT_TICKS_PER_CALL*/ RTTESTUNIT_NONE); \
1790 } while (0)
1791#else
1792# define BENCH_TSC(op, str) BENCH(op, str)
1793#endif
1794
1795 BENCH(s_u32 = 0, "s_u32 = 0");
1796 BENCH(ASMAtomicUoReadU8(&s_u8), "ASMAtomicUoReadU8");
1797 BENCH(ASMAtomicUoReadS8(&s_i8), "ASMAtomicUoReadS8");
1798 BENCH(ASMAtomicUoReadU16(&s_u16), "ASMAtomicUoReadU16");
1799 BENCH(ASMAtomicUoReadS16(&s_i16), "ASMAtomicUoReadS16");
1800 BENCH(ASMAtomicUoReadU32(&s_u32), "ASMAtomicUoReadU32");
1801 BENCH(ASMAtomicUoReadS32(&s_i32), "ASMAtomicUoReadS32");
1802 BENCH(ASMAtomicUoReadU64(&s_u64), "ASMAtomicUoReadU64");
1803 BENCH(ASMAtomicUoReadS64(&s_i64), "ASMAtomicUoReadS64");
1804 BENCH(ASMAtomicReadU8(&s_u8), "ASMAtomicReadU8");
1805 BENCH(ASMAtomicReadS8(&s_i8), "ASMAtomicReadS8");
1806 BENCH(ASMAtomicReadU16(&s_u16), "ASMAtomicReadU16");
1807 BENCH(ASMAtomicReadS16(&s_i16), "ASMAtomicReadS16");
1808 BENCH(ASMAtomicReadU32(&s_u32), "ASMAtomicReadU32");
1809 BENCH(ASMAtomicReadS32(&s_i32), "ASMAtomicReadS32");
1810 BENCH(ASMAtomicReadU64(&s_u64), "ASMAtomicReadU64");
1811 BENCH(ASMAtomicReadS64(&s_i64), "ASMAtomicReadS64");
1812 BENCH(ASMAtomicUoWriteU8(&s_u8, 0), "ASMAtomicUoWriteU8");
1813 BENCH(ASMAtomicUoWriteS8(&s_i8, 0), "ASMAtomicUoWriteS8");
1814 BENCH(ASMAtomicUoWriteU16(&s_u16, 0), "ASMAtomicUoWriteU16");
1815 BENCH(ASMAtomicUoWriteS16(&s_i16, 0), "ASMAtomicUoWriteS16");
1816 BENCH(ASMAtomicUoWriteU32(&s_u32, 0), "ASMAtomicUoWriteU32");
1817 BENCH(ASMAtomicUoWriteS32(&s_i32, 0), "ASMAtomicUoWriteS32");
1818 BENCH(ASMAtomicUoWriteU64(&s_u64, 0), "ASMAtomicUoWriteU64");
1819 BENCH(ASMAtomicUoWriteS64(&s_i64, 0), "ASMAtomicUoWriteS64");
1820 BENCH(ASMAtomicWriteU8(&s_u8, 0), "ASMAtomicWriteU8");
1821 BENCH(ASMAtomicWriteS8(&s_i8, 0), "ASMAtomicWriteS8");
1822 BENCH(ASMAtomicWriteU16(&s_u16, 0), "ASMAtomicWriteU16");
1823 BENCH(ASMAtomicWriteS16(&s_i16, 0), "ASMAtomicWriteS16");
1824 BENCH(ASMAtomicWriteU32(&s_u32, 0), "ASMAtomicWriteU32");
1825 BENCH(ASMAtomicWriteS32(&s_i32, 0), "ASMAtomicWriteS32");
1826 BENCH(ASMAtomicWriteU64(&s_u64, 0), "ASMAtomicWriteU64");
1827 BENCH(ASMAtomicWriteS64(&s_i64, 0), "ASMAtomicWriteS64");
1828 BENCH(ASMAtomicXchgU8(&s_u8, 0), "ASMAtomicXchgU8");
1829 BENCH(ASMAtomicXchgS8(&s_i8, 0), "ASMAtomicXchgS8");
1830 BENCH(ASMAtomicXchgU16(&s_u16, 0), "ASMAtomicXchgU16");
1831 BENCH(ASMAtomicXchgS16(&s_i16, 0), "ASMAtomicXchgS16");
1832 BENCH(ASMAtomicXchgU32(&s_u32, 0), "ASMAtomicXchgU32");
1833 BENCH(ASMAtomicXchgS32(&s_i32, 0), "ASMAtomicXchgS32");
1834 BENCH(ASMAtomicXchgU64(&s_u64, 0), "ASMAtomicXchgU64");
1835 BENCH(ASMAtomicXchgS64(&s_i64, 0), "ASMAtomicXchgS64");
1836 BENCH(ASMAtomicCmpXchgU32(&s_u32, 0, 0), "ASMAtomicCmpXchgU32");
1837 BENCH(ASMAtomicCmpXchgS32(&s_i32, 0, 0), "ASMAtomicCmpXchgS32");
1838 BENCH(ASMAtomicCmpXchgU64(&s_u64, 0, 0), "ASMAtomicCmpXchgU64");
1839 BENCH(ASMAtomicCmpXchgS64(&s_i64, 0, 0), "ASMAtomicCmpXchgS64");
1840 BENCH(ASMAtomicCmpXchgU32(&s_u32, 0, 1), "ASMAtomicCmpXchgU32/neg");
1841 BENCH(ASMAtomicCmpXchgS32(&s_i32, 0, 1), "ASMAtomicCmpXchgS32/neg");
1842 BENCH(ASMAtomicCmpXchgU64(&s_u64, 0, 1), "ASMAtomicCmpXchgU64/neg");
1843 BENCH(ASMAtomicCmpXchgS64(&s_i64, 0, 1), "ASMAtomicCmpXchgS64/neg");
1844 BENCH(ASMAtomicIncU32(&s_u32), "ASMAtomicIncU32");
1845 BENCH(ASMAtomicIncS32(&s_i32), "ASMAtomicIncS32");
1846 BENCH(ASMAtomicDecU32(&s_u32), "ASMAtomicDecU32");
1847 BENCH(ASMAtomicDecS32(&s_i32), "ASMAtomicDecS32");
1848 BENCH(ASMAtomicAddU32(&s_u32, 5), "ASMAtomicAddU32");
1849 BENCH(ASMAtomicAddS32(&s_i32, 5), "ASMAtomicAddS32");
1850 BENCH(ASMAtomicUoIncU32(&s_u32), "ASMAtomicUoIncU32");
1851 BENCH(ASMAtomicUoDecU32(&s_u32), "ASMAtomicUoDecU32");
1852 BENCH(ASMAtomicUoAndU32(&s_u32, 0xffffffff), "ASMAtomicUoAndU32");
1853 BENCH(ASMAtomicUoOrU32(&s_u32, 0xffffffff), "ASMAtomicUoOrU32");
1854 BENCH_TSC(ASMSerializeInstructionCpuId(), "ASMSerializeInstructionCpuId");
1855 BENCH_TSC(ASMSerializeInstructionIRet(), "ASMSerializeInstructionIRet");
1856
1857 /* The Darwin gcc does not like this ... */
1858#if !defined(RT_OS_DARWIN) && !defined(GCC44_32BIT_PIC) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86))
1859 BENCH(s_u8 = ASMGetApicId(), "ASMGetApicId");
1860#endif
1861#if !defined(GCC44_32BIT_PIC) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86))
1862 uint32_t uAux;
1863 if ( ASMHasCpuId()
1864 && ASMIsValidExtRange(ASMCpuId_EAX(0x80000000))
1865 && (ASMCpuId_EDX(0x80000001) & X86_CPUID_EXT_FEATURE_EDX_RDTSCP) )
1866 {
1867 BENCH_TSC(ASMSerializeInstructionRdTscp(), "ASMSerializeInstructionRdTscp");
1868 BENCH(s_u64 = ASMReadTscWithAux(&uAux), "ASMReadTscWithAux");
1869 }
1870 BENCH(s_u64 = ASMReadTSC(), "ASMReadTSC");
1871 union
1872 {
1873 uint64_t u64[2];
1874 RTIDTR Unaligned;
1875 struct
1876 {
1877 uint16_t abPadding[3];
1878 RTIDTR Aligned;
1879 } s;
1880 } uBuf;
1881 Assert(((uintptr_t)&uBuf.Unaligned.pIdt & (sizeof(uintptr_t) - 1)) != 0);
1882 BENCH(ASMGetIDTR(&uBuf.Unaligned), "ASMGetIDTR/unaligned");
1883 Assert(((uintptr_t)&uBuf.s.Aligned.pIdt & (sizeof(uintptr_t) - 1)) == 0);
1884 BENCH(ASMGetIDTR(&uBuf.s.Aligned), "ASMGetIDTR/aligned");
1885#endif
1886
1887#undef BENCH
1888}
1889
1890
1891int main(int argc, char **argv)
1892{
1893 RT_NOREF_PV(argc); RT_NOREF_PV(argv);
1894
1895 int rc = RTTestInitAndCreate("tstRTInlineAsm", &g_hTest);
1896 if (rc)
1897 return rc;
1898 RTTestBanner(g_hTest);
1899
1900 /*
1901 * Execute the tests.
1902 */
1903#if !defined(GCC44_32BIT_PIC) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86))
1904 tstASMCpuId();
1905 //bruteForceCpuId();
1906#endif
1907#if 1
1908 tstASMAtomicXchgU8();
1909 tstASMAtomicXchgU16();
1910 tstASMAtomicXchgU32();
1911 tstASMAtomicXchgU64();
1912 tstASMAtomicXchgPtr();
1913 tstASMAtomicCmpXchgU8();
1914 tstASMAtomicCmpXchgU32();
1915 tstASMAtomicCmpXchgU64();
1916 tstASMAtomicCmpXchgExU32();
1917 tstASMAtomicCmpXchgExU64();
1918 tstASMAtomicReadU64();
1919 tstASMAtomicUoReadU64();
1920
1921 tstASMAtomicAddS32();
1922 tstASMAtomicAddS64();
1923 tstASMAtomicDecIncS32();
1924 tstASMAtomicDecIncS64();
1925 tstASMAtomicAndOrU32();
1926 tstASMAtomicAndOrU64();
1927
1928 tstASMAtomicUoIncU32();
1929 tstASMAtomicUoDecU32();
1930 tstASMAtomicUoAndOrU32();
1931
1932 tstASMMemZeroPage();
1933 tstASMMemIsZeroPage(g_hTest);
1934 tstASMMemFirstMismatchingU8(g_hTest);
1935 tstASMMemZero32();
1936 tstASMMemFill32();
1937
1938 tstASMMath();
1939
1940 tstASMByteSwap();
1941
1942 tstASMBench();
1943#endif
1944
1945 /*
1946 * Show the result.
1947 */
1948 return RTTestSummaryAndDestroy(g_hTest);
1949}
1950
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