VirtualBox

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

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

IPRT/tstRTInlineAsm.cpp: Mark cache association string leak. bugref:9841

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