VirtualBox

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

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

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