VirtualBox

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

Last change on this file since 85546 was 85072, checked in by vboxsync, 4 years ago

tstRTInlineAsm.cpp: Stop using the 'register' keyword, Clang barfs on it in C++11 mode. bugref:9790

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