VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstInlineAsm.cpp@ 30016

Last change on this file since 30016 was 29279, checked in by vboxsync, 14 years ago

Runtime: Made solaris.sparc64 link and run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 47.4 KB
Line 
1/* $Id: tstInlineAsm.cpp 29279 2010-05-09 23:29:11Z vboxsync $ */
2/** @file
3 * IPRT Testcase - inline assembly.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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* Header Files *
29*******************************************************************************/
30#include <iprt/asm.h>
31#include <iprt/asm-math.h>
32#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
33# include <iprt/asm-amd64-x86.h>
34#else
35# include <iprt/time.h>
36#endif
37#include <iprt/stream.h>
38#include <iprt/string.h>
39#include <iprt/initterm.h>
40#include <iprt/param.h>
41#include <iprt/thread.h>
42#include <iprt/test.h>
43
44
45
46/*******************************************************************************
47* Defined Constants And Macros *
48*******************************************************************************/
49#define CHECKVAL(val, expect, fmt) \
50 do \
51 { \
52 if ((val) != (expect)) \
53 { \
54 RTTestIErrorInc(); \
55 RTPrintf("%s, %d: " #val ": expected " fmt " got " fmt "\n", __FUNCTION__, __LINE__, (expect), (val)); \
56 } \
57 } while (0)
58
59#define CHECKOP(op, expect, fmt, type) \
60 do \
61 { \
62 type val = op; \
63 if (val != (type)(expect)) \
64 { \
65 RTTestIErrorInc(); \
66 RTPrintf("%s, %d: " #op ": expected " fmt " got " fmt "\n", __FUNCTION__, __LINE__, (type)(expect), val); \
67 } \
68 } while (0)
69
70
71#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
72
73const char *getCacheAss(unsigned u)
74{
75 if (u == 0)
76 return "res0 ";
77 if (u == 1)
78 return "direct";
79 if (u >= 256)
80 return "???";
81
82 char *pszRet;
83 RTStrAPrintf(&pszRet, "%d way", u); /* intentional leak! */
84 return pszRet;
85}
86
87
88const char *getL2CacheAss(unsigned u)
89{
90 switch (u)
91 {
92 case 0: return "off ";
93 case 1: return "direct";
94 case 2: return "2 way ";
95 case 3: return "res3 ";
96 case 4: return "4 way ";
97 case 5: return "res5 ";
98 case 6: return "8 way ";
99 case 7: return "res7 ";
100 case 8: return "16 way";
101 case 9: return "res9 ";
102 case 10: return "res10 ";
103 case 11: return "res11 ";
104 case 12: return "res12 ";
105 case 13: return "res13 ";
106 case 14: return "res14 ";
107 case 15: return "fully ";
108 default:
109 return "????";
110 }
111}
112
113
114/**
115 * Test and dump all possible info from the CPUID instruction.
116 *
117 * @remark Bits shared with the libc cpuid.c program. This all written by me, so no worries.
118 * @todo transform the dumping into a generic runtime function. We'll need it for logging!
119 */
120void tstASMCpuId(void)
121{
122 unsigned iBit;
123 struct
124 {
125 uint32_t uEBX, uEAX, uEDX, uECX;
126 } s;
127 if (!ASMHasCpuId())
128 {
129 RTPrintf("tstInlineAsm: warning! CPU doesn't support CPUID\n");
130 return;
131 }
132
133 /*
134 * Try the 0 function and use that for checking the ASMCpuId_* variants.
135 */
136 ASMCpuId(0, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
137
138 uint32_t u32 = ASMCpuId_ECX(0);
139 CHECKVAL(u32, s.uECX, "%x");
140
141 u32 = ASMCpuId_EDX(0);
142 CHECKVAL(u32, s.uEDX, "%x");
143
144 uint32_t uECX2 = s.uECX - 1;
145 uint32_t uEDX2 = s.uEDX - 1;
146 ASMCpuId_ECX_EDX(0, &uECX2, &uEDX2);
147
148 CHECKVAL(uECX2, s.uECX, "%x");
149 CHECKVAL(uEDX2, s.uEDX, "%x");
150
151 /*
152 * Done testing, dump the information.
153 */
154 RTPrintf("tstInlineAsm: CPUID Dump\n");
155 ASMCpuId(0, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
156 const uint32_t cFunctions = s.uEAX;
157
158 /* raw dump */
159 RTPrintf("\n"
160 " RAW Standard CPUIDs\n"
161 "Function eax ebx ecx edx\n");
162 for (unsigned iStd = 0; iStd <= cFunctions + 3; iStd++)
163 {
164 ASMCpuId(iStd, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
165 RTPrintf("%08x %08x %08x %08x %08x%s\n",
166 iStd, s.uEAX, s.uEBX, s.uECX, s.uEDX, iStd <= cFunctions ? "" : "*");
167 }
168
169 /*
170 * Understandable output
171 */
172 ASMCpuId(0, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
173 RTPrintf("Name: %.04s%.04s%.04s\n"
174 "Support: 0-%u\n",
175 &s.uEBX, &s.uEDX, &s.uECX, s.uEAX);
176 bool const fIntel = ASMIsIntelCpuEx(s.uEBX, s.uECX, s.uEDX);
177
178 /*
179 * Get Features.
180 */
181 if (cFunctions >= 1)
182 {
183 ASMCpuId(1, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
184 RTPrintf("Family: %#x \tExtended: %#x \tEffective: %#x\n"
185 "Model: %#x \tExtended: %#x \tEffective: %#x\n"
186 "Stepping: %d\n"
187 "APIC ID: %#04x\n"
188 "Logical CPUs: %d\n"
189 "CLFLUSH Size: %d\n"
190 "Brand ID: %#04x\n",
191 (s.uEAX >> 8) & 0xf, (s.uEAX >> 20) & 0x7f, ASMGetCpuFamily(s.uEAX),
192 (s.uEAX >> 4) & 0xf, (s.uEAX >> 16) & 0x0f, ASMGetCpuModel(s.uEAX, fIntel),
193 ASMGetCpuStepping(s.uEAX),
194 (s.uEBX >> 24) & 0xff,
195 (s.uEBX >> 16) & 0xff,
196 (s.uEBX >> 8) & 0xff,
197 (s.uEBX >> 0) & 0xff);
198
199 RTPrintf("Features EDX: ");
200 if (s.uEDX & RT_BIT(0)) RTPrintf(" FPU");
201 if (s.uEDX & RT_BIT(1)) RTPrintf(" VME");
202 if (s.uEDX & RT_BIT(2)) RTPrintf(" DE");
203 if (s.uEDX & RT_BIT(3)) RTPrintf(" PSE");
204 if (s.uEDX & RT_BIT(4)) RTPrintf(" TSC");
205 if (s.uEDX & RT_BIT(5)) RTPrintf(" MSR");
206 if (s.uEDX & RT_BIT(6)) RTPrintf(" PAE");
207 if (s.uEDX & RT_BIT(7)) RTPrintf(" MCE");
208 if (s.uEDX & RT_BIT(8)) RTPrintf(" CX8");
209 if (s.uEDX & RT_BIT(9)) RTPrintf(" APIC");
210 if (s.uEDX & RT_BIT(10)) RTPrintf(" 10");
211 if (s.uEDX & RT_BIT(11)) RTPrintf(" SEP");
212 if (s.uEDX & RT_BIT(12)) RTPrintf(" MTRR");
213 if (s.uEDX & RT_BIT(13)) RTPrintf(" PGE");
214 if (s.uEDX & RT_BIT(14)) RTPrintf(" MCA");
215 if (s.uEDX & RT_BIT(15)) RTPrintf(" CMOV");
216 if (s.uEDX & RT_BIT(16)) RTPrintf(" PAT");
217 if (s.uEDX & RT_BIT(17)) RTPrintf(" PSE36");
218 if (s.uEDX & RT_BIT(18)) RTPrintf(" PSN");
219 if (s.uEDX & RT_BIT(19)) RTPrintf(" CLFSH");
220 if (s.uEDX & RT_BIT(20)) RTPrintf(" 20");
221 if (s.uEDX & RT_BIT(21)) RTPrintf(" DS");
222 if (s.uEDX & RT_BIT(22)) RTPrintf(" ACPI");
223 if (s.uEDX & RT_BIT(23)) RTPrintf(" MMX");
224 if (s.uEDX & RT_BIT(24)) RTPrintf(" FXSR");
225 if (s.uEDX & RT_BIT(25)) RTPrintf(" SSE");
226 if (s.uEDX & RT_BIT(26)) RTPrintf(" SSE2");
227 if (s.uEDX & RT_BIT(27)) RTPrintf(" SS");
228 if (s.uEDX & RT_BIT(28)) RTPrintf(" HTT");
229 if (s.uEDX & RT_BIT(29)) RTPrintf(" 29");
230 if (s.uEDX & RT_BIT(30)) RTPrintf(" 30");
231 if (s.uEDX & RT_BIT(31)) RTPrintf(" 31");
232 RTPrintf("\n");
233
234 /** @todo check intel docs. */
235 RTPrintf("Features ECX: ");
236 if (s.uECX & RT_BIT(0)) RTPrintf(" SSE3");
237 for (iBit = 1; iBit < 13; iBit++)
238 if (s.uECX & RT_BIT(iBit))
239 RTPrintf(" %d", iBit);
240 if (s.uECX & RT_BIT(13)) RTPrintf(" CX16");
241 for (iBit = 14; iBit < 32; iBit++)
242 if (s.uECX & RT_BIT(iBit))
243 RTPrintf(" %d", iBit);
244 RTPrintf("\n");
245 }
246
247 /*
248 * Extended.
249 * Implemented after AMD specs.
250 */
251 /** @todo check out the intel specs. */
252 ASMCpuId(0x80000000, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
253 if (!s.uEAX && !s.uEBX && !s.uECX && !s.uEDX)
254 {
255 RTPrintf("No extended CPUID info? Check the manual on how to detect this...\n");
256 return;
257 }
258 const uint32_t cExtFunctions = s.uEAX | 0x80000000;
259
260 /* raw dump */
261 RTPrintf("\n"
262 " RAW Extended CPUIDs\n"
263 "Function eax ebx ecx edx\n");
264 for (unsigned iExt = 0x80000000; iExt <= cExtFunctions + 3; iExt++)
265 {
266 ASMCpuId(iExt, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
267 RTPrintf("%08x %08x %08x %08x %08x%s\n",
268 iExt, s.uEAX, s.uEBX, s.uECX, s.uEDX, iExt <= cExtFunctions ? "" : "*");
269 }
270
271 /*
272 * Understandable output
273 */
274 ASMCpuId(0x80000000, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
275 RTPrintf("Ext Name: %.4s%.4s%.4s\n"
276 "Ext Supports: 0x80000000-%#010x\n",
277 &s.uEBX, &s.uEDX, &s.uECX, s.uEAX);
278
279 if (cExtFunctions >= 0x80000001)
280 {
281 ASMCpuId(0x80000001, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
282 RTPrintf("Family: %#x \tExtended: %#x \tEffective: %#x\n"
283 "Model: %#x \tExtended: %#x \tEffective: %#x\n"
284 "Stepping: %d\n"
285 "Brand ID: %#05x\n",
286 (s.uEAX >> 8) & 0xf, (s.uEAX >> 20) & 0x7f, ASMGetCpuFamily(s.uEAX),
287 (s.uEAX >> 4) & 0xf, (s.uEAX >> 16) & 0x0f, ASMGetCpuModel(s.uEAX, fIntel),
288 ASMGetCpuStepping(s.uEAX),
289 s.uEBX & 0xfff);
290
291 RTPrintf("Features EDX: ");
292 if (s.uEDX & RT_BIT(0)) RTPrintf(" FPU");
293 if (s.uEDX & RT_BIT(1)) RTPrintf(" VME");
294 if (s.uEDX & RT_BIT(2)) RTPrintf(" DE");
295 if (s.uEDX & RT_BIT(3)) RTPrintf(" PSE");
296 if (s.uEDX & RT_BIT(4)) RTPrintf(" TSC");
297 if (s.uEDX & RT_BIT(5)) RTPrintf(" MSR");
298 if (s.uEDX & RT_BIT(6)) RTPrintf(" PAE");
299 if (s.uEDX & RT_BIT(7)) RTPrintf(" MCE");
300 if (s.uEDX & RT_BIT(8)) RTPrintf(" CMPXCHG8B");
301 if (s.uEDX & RT_BIT(9)) RTPrintf(" APIC");
302 if (s.uEDX & RT_BIT(10)) RTPrintf(" 10");
303 if (s.uEDX & RT_BIT(11)) RTPrintf(" SysCallSysRet");
304 if (s.uEDX & RT_BIT(12)) RTPrintf(" MTRR");
305 if (s.uEDX & RT_BIT(13)) RTPrintf(" PGE");
306 if (s.uEDX & RT_BIT(14)) RTPrintf(" MCA");
307 if (s.uEDX & RT_BIT(15)) RTPrintf(" CMOV");
308 if (s.uEDX & RT_BIT(16)) RTPrintf(" PAT");
309 if (s.uEDX & RT_BIT(17)) RTPrintf(" PSE36");
310 if (s.uEDX & RT_BIT(18)) RTPrintf(" 18");
311 if (s.uEDX & RT_BIT(19)) RTPrintf(" 19");
312 if (s.uEDX & RT_BIT(20)) RTPrintf(" NX");
313 if (s.uEDX & RT_BIT(21)) RTPrintf(" 21");
314 if (s.uEDX & RT_BIT(22)) RTPrintf(" MmxExt");
315 if (s.uEDX & RT_BIT(23)) RTPrintf(" MMX");
316 if (s.uEDX & RT_BIT(24)) RTPrintf(" FXSR");
317 if (s.uEDX & RT_BIT(25)) RTPrintf(" FastFXSR");
318 if (s.uEDX & RT_BIT(26)) RTPrintf(" 26");
319 if (s.uEDX & RT_BIT(27)) RTPrintf(" RDTSCP");
320 if (s.uEDX & RT_BIT(28)) RTPrintf(" 28");
321 if (s.uEDX & RT_BIT(29)) RTPrintf(" LongMode");
322 if (s.uEDX & RT_BIT(30)) RTPrintf(" 3DNowExt");
323 if (s.uEDX & RT_BIT(31)) RTPrintf(" 3DNow");
324 RTPrintf("\n");
325
326 RTPrintf("Features ECX: ");
327 if (s.uECX & RT_BIT(0)) RTPrintf(" LahfSahf");
328 if (s.uECX & RT_BIT(1)) RTPrintf(" CmpLegacy");
329 if (s.uECX & RT_BIT(2)) RTPrintf(" SVM");
330 if (s.uECX & RT_BIT(3)) RTPrintf(" 3");
331 if (s.uECX & RT_BIT(4)) RTPrintf(" AltMovCr8");
332 for (iBit = 5; iBit < 32; iBit++)
333 if (s.uECX & RT_BIT(iBit))
334 RTPrintf(" %d", iBit);
335 RTPrintf("\n");
336 }
337
338 char szString[4*4*3+1] = {0};
339 if (cExtFunctions >= 0x80000002)
340 ASMCpuId(0x80000002, &szString[0 + 0], &szString[0 + 4], &szString[0 + 8], &szString[0 + 12]);
341 if (cExtFunctions >= 0x80000003)
342 ASMCpuId(0x80000003, &szString[16 + 0], &szString[16 + 4], &szString[16 + 8], &szString[16 + 12]);
343 if (cExtFunctions >= 0x80000004)
344 ASMCpuId(0x80000004, &szString[32 + 0], &szString[32 + 4], &szString[32 + 8], &szString[32 + 12]);
345 if (cExtFunctions >= 0x80000002)
346 RTPrintf("Full Name: %s\n", szString);
347
348 if (cExtFunctions >= 0x80000005)
349 {
350 ASMCpuId(0x80000005, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
351 RTPrintf("TLB 2/4M Instr/Uni: %s %3d entries\n"
352 "TLB 2/4M Data: %s %3d entries\n",
353 getCacheAss((s.uEAX >> 8) & 0xff), (s.uEAX >> 0) & 0xff,
354 getCacheAss((s.uEAX >> 24) & 0xff), (s.uEAX >> 16) & 0xff);
355 RTPrintf("TLB 4K Instr/Uni: %s %3d entries\n"
356 "TLB 4K Data: %s %3d entries\n",
357 getCacheAss((s.uEBX >> 8) & 0xff), (s.uEBX >> 0) & 0xff,
358 getCacheAss((s.uEBX >> 24) & 0xff), (s.uEBX >> 16) & 0xff);
359 RTPrintf("L1 Instr Cache Line Size: %d bytes\n"
360 "L1 Instr Cache Lines Per Tag: %d\n"
361 "L1 Instr Cache Associativity: %s\n"
362 "L1 Instr Cache Size: %d KB\n",
363 (s.uEDX >> 0) & 0xff,
364 (s.uEDX >> 8) & 0xff,
365 getCacheAss((s.uEDX >> 16) & 0xff),
366 (s.uEDX >> 24) & 0xff);
367 RTPrintf("L1 Data Cache Line Size: %d bytes\n"
368 "L1 Data Cache Lines Per Tag: %d\n"
369 "L1 Data Cache Associativity: %s\n"
370 "L1 Data Cache Size: %d KB\n",
371 (s.uECX >> 0) & 0xff,
372 (s.uECX >> 8) & 0xff,
373 getCacheAss((s.uECX >> 16) & 0xff),
374 (s.uECX >> 24) & 0xff);
375 }
376
377 if (cExtFunctions >= 0x80000006)
378 {
379 ASMCpuId(0x80000006, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
380 RTPrintf("L2 TLB 2/4M Instr/Uni: %s %4d entries\n"
381 "L2 TLB 2/4M Data: %s %4d entries\n",
382 getL2CacheAss((s.uEAX >> 12) & 0xf), (s.uEAX >> 0) & 0xfff,
383 getL2CacheAss((s.uEAX >> 28) & 0xf), (s.uEAX >> 16) & 0xfff);
384 RTPrintf("L2 TLB 4K Instr/Uni: %s %4d entries\n"
385 "L2 TLB 4K Data: %s %4d entries\n",
386 getL2CacheAss((s.uEBX >> 12) & 0xf), (s.uEBX >> 0) & 0xfff,
387 getL2CacheAss((s.uEBX >> 28) & 0xf), (s.uEBX >> 16) & 0xfff);
388 RTPrintf("L2 Cache Line Size: %d bytes\n"
389 "L2 Cache Lines Per Tag: %d\n"
390 "L2 Cache Associativity: %s\n"
391 "L2 Cache Size: %d KB\n",
392 (s.uEDX >> 0) & 0xff,
393 (s.uEDX >> 8) & 0xf,
394 getL2CacheAss((s.uEDX >> 12) & 0xf),
395 (s.uEDX >> 16) & 0xffff);
396 }
397
398 if (cExtFunctions >= 0x80000007)
399 {
400 ASMCpuId(0x80000007, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
401 RTPrintf("APM Features: ");
402 if (s.uEDX & RT_BIT(0)) RTPrintf(" TS");
403 if (s.uEDX & RT_BIT(1)) RTPrintf(" FID");
404 if (s.uEDX & RT_BIT(2)) RTPrintf(" VID");
405 if (s.uEDX & RT_BIT(3)) RTPrintf(" TTP");
406 if (s.uEDX & RT_BIT(4)) RTPrintf(" TM");
407 if (s.uEDX & RT_BIT(5)) RTPrintf(" STC");
408 if (s.uEDX & RT_BIT(6)) RTPrintf(" 6");
409 if (s.uEDX & RT_BIT(7)) RTPrintf(" 7");
410 if (s.uEDX & RT_BIT(8)) RTPrintf(" TscInvariant");
411 for (iBit = 9; iBit < 32; iBit++)
412 if (s.uEDX & RT_BIT(iBit))
413 RTPrintf(" %d", iBit);
414 RTPrintf("\n");
415 }
416
417 if (cExtFunctions >= 0x80000008)
418 {
419 ASMCpuId(0x80000008, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
420 RTPrintf("Physical Address Width: %d bits\n"
421 "Virtual Address Width: %d bits\n",
422 (s.uEAX >> 0) & 0xff,
423 (s.uEAX >> 8) & 0xff);
424 RTPrintf("Physical Core Count: %d\n",
425 ((s.uECX >> 0) & 0xff) + 1);
426 if ((s.uECX >> 12) & 0xf)
427 RTPrintf("ApicIdCoreIdSize: %d bits\n", (s.uECX >> 12) & 0xf);
428 }
429
430 if (cExtFunctions >= 0x8000000a)
431 {
432 ASMCpuId(0x8000000a, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
433 RTPrintf("SVM Revision: %d (%#x)\n"
434 "Number of Address Space IDs: %d (%#x)\n",
435 s.uEAX & 0xff, s.uEAX & 0xff,
436 s.uEBX, s.uEBX);
437 }
438}
439
440#endif /* AMD64 || X86 */
441
442static void tstASMAtomicXchgU8(void)
443{
444 struct
445 {
446 uint8_t u8Dummy0;
447 uint8_t u8;
448 uint8_t u8Dummy1;
449 } s;
450
451 s.u8 = 0;
452 s.u8Dummy0 = s.u8Dummy1 = 0x42;
453 CHECKOP(ASMAtomicXchgU8(&s.u8, 1), 0, "%#x", uint8_t);
454 CHECKVAL(s.u8, 1, "%#x");
455
456 CHECKOP(ASMAtomicXchgU8(&s.u8, 0), 1, "%#x", uint8_t);
457 CHECKVAL(s.u8, 0, "%#x");
458
459 CHECKOP(ASMAtomicXchgU8(&s.u8, 0xff), 0, "%#x", uint8_t);
460 CHECKVAL(s.u8, 0xff, "%#x");
461
462 CHECKOP(ASMAtomicXchgU8(&s.u8, 0x87), 0xffff, "%#x", uint8_t);
463 CHECKVAL(s.u8, 0x87, "%#x");
464 CHECKVAL(s.u8Dummy0, 0x42, "%#x");
465 CHECKVAL(s.u8Dummy1, 0x42, "%#x");
466}
467
468
469static void tstASMAtomicXchgU16(void)
470{
471 struct
472 {
473 uint16_t u16Dummy0;
474 uint16_t u16;
475 uint16_t u16Dummy1;
476 } s;
477
478 s.u16 = 0;
479 s.u16Dummy0 = s.u16Dummy1 = 0x1234;
480 CHECKOP(ASMAtomicXchgU16(&s.u16, 1), 0, "%#x", uint16_t);
481 CHECKVAL(s.u16, 1, "%#x");
482
483 CHECKOP(ASMAtomicXchgU16(&s.u16, 0), 1, "%#x", uint16_t);
484 CHECKVAL(s.u16, 0, "%#x");
485
486 CHECKOP(ASMAtomicXchgU16(&s.u16, 0xffff), 0, "%#x", uint16_t);
487 CHECKVAL(s.u16, 0xffff, "%#x");
488
489 CHECKOP(ASMAtomicXchgU16(&s.u16, 0x8765), 0xffff, "%#x", uint16_t);
490 CHECKVAL(s.u16, 0x8765, "%#x");
491 CHECKVAL(s.u16Dummy0, 0x1234, "%#x");
492 CHECKVAL(s.u16Dummy1, 0x1234, "%#x");
493}
494
495
496static void tstASMAtomicXchgU32(void)
497{
498 struct
499 {
500 uint32_t u32Dummy0;
501 uint32_t u32;
502 uint32_t u32Dummy1;
503 } s;
504
505 s.u32 = 0;
506 s.u32Dummy0 = s.u32Dummy1 = 0x11223344;
507
508 CHECKOP(ASMAtomicXchgU32(&s.u32, 1), 0, "%#x", uint32_t);
509 CHECKVAL(s.u32, 1, "%#x");
510
511 CHECKOP(ASMAtomicXchgU32(&s.u32, 0), 1, "%#x", uint32_t);
512 CHECKVAL(s.u32, 0, "%#x");
513
514 CHECKOP(ASMAtomicXchgU32(&s.u32, ~0U), 0, "%#x", uint32_t);
515 CHECKVAL(s.u32, ~0U, "%#x");
516
517 CHECKOP(ASMAtomicXchgU32(&s.u32, 0x87654321), ~0U, "%#x", uint32_t);
518 CHECKVAL(s.u32, 0x87654321, "%#x");
519
520 CHECKVAL(s.u32Dummy0, 0x11223344, "%#x");
521 CHECKVAL(s.u32Dummy1, 0x11223344, "%#x");
522}
523
524
525static void tstASMAtomicXchgU64(void)
526{
527 struct
528 {
529 uint64_t u64Dummy0;
530 uint64_t u64;
531 uint64_t u64Dummy1;
532 } s;
533
534 s.u64 = 0;
535 s.u64Dummy0 = s.u64Dummy1 = 0x1122334455667788ULL;
536
537 CHECKOP(ASMAtomicXchgU64(&s.u64, 1), 0ULL, "%#llx", uint64_t);
538 CHECKVAL(s.u64, 1ULL, "%#llx");
539
540 CHECKOP(ASMAtomicXchgU64(&s.u64, 0), 1ULL, "%#llx", uint64_t);
541 CHECKVAL(s.u64, 0ULL, "%#llx");
542
543 CHECKOP(ASMAtomicXchgU64(&s.u64, ~0ULL), 0ULL, "%#llx", uint64_t);
544 CHECKVAL(s.u64, ~0ULL, "%#llx");
545
546 CHECKOP(ASMAtomicXchgU64(&s.u64, 0xfedcba0987654321ULL), ~0ULL, "%#llx", uint64_t);
547 CHECKVAL(s.u64, 0xfedcba0987654321ULL, "%#llx");
548
549 CHECKVAL(s.u64Dummy0, 0x1122334455667788ULL, "%#llx");
550 CHECKVAL(s.u64Dummy1, 0x1122334455667788ULL, "%#llx");
551}
552
553
554static void tstASMAtomicXchgPtr(void)
555{
556 void *pv = NULL;
557
558 CHECKOP(ASMAtomicXchgPtr(&pv, (void *)(~(uintptr_t)0)), NULL, "%p", void *);
559 CHECKVAL(pv, (void *)(~(uintptr_t)0), "%p");
560
561 CHECKOP(ASMAtomicXchgPtr(&pv, (void *)0x87654321), (void *)(~(uintptr_t)0), "%p", void *);
562 CHECKVAL(pv, (void *)0x87654321, "%p");
563
564 CHECKOP(ASMAtomicXchgPtr(&pv, NULL), (void *)0x87654321, "%p", void *);
565 CHECKVAL(pv, NULL, "%p");
566}
567
568
569static void tstASMAtomicCmpXchgU8(void)
570{
571 struct
572 {
573 uint8_t u8Before;
574 uint8_t u8;
575 uint8_t u8After;
576 } u = { 0xcc, 0xff, 0xaa };
577
578 CHECKOP(ASMAtomicCmpXchgU8(&u.u8, 0, 0), false, "%d", bool);
579 CHECKVAL(u.u8, 0xff, "%x"); CHECKVAL(u.u8Before, 0xcc, "%x"); CHECKVAL(u.u8After, 0xaa, "%x");
580
581 CHECKOP(ASMAtomicCmpXchgU8(&u.u8, 0, 0xff), true, "%d", bool);
582 CHECKVAL(u.u8, 0, "%x"); CHECKVAL(u.u8Before, 0xcc, "%x"); CHECKVAL(u.u8After, 0xaa, "%x");
583
584 CHECKOP(ASMAtomicCmpXchgU8(&u.u8, 0x79, 0xff), false, "%d", bool);
585 CHECKVAL(u.u8, 0, "%x"); CHECKVAL(u.u8Before, 0xcc, "%x"); CHECKVAL(u.u8After, 0xaa, "%x");
586
587 CHECKOP(ASMAtomicCmpXchgU8(&u.u8, 0x97, 0), true, "%d", bool);
588 CHECKVAL(u.u8, 0x97, "%x"); CHECKVAL(u.u8Before, 0xcc, "%x"); CHECKVAL(u.u8After, 0xaa, "%x");
589}
590
591
592static void tstASMAtomicCmpXchgU32(void)
593{
594 uint32_t u32 = 0xffffffff;
595
596 CHECKOP(ASMAtomicCmpXchgU32(&u32, 0, 0), false, "%d", bool);
597 CHECKVAL(u32, 0xffffffff, "%x");
598
599 CHECKOP(ASMAtomicCmpXchgU32(&u32, 0, 0xffffffff), true, "%d", bool);
600 CHECKVAL(u32, 0, "%x");
601
602 CHECKOP(ASMAtomicCmpXchgU32(&u32, 0x8008efd, 0xffffffff), false, "%d", bool);
603 CHECKVAL(u32, 0, "%x");
604
605 CHECKOP(ASMAtomicCmpXchgU32(&u32, 0x8008efd, 0), true, "%d", bool);
606 CHECKVAL(u32, 0x8008efd, "%x");
607}
608
609
610static void tstASMAtomicCmpXchgU64(void)
611{
612 uint64_t u64 = 0xffffffffffffffULL;
613
614 CHECKOP(ASMAtomicCmpXchgU64(&u64, 0, 0), false, "%d", bool);
615 CHECKVAL(u64, 0xffffffffffffffULL, "%#llx");
616
617 CHECKOP(ASMAtomicCmpXchgU64(&u64, 0, 0xffffffffffffffULL), true, "%d", bool);
618 CHECKVAL(u64, 0, "%x");
619
620 CHECKOP(ASMAtomicCmpXchgU64(&u64, 0x80040008008efdULL, 0xffffffff), false, "%d", bool);
621 CHECKVAL(u64, 0, "%x");
622
623 CHECKOP(ASMAtomicCmpXchgU64(&u64, 0x80040008008efdULL, 0xffffffff00000000ULL), false, "%d", bool);
624 CHECKVAL(u64, 0, "%x");
625
626 CHECKOP(ASMAtomicCmpXchgU64(&u64, 0x80040008008efdULL, 0), true, "%d", bool);
627 CHECKVAL(u64, 0x80040008008efdULL, "%#llx");
628}
629
630
631static void tstASMAtomicCmpXchgExU32(void)
632{
633 uint32_t u32 = 0xffffffff;
634 uint32_t u32Old = 0x80005111;
635
636 CHECKOP(ASMAtomicCmpXchgExU32(&u32, 0, 0, &u32Old), false, "%d", bool);
637 CHECKVAL(u32, 0xffffffff, "%x");
638 CHECKVAL(u32Old, 0xffffffff, "%x");
639
640 CHECKOP(ASMAtomicCmpXchgExU32(&u32, 0, 0xffffffff, &u32Old), true, "%d", bool);
641 CHECKVAL(u32, 0, "%x");
642 CHECKVAL(u32Old, 0xffffffff, "%x");
643
644 CHECKOP(ASMAtomicCmpXchgExU32(&u32, 0x8008efd, 0xffffffff, &u32Old), false, "%d", bool);
645 CHECKVAL(u32, 0, "%x");
646 CHECKVAL(u32Old, 0, "%x");
647
648 CHECKOP(ASMAtomicCmpXchgExU32(&u32, 0x8008efd, 0, &u32Old), true, "%d", bool);
649 CHECKVAL(u32, 0x8008efd, "%x");
650 CHECKVAL(u32Old, 0, "%x");
651
652 CHECKOP(ASMAtomicCmpXchgExU32(&u32, 0, 0x8008efd, &u32Old), true, "%d", bool);
653 CHECKVAL(u32, 0, "%x");
654 CHECKVAL(u32Old, 0x8008efd, "%x");
655}
656
657
658static void tstASMAtomicCmpXchgExU64(void)
659{
660 uint64_t u64 = 0xffffffffffffffffULL;
661 uint64_t u64Old = 0x8000000051111111ULL;
662
663 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0, 0, &u64Old), false, "%d", bool);
664 CHECKVAL(u64, 0xffffffffffffffffULL, "%llx");
665 CHECKVAL(u64Old, 0xffffffffffffffffULL, "%llx");
666
667 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0, 0xffffffffffffffffULL, &u64Old), true, "%d", bool);
668 CHECKVAL(u64, 0ULL, "%llx");
669 CHECKVAL(u64Old, 0xffffffffffffffffULL, "%llx");
670
671 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0x80040008008efdULL, 0xffffffff, &u64Old), false, "%d", bool);
672 CHECKVAL(u64, 0ULL, "%llx");
673 CHECKVAL(u64Old, 0ULL, "%llx");
674
675 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0x80040008008efdULL, 0xffffffff00000000ULL, &u64Old), false, "%d", bool);
676 CHECKVAL(u64, 0ULL, "%llx");
677 CHECKVAL(u64Old, 0ULL, "%llx");
678
679 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0x80040008008efdULL, 0, &u64Old), true, "%d", bool);
680 CHECKVAL(u64, 0x80040008008efdULL, "%llx");
681 CHECKVAL(u64Old, 0ULL, "%llx");
682
683 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0, 0x80040008008efdULL, &u64Old), true, "%d", bool);
684 CHECKVAL(u64, 0ULL, "%llx");
685 CHECKVAL(u64Old, 0x80040008008efdULL, "%llx");
686}
687
688
689static void tstASMAtomicReadU64(void)
690{
691 uint64_t u64 = 0;
692
693 CHECKOP(ASMAtomicReadU64(&u64), 0ULL, "%#llx", uint64_t);
694 CHECKVAL(u64, 0ULL, "%#llx");
695
696 u64 = ~0ULL;
697 CHECKOP(ASMAtomicReadU64(&u64), ~0ULL, "%#llx", uint64_t);
698 CHECKVAL(u64, ~0ULL, "%#llx");
699
700 u64 = 0xfedcba0987654321ULL;
701 CHECKOP(ASMAtomicReadU64(&u64), 0xfedcba0987654321ULL, "%#llx", uint64_t);
702 CHECKVAL(u64, 0xfedcba0987654321ULL, "%#llx");
703}
704
705
706static void tstASMAtomicUoReadU64(void)
707{
708 uint64_t u64 = 0;
709
710 CHECKOP(ASMAtomicUoReadU64(&u64), 0ULL, "%#llx", uint64_t);
711 CHECKVAL(u64, 0ULL, "%#llx");
712
713 u64 = ~0ULL;
714 CHECKOP(ASMAtomicUoReadU64(&u64), ~0ULL, "%#llx", uint64_t);
715 CHECKVAL(u64, ~0ULL, "%#llx");
716
717 u64 = 0xfedcba0987654321ULL;
718 CHECKOP(ASMAtomicUoReadU64(&u64), 0xfedcba0987654321ULL, "%#llx", uint64_t);
719 CHECKVAL(u64, 0xfedcba0987654321ULL, "%#llx");
720}
721
722
723static void tstASMAtomicAddS32(void)
724{
725 int32_t i32Rc;
726 int32_t i32 = 10;
727#define MYCHECK(op, rc, val) \
728 do { \
729 i32Rc = op; \
730 if (i32Rc != (rc)) \
731 { \
732 RTPrintf("%s, %d: FAILURE: %s -> %d expected %d\n", __FUNCTION__, __LINE__, #op, i32Rc, rc); \
733 RTTestIErrorInc(); \
734 } \
735 if (i32 != (val)) \
736 { \
737 RTPrintf("%s, %d: FAILURE: %s => i32=%d expected %d\n", __FUNCTION__, __LINE__, #op, i32, val); \
738 RTTestIErrorInc(); \
739 } \
740 } while (0)
741 MYCHECK(ASMAtomicAddS32(&i32, 1), 10, 11);
742 MYCHECK(ASMAtomicAddS32(&i32, -2), 11, 9);
743 MYCHECK(ASMAtomicAddS32(&i32, -9), 9, 0);
744 MYCHECK(ASMAtomicAddS32(&i32, -0x7fffffff), 0, -0x7fffffff);
745 MYCHECK(ASMAtomicAddS32(&i32, 0), -0x7fffffff, -0x7fffffff);
746 MYCHECK(ASMAtomicAddS32(&i32, 0x7fffffff), -0x7fffffff, 0);
747 MYCHECK(ASMAtomicAddS32(&i32, 0), 0, 0);
748#undef MYCHECK
749}
750
751
752static void tstASMAtomicDecIncS32(void)
753{
754 int32_t i32Rc;
755 int32_t i32 = 10;
756#define MYCHECK(op, rc) \
757 do { \
758 i32Rc = op; \
759 if (i32Rc != (rc)) \
760 { \
761 RTPrintf("%s, %d: FAILURE: %s -> %d expected %d\n", __FUNCTION__, __LINE__, #op, i32Rc, rc); \
762 RTTestIErrorInc(); \
763 } \
764 if (i32 != (rc)) \
765 { \
766 RTPrintf("%s, %d: FAILURE: %s => i32=%d expected %d\n", __FUNCTION__, __LINE__, #op, i32, rc); \
767 RTTestIErrorInc(); \
768 } \
769 } while (0)
770 MYCHECK(ASMAtomicDecS32(&i32), 9);
771 MYCHECK(ASMAtomicDecS32(&i32), 8);
772 MYCHECK(ASMAtomicDecS32(&i32), 7);
773 MYCHECK(ASMAtomicDecS32(&i32), 6);
774 MYCHECK(ASMAtomicDecS32(&i32), 5);
775 MYCHECK(ASMAtomicDecS32(&i32), 4);
776 MYCHECK(ASMAtomicDecS32(&i32), 3);
777 MYCHECK(ASMAtomicDecS32(&i32), 2);
778 MYCHECK(ASMAtomicDecS32(&i32), 1);
779 MYCHECK(ASMAtomicDecS32(&i32), 0);
780 MYCHECK(ASMAtomicDecS32(&i32), -1);
781 MYCHECK(ASMAtomicDecS32(&i32), -2);
782 MYCHECK(ASMAtomicIncS32(&i32), -1);
783 MYCHECK(ASMAtomicIncS32(&i32), 0);
784 MYCHECK(ASMAtomicIncS32(&i32), 1);
785 MYCHECK(ASMAtomicIncS32(&i32), 2);
786 MYCHECK(ASMAtomicIncS32(&i32), 3);
787 MYCHECK(ASMAtomicDecS32(&i32), 2);
788 MYCHECK(ASMAtomicIncS32(&i32), 3);
789 MYCHECK(ASMAtomicDecS32(&i32), 2);
790 MYCHECK(ASMAtomicIncS32(&i32), 3);
791#undef MYCHECK
792}
793
794
795static void tstASMAtomicAndOrU32(void)
796{
797 uint32_t u32 = 0xffffffff;
798
799 ASMAtomicOrU32(&u32, 0xffffffff);
800 CHECKVAL(u32, 0xffffffff, "%x");
801
802 ASMAtomicAndU32(&u32, 0xffffffff);
803 CHECKVAL(u32, 0xffffffff, "%x");
804
805 ASMAtomicAndU32(&u32, 0x8f8f8f8f);
806 CHECKVAL(u32, 0x8f8f8f8f, "%x");
807
808 ASMAtomicOrU32(&u32, 0x70707070);
809 CHECKVAL(u32, 0xffffffff, "%x");
810
811 ASMAtomicAndU32(&u32, 1);
812 CHECKVAL(u32, 1, "%x");
813
814 ASMAtomicOrU32(&u32, 0x80000000);
815 CHECKVAL(u32, 0x80000001, "%x");
816
817 ASMAtomicAndU32(&u32, 0x80000000);
818 CHECKVAL(u32, 0x80000000, "%x");
819
820 ASMAtomicAndU32(&u32, 0);
821 CHECKVAL(u32, 0, "%x");
822
823 ASMAtomicOrU32(&u32, 0x42424242);
824 CHECKVAL(u32, 0x42424242, "%x");
825}
826
827
828void tstASMMemZeroPage(void)
829{
830 struct
831 {
832 uint64_t u64Magic1;
833 uint8_t abPage[PAGE_SIZE];
834 uint64_t u64Magic2;
835 } Buf1, Buf2, Buf3;
836
837 Buf1.u64Magic1 = UINT64_C(0xffffffffffffffff);
838 memset(Buf1.abPage, 0x55, sizeof(Buf1.abPage));
839 Buf1.u64Magic2 = UINT64_C(0xffffffffffffffff);
840 Buf2.u64Magic1 = UINT64_C(0xffffffffffffffff);
841 memset(Buf2.abPage, 0x77, sizeof(Buf2.abPage));
842 Buf2.u64Magic2 = UINT64_C(0xffffffffffffffff);
843 Buf3.u64Magic1 = UINT64_C(0xffffffffffffffff);
844 memset(Buf3.abPage, 0x99, sizeof(Buf3.abPage));
845 Buf3.u64Magic2 = UINT64_C(0xffffffffffffffff);
846 ASMMemZeroPage(Buf1.abPage);
847 ASMMemZeroPage(Buf2.abPage);
848 ASMMemZeroPage(Buf3.abPage);
849 if ( Buf1.u64Magic1 != UINT64_C(0xffffffffffffffff)
850 || Buf1.u64Magic2 != UINT64_C(0xffffffffffffffff)
851 || Buf2.u64Magic1 != UINT64_C(0xffffffffffffffff)
852 || Buf2.u64Magic2 != UINT64_C(0xffffffffffffffff)
853 || Buf3.u64Magic1 != UINT64_C(0xffffffffffffffff)
854 || Buf3.u64Magic2 != UINT64_C(0xffffffffffffffff))
855 {
856 RTPrintf("tstInlineAsm: ASMMemZeroPage violated one/both magic(s)!\n");
857 RTTestIErrorInc();
858 }
859 for (unsigned i = 0; i < sizeof(Buf1.abPage); i++)
860 if (Buf1.abPage[i])
861 {
862 RTPrintf("tstInlineAsm: ASMMemZeroPage didn't clear byte at offset %#x!\n", i);
863 RTTestIErrorInc();
864 }
865 for (unsigned i = 0; i < sizeof(Buf2.abPage); i++)
866 if (Buf2.abPage[i])
867 {
868 RTPrintf("tstInlineAsm: ASMMemZeroPage didn't clear byte at offset %#x!\n", i);
869 RTTestIErrorInc();
870 }
871 for (unsigned i = 0; i < sizeof(Buf3.abPage); i++)
872 if (Buf3.abPage[i])
873 {
874 RTPrintf("tstInlineAsm: ASMMemZeroPage didn't clear byte at offset %#x!\n", i);
875 RTTestIErrorInc();
876 }
877}
878
879
880void tstASMMemIsZeroPage(RTTEST hTest)
881{
882 RTTestSub(hTest, "ASMMemIsZeroPage");
883
884 void *pvPage1 = RTTestGuardedAllocHead(hTest, PAGE_SIZE);
885 void *pvPage2 = RTTestGuardedAllocTail(hTest, PAGE_SIZE);
886 RTTESTI_CHECK_RETV(pvPage1 && pvPage2);
887
888 memset(pvPage1, 0, PAGE_SIZE);
889 memset(pvPage2, 0, PAGE_SIZE);
890 RTTESTI_CHECK(ASMMemIsZeroPage(pvPage1));
891 RTTESTI_CHECK(ASMMemIsZeroPage(pvPage2));
892
893 memset(pvPage1, 0xff, PAGE_SIZE);
894 memset(pvPage2, 0xff, PAGE_SIZE);
895 RTTESTI_CHECK(!ASMMemIsZeroPage(pvPage1));
896 RTTESTI_CHECK(!ASMMemIsZeroPage(pvPage2));
897
898 memset(pvPage1, 0, PAGE_SIZE);
899 memset(pvPage2, 0, PAGE_SIZE);
900 for (unsigned off = 0; off < PAGE_SIZE; off++)
901 {
902 ((uint8_t *)pvPage1)[off] = 1;
903 RTTESTI_CHECK(!ASMMemIsZeroPage(pvPage1));
904 ((uint8_t *)pvPage1)[off] = 0;
905
906 ((uint8_t *)pvPage2)[off] = 0x80;
907 RTTESTI_CHECK(!ASMMemIsZeroPage(pvPage2));
908 ((uint8_t *)pvPage2)[off] = 0;
909 }
910
911 RTTestSubDone(hTest);
912}
913
914
915void tstASMMemZero32(void)
916{
917 struct
918 {
919 uint64_t u64Magic1;
920 uint8_t abPage[PAGE_SIZE - 32];
921 uint64_t u64Magic2;
922 } Buf1, Buf2, Buf3;
923
924 Buf1.u64Magic1 = UINT64_C(0xffffffffffffffff);
925 memset(Buf1.abPage, 0x55, sizeof(Buf1.abPage));
926 Buf1.u64Magic2 = UINT64_C(0xffffffffffffffff);
927 Buf2.u64Magic1 = UINT64_C(0xffffffffffffffff);
928 memset(Buf2.abPage, 0x77, sizeof(Buf2.abPage));
929 Buf2.u64Magic2 = UINT64_C(0xffffffffffffffff);
930 Buf3.u64Magic1 = UINT64_C(0xffffffffffffffff);
931 memset(Buf3.abPage, 0x99, sizeof(Buf3.abPage));
932 Buf3.u64Magic2 = UINT64_C(0xffffffffffffffff);
933 ASMMemZero32(Buf1.abPage, sizeof(Buf1.abPage));
934 ASMMemZero32(Buf2.abPage, sizeof(Buf2.abPage));
935 ASMMemZero32(Buf3.abPage, sizeof(Buf3.abPage));
936 if ( Buf1.u64Magic1 != UINT64_C(0xffffffffffffffff)
937 || Buf1.u64Magic2 != UINT64_C(0xffffffffffffffff)
938 || Buf2.u64Magic1 != UINT64_C(0xffffffffffffffff)
939 || Buf2.u64Magic2 != UINT64_C(0xffffffffffffffff)
940 || Buf3.u64Magic1 != UINT64_C(0xffffffffffffffff)
941 || Buf3.u64Magic2 != UINT64_C(0xffffffffffffffff))
942 {
943 RTPrintf("tstInlineAsm: ASMMemZero32 violated one/both magic(s)!\n");
944 RTTestIErrorInc();
945 }
946 for (unsigned i = 0; i < RT_ELEMENTS(Buf1.abPage); i++)
947 if (Buf1.abPage[i])
948 {
949 RTPrintf("tstInlineAsm: ASMMemZero32 didn't clear byte at offset %#x!\n", i);
950 RTTestIErrorInc();
951 }
952 for (unsigned i = 0; i < RT_ELEMENTS(Buf2.abPage); i++)
953 if (Buf2.abPage[i])
954 {
955 RTPrintf("tstInlineAsm: ASMMemZero32 didn't clear byte at offset %#x!\n", i);
956 RTTestIErrorInc();
957 }
958 for (unsigned i = 0; i < RT_ELEMENTS(Buf3.abPage); i++)
959 if (Buf3.abPage[i])
960 {
961 RTPrintf("tstInlineAsm: ASMMemZero32 didn't clear byte at offset %#x!\n", i);
962 RTTestIErrorInc();
963 }
964}
965
966
967void tstASMMemFill32(void)
968{
969 struct
970 {
971 uint64_t u64Magic1;
972 uint32_t au32Page[PAGE_SIZE / 4];
973 uint64_t u64Magic2;
974 } Buf1;
975 struct
976 {
977 uint64_t u64Magic1;
978 uint32_t au32Page[(PAGE_SIZE / 4) - 3];
979 uint64_t u64Magic2;
980 } Buf2;
981 struct
982 {
983 uint64_t u64Magic1;
984 uint32_t au32Page[(PAGE_SIZE / 4) - 1];
985 uint64_t u64Magic2;
986 } Buf3;
987
988 Buf1.u64Magic1 = UINT64_C(0xffffffffffffffff);
989 memset(Buf1.au32Page, 0x55, sizeof(Buf1.au32Page));
990 Buf1.u64Magic2 = UINT64_C(0xffffffffffffffff);
991 Buf2.u64Magic1 = UINT64_C(0xffffffffffffffff);
992 memset(Buf2.au32Page, 0x77, sizeof(Buf2.au32Page));
993 Buf2.u64Magic2 = UINT64_C(0xffffffffffffffff);
994 Buf3.u64Magic1 = UINT64_C(0xffffffffffffffff);
995 memset(Buf3.au32Page, 0x99, sizeof(Buf3.au32Page));
996 Buf3.u64Magic2 = UINT64_C(0xffffffffffffffff);
997 ASMMemFill32(Buf1.au32Page, sizeof(Buf1.au32Page), 0xdeadbeef);
998 ASMMemFill32(Buf2.au32Page, sizeof(Buf2.au32Page), 0xcafeff01);
999 ASMMemFill32(Buf3.au32Page, sizeof(Buf3.au32Page), 0xf00dd00f);
1000 if ( Buf1.u64Magic1 != UINT64_C(0xffffffffffffffff)
1001 || Buf1.u64Magic2 != UINT64_C(0xffffffffffffffff)
1002 || Buf2.u64Magic1 != UINT64_C(0xffffffffffffffff)
1003 || Buf2.u64Magic2 != UINT64_C(0xffffffffffffffff)
1004 || Buf3.u64Magic1 != UINT64_C(0xffffffffffffffff)
1005 || Buf3.u64Magic2 != UINT64_C(0xffffffffffffffff))
1006 {
1007 RTPrintf("tstInlineAsm: ASMMemFill32 violated one/both magic(s)!\n");
1008 RTTestIErrorInc();
1009 }
1010 for (unsigned i = 0; i < RT_ELEMENTS(Buf1.au32Page); i++)
1011 if (Buf1.au32Page[i] != 0xdeadbeef)
1012 {
1013 RTPrintf("tstInlineAsm: ASMMemFill32 %#x: %#x exepcted %#x\n", i, Buf1.au32Page[i], 0xdeadbeef);
1014 RTTestIErrorInc();
1015 }
1016 for (unsigned i = 0; i < RT_ELEMENTS(Buf2.au32Page); i++)
1017 if (Buf2.au32Page[i] != 0xcafeff01)
1018 {
1019 RTPrintf("tstInlineAsm: ASMMemFill32 %#x: %#x exepcted %#x\n", i, Buf2.au32Page[i], 0xcafeff01);
1020 RTTestIErrorInc();
1021 }
1022 for (unsigned i = 0; i < RT_ELEMENTS(Buf3.au32Page); i++)
1023 if (Buf3.au32Page[i] != 0xf00dd00f)
1024 {
1025 RTPrintf("tstInlineAsm: ASMMemFill32 %#x: %#x exepcted %#x\n", i, Buf3.au32Page[i], 0xf00dd00f);
1026 RTTestIErrorInc();
1027 }
1028}
1029
1030
1031
1032void tstASMMath(void)
1033{
1034 uint64_t u64 = ASMMult2xU32RetU64(UINT32_C(0x80000000), UINT32_C(0x10000000));
1035 CHECKVAL(u64, UINT64_C(0x0800000000000000), "%#018RX64");
1036
1037 uint32_t u32 = ASMDivU64ByU32RetU32(UINT64_C(0x0800000000000000), UINT32_C(0x10000000));
1038 CHECKVAL(u32, UINT32_C(0x80000000), "%#010RX32");
1039
1040#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
1041 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x0000000000000001), UINT32_C(0x00000001), UINT32_C(0x00000001));
1042 CHECKVAL(u64, UINT64_C(0x0000000000000001), "%#018RX64");
1043 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x0000000100000000), UINT32_C(0x80000000), UINT32_C(0x00000002));
1044 CHECKVAL(u64, UINT64_C(0x4000000000000000), "%#018RX64");
1045 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xfedcba9876543210), UINT32_C(0xffffffff), UINT32_C(0xffffffff));
1046 CHECKVAL(u64, UINT64_C(0xfedcba9876543210), "%#018RX64");
1047 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xffffffffffffffff), UINT32_C(0xffffffff), UINT32_C(0xffffffff));
1048 CHECKVAL(u64, UINT64_C(0xffffffffffffffff), "%#018RX64");
1049 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xffffffffffffffff), UINT32_C(0xfffffff0), UINT32_C(0xffffffff));
1050 CHECKVAL(u64, UINT64_C(0xfffffff0fffffff0), "%#018RX64");
1051 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x3415934810359583), UINT32_C(0x58734981), UINT32_C(0xf8694045));
1052 CHECKVAL(u64, UINT64_C(0x128b9c3d43184763), "%#018RX64");
1053 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x3415934810359583), UINT32_C(0xf8694045), UINT32_C(0x58734981));
1054 CHECKVAL(u64, UINT64_C(0x924719355cd35a27), "%#018RX64");
1055
1056# if 0 /* bird: question is whether this should trap or not:
1057 *
1058 * frank: Of course it must trap:
1059 *
1060 * 0xfffffff8 * 0x77d7daf8 = 0x77d7daf441412840
1061 *
1062 * During the following division, the quotient must fit into a 32-bit register.
1063 * Therefore the smallest valid divisor is
1064 *
1065 * (0x77d7daf441412840 >> 32) + 1 = 0x77d7daf5
1066 *
1067 * which is definitely greater than 0x3b9aca00.
1068 *
1069 * bird: No, the C version does *not* crash. So, the question is whether there's any
1070 * code depending on it not crashing.
1071 *
1072 * Of course the assembly versions of the code crash right now for the reasons you've
1073 * given, but the 32-bit MSC version does not crash.
1074 *
1075 * frank: The C version does not crash but delivers incorrect results for this case.
1076 * The reason is
1077 *
1078 * u.s.Hi = (unsigned long)(u64Hi / u32C);
1079 *
1080 * Here the division is actually 64-bit by 64-bit but the 64-bit result is truncated
1081 * to 32 bit. If using this (optimized and fast) function we should just be sure that
1082 * the operands are in a valid range.
1083 */
1084 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xfffffff8c65d6731), UINT32_C(0x77d7daf8), UINT32_C(0x3b9aca00));
1085 CHECKVAL(u64, UINT64_C(0x02b8f9a2aa74e3dc), "%#018RX64");
1086# endif
1087#endif /* AMD64 || X86 */
1088
1089 u32 = ASMModU64ByU32RetU32(UINT64_C(0x0ffffff8c65d6731), UINT32_C(0x77d7daf8));
1090 CHECKVAL(u32, UINT32_C(0x3B642451), "%#010RX32");
1091
1092 int32_t i32;
1093 i32 = ASMModS64ByS32RetS32(INT64_C(-11), INT32_C(-2));
1094 CHECKVAL(i32, INT32_C(-1), "%010RI32");
1095 i32 = ASMModS64ByS32RetS32(INT64_C(-11), INT32_C(2));
1096 CHECKVAL(i32, INT32_C(-1), "%010RI32");
1097 i32 = ASMModS64ByS32RetS32(INT64_C(11), INT32_C(-2));
1098 CHECKVAL(i32, INT32_C(1), "%010RI32");
1099
1100 i32 = ASMModS64ByS32RetS32(INT64_C(92233720368547758), INT32_C(2147483647));
1101 CHECKVAL(i32, INT32_C(2104533974), "%010RI32");
1102 i32 = ASMModS64ByS32RetS32(INT64_C(-92233720368547758), INT32_C(2147483647));
1103 CHECKVAL(i32, INT32_C(-2104533974), "%010RI32");
1104}
1105
1106
1107void tstASMByteSwap(void)
1108{
1109 RTPrintf("tstInlineASM: TESTING - ASMByteSwap*\n");
1110
1111 uint64_t u64In = UINT64_C(0x0011223344556677);
1112 uint64_t u64Out = ASMByteSwapU64(u64In);
1113 CHECKVAL(u64In, UINT64_C(0x0011223344556677), "%#018RX64");
1114 CHECKVAL(u64Out, UINT64_C(0x7766554433221100), "%#018RX64");
1115 u64Out = ASMByteSwapU64(u64Out);
1116 CHECKVAL(u64Out, u64In, "%#018RX64");
1117 u64In = UINT64_C(0x0123456789abcdef);
1118 u64Out = ASMByteSwapU64(u64In);
1119 CHECKVAL(u64In, UINT64_C(0x0123456789abcdef), "%#018RX64");
1120 CHECKVAL(u64Out, UINT64_C(0xefcdab8967452301), "%#018RX64");
1121 u64Out = ASMByteSwapU64(u64Out);
1122 CHECKVAL(u64Out, u64In, "%#018RX64");
1123 u64In = 0;
1124 u64Out = ASMByteSwapU64(u64In);
1125 CHECKVAL(u64Out, u64In, "%#018RX64");
1126 u64In = ~(uint64_t)0;
1127 u64Out = ASMByteSwapU64(u64In);
1128 CHECKVAL(u64Out, u64In, "%#018RX64");
1129
1130 uint32_t u32In = UINT32_C(0x00112233);
1131 uint32_t u32Out = ASMByteSwapU32(u32In);
1132 CHECKVAL(u32In, UINT32_C(0x00112233), "%#010RX32");
1133 CHECKVAL(u32Out, UINT32_C(0x33221100), "%#010RX32");
1134 u32Out = ASMByteSwapU32(u32Out);
1135 CHECKVAL(u32Out, u32In, "%#010RX32");
1136 u32In = UINT32_C(0x12345678);
1137 u32Out = ASMByteSwapU32(u32In);
1138 CHECKVAL(u32In, UINT32_C(0x12345678), "%#010RX32");
1139 CHECKVAL(u32Out, UINT32_C(0x78563412), "%#010RX32");
1140 u32Out = ASMByteSwapU32(u32Out);
1141 CHECKVAL(u32Out, u32In, "%#010RX32");
1142 u32In = 0;
1143 u32Out = ASMByteSwapU32(u32In);
1144 CHECKVAL(u32Out, u32In, "%#010RX32");
1145 u32In = ~(uint32_t)0;
1146 u32Out = ASMByteSwapU32(u32In);
1147 CHECKVAL(u32Out, u32In, "%#010RX32");
1148
1149 uint16_t u16In = UINT16_C(0x0011);
1150 uint16_t u16Out = ASMByteSwapU16(u16In);
1151 CHECKVAL(u16In, UINT16_C(0x0011), "%#06RX16");
1152 CHECKVAL(u16Out, UINT16_C(0x1100), "%#06RX16");
1153 u16Out = ASMByteSwapU16(u16Out);
1154 CHECKVAL(u16Out, u16In, "%#06RX16");
1155 u16In = UINT16_C(0x1234);
1156 u16Out = ASMByteSwapU16(u16In);
1157 CHECKVAL(u16In, UINT16_C(0x1234), "%#06RX16");
1158 CHECKVAL(u16Out, UINT16_C(0x3412), "%#06RX16");
1159 u16Out = ASMByteSwapU16(u16Out);
1160 CHECKVAL(u16Out, u16In, "%#06RX16");
1161 u16In = 0;
1162 u16Out = ASMByteSwapU16(u16In);
1163 CHECKVAL(u16Out, u16In, "%#06RX16");
1164 u16In = ~(uint16_t)0;
1165 u16Out = ASMByteSwapU16(u16In);
1166 CHECKVAL(u16Out, u16In, "%#06RX16");
1167}
1168
1169
1170void tstASMBench(void)
1171{
1172 /*
1173 * Make this static. We don't want to have this located on the stack.
1174 */
1175 static uint8_t volatile s_u8;
1176 static int8_t volatile s_i8;
1177 static uint16_t volatile s_u16;
1178 static int16_t volatile s_i16;
1179 static uint32_t volatile s_u32;
1180 static int32_t volatile s_i32;
1181 static uint64_t volatile s_u64;
1182 static int64_t volatile s_i64;
1183 register unsigned i;
1184 const unsigned cRounds = 2000000;
1185 register uint64_t u64Elapsed;
1186
1187 RTPrintf("tstInlineASM: Benchmarking:\n");
1188
1189#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
1190# define BENCH(op, str) \
1191 do { \
1192 RTThreadYield(); \
1193 u64Elapsed = ASMReadTSC(); \
1194 for (i = cRounds; i > 0; i--) \
1195 op; \
1196 u64Elapsed = ASMReadTSC() - u64Elapsed; \
1197 RTPrintf(" %-30s %3llu cycles\n", str, u64Elapsed / cRounds); \
1198 } while (0)
1199#else
1200# define BENCH(op, str) \
1201 do { \
1202 RTThreadYield(); \
1203 u64Elapsed = RTTimeNanoTS(); \
1204 for (i = cRounds; i > 0; i--) \
1205 op; \
1206 u64Elapsed = RTTimeNanoTS() - u64Elapsed; \
1207 RTPrintf(" %-30s %3llu ns\n", str, u64Elapsed / cRounds); \
1208 } while (0)
1209#endif
1210
1211 BENCH(s_u32 = 0, "s_u32 = 0:");
1212 BENCH(ASMAtomicUoReadU8(&s_u8), "ASMAtomicUoReadU8:");
1213 BENCH(ASMAtomicUoReadS8(&s_i8), "ASMAtomicUoReadS8:");
1214 BENCH(ASMAtomicUoReadU16(&s_u16), "ASMAtomicUoReadU16:");
1215 BENCH(ASMAtomicUoReadS16(&s_i16), "ASMAtomicUoReadS16:");
1216 BENCH(ASMAtomicUoReadU32(&s_u32), "ASMAtomicUoReadU32:");
1217 BENCH(ASMAtomicUoReadS32(&s_i32), "ASMAtomicUoReadS32:");
1218 BENCH(ASMAtomicUoReadU64(&s_u64), "ASMAtomicUoReadU64:");
1219 BENCH(ASMAtomicUoReadS64(&s_i64), "ASMAtomicUoReadS64:");
1220 BENCH(ASMAtomicReadU8(&s_u8), "ASMAtomicReadU8:");
1221 BENCH(ASMAtomicReadS8(&s_i8), "ASMAtomicReadS8:");
1222 BENCH(ASMAtomicReadU16(&s_u16), "ASMAtomicReadU16:");
1223 BENCH(ASMAtomicReadS16(&s_i16), "ASMAtomicReadS16:");
1224 BENCH(ASMAtomicReadU32(&s_u32), "ASMAtomicReadU32:");
1225 BENCH(ASMAtomicReadS32(&s_i32), "ASMAtomicReadS32:");
1226 BENCH(ASMAtomicReadU64(&s_u64), "ASMAtomicReadU64:");
1227 BENCH(ASMAtomicReadS64(&s_i64), "ASMAtomicReadS64:");
1228 BENCH(ASMAtomicUoWriteU8(&s_u8, 0), "ASMAtomicUoWriteU8:");
1229 BENCH(ASMAtomicUoWriteS8(&s_i8, 0), "ASMAtomicUoWriteS8:");
1230 BENCH(ASMAtomicUoWriteU16(&s_u16, 0), "ASMAtomicUoWriteU16:");
1231 BENCH(ASMAtomicUoWriteS16(&s_i16, 0), "ASMAtomicUoWriteS16:");
1232 BENCH(ASMAtomicUoWriteU32(&s_u32, 0), "ASMAtomicUoWriteU32:");
1233 BENCH(ASMAtomicUoWriteS32(&s_i32, 0), "ASMAtomicUoWriteS32:");
1234 BENCH(ASMAtomicUoWriteU64(&s_u64, 0), "ASMAtomicUoWriteU64:");
1235 BENCH(ASMAtomicUoWriteS64(&s_i64, 0), "ASMAtomicUoWriteS64:");
1236 BENCH(ASMAtomicWriteU8(&s_u8, 0), "ASMAtomicWriteU8:");
1237 BENCH(ASMAtomicWriteS8(&s_i8, 0), "ASMAtomicWriteS8:");
1238 BENCH(ASMAtomicWriteU16(&s_u16, 0), "ASMAtomicWriteU16:");
1239 BENCH(ASMAtomicWriteS16(&s_i16, 0), "ASMAtomicWriteS16:");
1240 BENCH(ASMAtomicWriteU32(&s_u32, 0), "ASMAtomicWriteU32:");
1241 BENCH(ASMAtomicWriteS32(&s_i32, 0), "ASMAtomicWriteS32:");
1242 BENCH(ASMAtomicWriteU64(&s_u64, 0), "ASMAtomicWriteU64:");
1243 BENCH(ASMAtomicWriteS64(&s_i64, 0), "ASMAtomicWriteS64:");
1244 BENCH(ASMAtomicXchgU8(&s_u8, 0), "ASMAtomicXchgU8:");
1245 BENCH(ASMAtomicXchgS8(&s_i8, 0), "ASMAtomicXchgS8:");
1246 BENCH(ASMAtomicXchgU16(&s_u16, 0), "ASMAtomicXchgU16:");
1247 BENCH(ASMAtomicXchgS16(&s_i16, 0), "ASMAtomicXchgS16:");
1248 BENCH(ASMAtomicXchgU32(&s_u32, 0), "ASMAtomicXchgU32:");
1249 BENCH(ASMAtomicXchgS32(&s_i32, 0), "ASMAtomicXchgS32:");
1250 BENCH(ASMAtomicXchgU64(&s_u64, 0), "ASMAtomicXchgU64:");
1251 BENCH(ASMAtomicXchgS64(&s_i64, 0), "ASMAtomicXchgS64:");
1252 BENCH(ASMAtomicCmpXchgU32(&s_u32, 0, 0), "ASMAtomicCmpXchgU32:");
1253 BENCH(ASMAtomicCmpXchgS32(&s_i32, 0, 0), "ASMAtomicCmpXchgS32:");
1254 BENCH(ASMAtomicCmpXchgU64(&s_u64, 0, 0), "ASMAtomicCmpXchgU64:");
1255 BENCH(ASMAtomicCmpXchgS64(&s_i64, 0, 0), "ASMAtomicCmpXchgS64:");
1256 BENCH(ASMAtomicCmpXchgU32(&s_u32, 0, 1), "ASMAtomicCmpXchgU32/neg:");
1257 BENCH(ASMAtomicCmpXchgS32(&s_i32, 0, 1), "ASMAtomicCmpXchgS32/neg:");
1258 BENCH(ASMAtomicCmpXchgU64(&s_u64, 0, 1), "ASMAtomicCmpXchgU64/neg:");
1259 BENCH(ASMAtomicCmpXchgS64(&s_i64, 0, 1), "ASMAtomicCmpXchgS64/neg:");
1260 BENCH(ASMAtomicIncU32(&s_u32), "ASMAtomicIncU32:");
1261 BENCH(ASMAtomicIncS32(&s_i32), "ASMAtomicIncS32:");
1262 BENCH(ASMAtomicDecU32(&s_u32), "ASMAtomicDecU32:");
1263 BENCH(ASMAtomicDecS32(&s_i32), "ASMAtomicDecS32:");
1264 BENCH(ASMAtomicAddU32(&s_u32, 5), "ASMAtomicAddU32:");
1265 BENCH(ASMAtomicAddS32(&s_i32, 5), "ASMAtomicAddS32:");
1266
1267 RTPrintf("Done.\n");
1268
1269#undef BENCH
1270}
1271
1272
1273int main(int argc, char *argv[])
1274{
1275 RTTEST hTest;
1276 int rc = RTTestInitAndCreate("tstInlineAsm", &hTest);
1277 if (rc)
1278 return rc;
1279 RTTestBanner(hTest);
1280
1281 /*
1282 * Execute the tests.
1283 */
1284#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
1285 tstASMCpuId();
1286#endif
1287 tstASMAtomicXchgU8();
1288 tstASMAtomicXchgU16();
1289 tstASMAtomicXchgU32();
1290 tstASMAtomicXchgU64();
1291 tstASMAtomicXchgPtr();
1292 tstASMAtomicCmpXchgU8();
1293 tstASMAtomicCmpXchgU32();
1294 tstASMAtomicCmpXchgU64();
1295 tstASMAtomicCmpXchgExU32();
1296 tstASMAtomicCmpXchgExU64();
1297 tstASMAtomicReadU64();
1298 tstASMAtomicUoReadU64();
1299 tstASMAtomicAddS32();
1300 tstASMAtomicDecIncS32();
1301 tstASMAtomicAndOrU32();
1302 tstASMMemZeroPage();
1303 tstASMMemIsZeroPage(hTest);
1304 tstASMMemZero32();
1305 tstASMMemFill32();
1306 tstASMMath();
1307 tstASMByteSwap();
1308 tstASMBench();
1309
1310 /*
1311 * Show the result.
1312 */
1313 return RTTestSummaryAndDestroy(hTest);
1314}
1315
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