VirtualBox

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

Last change on this file since 6741 was 6644, checked in by vboxsync, 17 years ago

Add CmpXchg functions to IPRT which additionally pass back the old value, including some testcases.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 33.5 KB
Line 
1/* $Id: tstInlineAsm.cpp 6644 2008-01-31 09:40:28Z vboxsync $ */
2/** @file
3 * innotek Portable Runtime Testcase - inline assembly.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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/stream.h>
32#include <iprt/string.h>
33#include <iprt/runtime.h>
34#include <iprt/param.h>
35
36
37/*******************************************************************************
38* Global Variables *
39*******************************************************************************/
40/** Global error count. */
41static unsigned g_cErrors;
42
43
44/*******************************************************************************
45* Defined Constants And Macros *
46*******************************************************************************/
47#define CHECKVAL(val, expect, fmt) \
48 do \
49 { \
50 if ((val) != (expect)) \
51 { \
52 g_cErrors++; \
53 RTPrintf("%s, %d: " #val ": expected " fmt " got " fmt "\n", __FUNCTION__, __LINE__, (expect), (val)); \
54 } \
55 } while (0)
56
57#define CHECKOP(op, expect, fmt, type) \
58 do \
59 { \
60 type val = op; \
61 if (val != (type)(expect)) \
62 { \
63 g_cErrors++; \
64 RTPrintf("%s, %d: " #op ": expected " fmt " got " fmt "\n", __FUNCTION__, __LINE__, (type)(expect), val); \
65 } \
66 } while (0)
67
68
69#if !defined(PIC) || !defined(RT_ARCH_X86)
70const char *getCacheAss(unsigned u)
71{
72 if (u == 0)
73 return "res0 ";
74 if (u == 1)
75 return "direct";
76 if (u >= 256)
77 return "???";
78
79 char *pszRet;
80 RTStrAPrintf(&pszRet, "%d way", u); /* intentional leak! */
81 return pszRet;
82}
83
84
85const char *getL2CacheAss(unsigned u)
86{
87 switch (u)
88 {
89 case 0: return "off ";
90 case 1: return "direct";
91 case 2: return "2 way ";
92 case 3: return "res3 ";
93 case 4: return "4 way ";
94 case 5: return "res5 ";
95 case 6: return "8 way ";
96 case 7: return "res7 ";
97 case 8: return "16 way";
98 case 9: return "res9 ";
99 case 10: return "res10 ";
100 case 11: return "res11 ";
101 case 12: return "res12 ";
102 case 13: return "res13 ";
103 case 14: return "res14 ";
104 case 15: return "fully ";
105 default:
106 return "????";
107 }
108}
109
110
111/**
112 * Test and dump all possible info from the CPUID instruction.
113 *
114 * @remark Bits shared with the libc cpuid.c program. This all written by me, so no worries.
115 * @todo transform the dumping into a generic runtime function. We'll need it for logging!
116 */
117void tstASMCpuId(void)
118{
119 unsigned iBit;
120 struct
121 {
122 uint32_t uEBX, uEAX, uEDX, uECX;
123 } s;
124 if (!ASMHasCpuId())
125 {
126 RTPrintf("tstInlineAsm: warning! CPU doesn't support CPUID\n");
127 return;
128 }
129
130 /*
131 * Try the 0 function and use that for checking the ASMCpuId_* variants.
132 */
133 ASMCpuId(0, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
134
135 uint32_t u32 = ASMCpuId_ECX(0);
136 CHECKVAL(u32, s.uECX, "%x");
137
138 u32 = ASMCpuId_EDX(0);
139 CHECKVAL(u32, s.uEDX, "%x");
140
141 uint32_t uECX2 = s.uECX - 1;
142 uint32_t uEDX2 = s.uEDX - 1;
143 ASMCpuId_ECX_EDX(0, &uECX2, &uEDX2);
144
145 CHECKVAL(uECX2, s.uECX, "%x");
146 CHECKVAL(uEDX2, s.uEDX, "%x");
147
148 /*
149 * Done testing, dump the information.
150 */
151 RTPrintf("tstInlineAsm: CPUID Dump\n");
152 ASMCpuId(0, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
153 const uint32_t cFunctions = s.uEAX;
154
155 /* raw dump */
156 RTPrintf("\n"
157 " RAW Standard CPUIDs\n"
158 "Function eax ebx ecx edx\n");
159 for (unsigned iStd = 0; iStd <= cFunctions + 3; iStd++)
160 {
161 ASMCpuId(iStd, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
162 RTPrintf("%08x %08x %08x %08x %08x%s\n",
163 iStd, s.uEAX, s.uEBX, s.uECX, s.uEDX, iStd <= cFunctions ? "" : "*");
164 }
165
166 /*
167 * Understandable output
168 */
169 ASMCpuId(0, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
170 RTPrintf("Name: %.04s%.04s%.04s\n"
171 "Support: 0-%u\n",
172 &s.uEBX, &s.uEDX, &s.uECX, s.uEAX);
173
174 /*
175 * Get Features.
176 */
177 if (cFunctions >= 1)
178 {
179 ASMCpuId(1, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
180 RTPrintf("Family: %d \tExtended: %d \tEffectiv: %d\n"
181 "Model: %d \tExtended: %d \tEffectiv: %d\n"
182 "Stepping: %d\n"
183 "APIC ID: %#04x\n"
184 "Logical CPUs: %d\n"
185 "CLFLUSH Size: %d\n"
186 "Brand ID: %#04x\n",
187 (s.uEAX >> 8) & 0xf, (s.uEAX >> 20) & 0x7f, ((s.uEAX >> 8) & 0xf) + (((s.uEAX >> 8) & 0xf) == 0xf ? (s.uEAX >> 20) & 0x7f : 0),
188 (s.uEAX >> 4) & 0xf, (s.uEAX >> 16) & 0x0f, ((s.uEAX >> 4) & 0xf) | (((s.uEAX >> 4) & 0xf) == 0xf ? (s.uEAX >> 16) & 0x0f : 0),
189 (s.uEAX >> 0) & 0xf,
190 (s.uEBX >> 24) & 0xff,
191 (s.uEBX >> 16) & 0xff,
192 (s.uEBX >> 8) & 0xff,
193 (s.uEBX >> 0) & 0xff);
194
195 RTPrintf("Features EDX: ");
196 if (s.uEDX & RT_BIT(0)) RTPrintf(" FPU");
197 if (s.uEDX & RT_BIT(1)) RTPrintf(" VME");
198 if (s.uEDX & RT_BIT(2)) RTPrintf(" DE");
199 if (s.uEDX & RT_BIT(3)) RTPrintf(" PSE");
200 if (s.uEDX & RT_BIT(4)) RTPrintf(" TSC");
201 if (s.uEDX & RT_BIT(5)) RTPrintf(" MSR");
202 if (s.uEDX & RT_BIT(6)) RTPrintf(" PAE");
203 if (s.uEDX & RT_BIT(7)) RTPrintf(" MCE");
204 if (s.uEDX & RT_BIT(8)) RTPrintf(" CX8");
205 if (s.uEDX & RT_BIT(9)) RTPrintf(" APIC");
206 if (s.uEDX & RT_BIT(10)) RTPrintf(" 10");
207 if (s.uEDX & RT_BIT(11)) RTPrintf(" SEP");
208 if (s.uEDX & RT_BIT(12)) RTPrintf(" MTRR");
209 if (s.uEDX & RT_BIT(13)) RTPrintf(" PGE");
210 if (s.uEDX & RT_BIT(14)) RTPrintf(" MCA");
211 if (s.uEDX & RT_BIT(15)) RTPrintf(" CMOV");
212 if (s.uEDX & RT_BIT(16)) RTPrintf(" PAT");
213 if (s.uEDX & RT_BIT(17)) RTPrintf(" PSE36");
214 if (s.uEDX & RT_BIT(18)) RTPrintf(" PSN");
215 if (s.uEDX & RT_BIT(19)) RTPrintf(" CLFSH");
216 if (s.uEDX & RT_BIT(20)) RTPrintf(" 20");
217 if (s.uEDX & RT_BIT(21)) RTPrintf(" DS");
218 if (s.uEDX & RT_BIT(22)) RTPrintf(" ACPI");
219 if (s.uEDX & RT_BIT(23)) RTPrintf(" MMX");
220 if (s.uEDX & RT_BIT(24)) RTPrintf(" FXSR");
221 if (s.uEDX & RT_BIT(25)) RTPrintf(" SSE");
222 if (s.uEDX & RT_BIT(26)) RTPrintf(" SSE2");
223 if (s.uEDX & RT_BIT(27)) RTPrintf(" SS");
224 if (s.uEDX & RT_BIT(28)) RTPrintf(" HTT");
225 if (s.uEDX & RT_BIT(29)) RTPrintf(" 29");
226 if (s.uEDX & RT_BIT(30)) RTPrintf(" 30");
227 if (s.uEDX & RT_BIT(31)) RTPrintf(" 31");
228 RTPrintf("\n");
229
230 /** @todo check intel docs. */
231 RTPrintf("Features ECX: ");
232 if (s.uECX & RT_BIT(0)) RTPrintf(" SSE3");
233 for (iBit = 1; iBit < 13; iBit++)
234 if (s.uECX & RT_BIT(iBit))
235 RTPrintf(" %d", iBit);
236 if (s.uECX & RT_BIT(13)) RTPrintf(" CX16");
237 for (iBit = 14; iBit < 32; iBit++)
238 if (s.uECX & RT_BIT(iBit))
239 RTPrintf(" %d", iBit);
240 RTPrintf("\n");
241 }
242
243 /*
244 * Extended.
245 * Implemented after AMD specs.
246 */
247 /** @todo check out the intel specs. */
248 ASMCpuId(0x80000000, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
249 if (!s.uEAX && !s.uEBX && !s.uECX && !s.uEDX)
250 {
251 RTPrintf("No extended CPUID info? Check the manual on how to detect this...\n");
252 return;
253 }
254 const uint32_t cExtFunctions = s.uEAX | 0x80000000;
255
256 /* raw dump */
257 RTPrintf("\n"
258 " RAW Extended CPUIDs\n"
259 "Function eax ebx ecx edx\n");
260 for (unsigned iExt = 0x80000000; iExt <= cExtFunctions + 3; iExt++)
261 {
262 ASMCpuId(iExt, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
263 RTPrintf("%08x %08x %08x %08x %08x%s\n",
264 iExt, s.uEAX, s.uEBX, s.uECX, s.uEDX, iExt <= cExtFunctions ? "" : "*");
265 }
266
267 /*
268 * Understandable output
269 */
270 ASMCpuId(0x80000000, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
271 RTPrintf("Ext Name: %.4s%.4s%.4s\n"
272 "Ext Supports: 0x80000000-%#010x\n",
273 &s.uEBX, &s.uEDX, &s.uECX, s.uEAX);
274
275 if (cExtFunctions >= 0x80000001)
276 {
277 ASMCpuId(0x80000001, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
278 RTPrintf("Family: %d \tExtended: %d \tEffectiv: %d\n"
279 "Model: %d \tExtended: %d \tEffectiv: %d\n"
280 "Stepping: %d\n"
281 "Brand ID: %#05x\n",
282 (s.uEAX >> 8) & 0xf, (s.uEAX >> 20) & 0x7f, ((s.uEAX >> 8) & 0xf) + (((s.uEAX >> 8) & 0xf) == 0xf ? (s.uEAX >> 20) & 0x7f : 0),
283 (s.uEAX >> 4) & 0xf, (s.uEAX >> 16) & 0x0f, ((s.uEAX >> 4) & 0xf) | (((s.uEAX >> 4) & 0xf) == 0xf ? (s.uEAX >> 16) & 0x0f : 0),
284 (s.uEAX >> 0) & 0xf,
285 s.uEBX & 0xfff);
286
287 RTPrintf("Features EDX: ");
288 if (s.uEDX & RT_BIT(0)) RTPrintf(" FPU");
289 if (s.uEDX & RT_BIT(1)) RTPrintf(" VME");
290 if (s.uEDX & RT_BIT(2)) RTPrintf(" DE");
291 if (s.uEDX & RT_BIT(3)) RTPrintf(" PSE");
292 if (s.uEDX & RT_BIT(4)) RTPrintf(" TSC");
293 if (s.uEDX & RT_BIT(5)) RTPrintf(" MSR");
294 if (s.uEDX & RT_BIT(6)) RTPrintf(" PAE");
295 if (s.uEDX & RT_BIT(7)) RTPrintf(" MCE");
296 if (s.uEDX & RT_BIT(8)) RTPrintf(" CMPXCHG8B");
297 if (s.uEDX & RT_BIT(9)) RTPrintf(" APIC");
298 if (s.uEDX & RT_BIT(10)) RTPrintf(" 10");
299 if (s.uEDX & RT_BIT(11)) RTPrintf(" SysCallSysRet");
300 if (s.uEDX & RT_BIT(12)) RTPrintf(" MTRR");
301 if (s.uEDX & RT_BIT(13)) RTPrintf(" PGE");
302 if (s.uEDX & RT_BIT(14)) RTPrintf(" MCA");
303 if (s.uEDX & RT_BIT(15)) RTPrintf(" CMOV");
304 if (s.uEDX & RT_BIT(16)) RTPrintf(" PAT");
305 if (s.uEDX & RT_BIT(17)) RTPrintf(" PSE36");
306 if (s.uEDX & RT_BIT(18)) RTPrintf(" 18");
307 if (s.uEDX & RT_BIT(19)) RTPrintf(" 19");
308 if (s.uEDX & RT_BIT(20)) RTPrintf(" NX");
309 if (s.uEDX & RT_BIT(21)) RTPrintf(" 21");
310 if (s.uEDX & RT_BIT(22)) RTPrintf(" MmxExt");
311 if (s.uEDX & RT_BIT(23)) RTPrintf(" MMX");
312 if (s.uEDX & RT_BIT(24)) RTPrintf(" FXSR");
313 if (s.uEDX & RT_BIT(25)) RTPrintf(" FastFXSR");
314 if (s.uEDX & RT_BIT(26)) RTPrintf(" 26");
315 if (s.uEDX & RT_BIT(27)) RTPrintf(" RDTSCP");
316 if (s.uEDX & RT_BIT(28)) RTPrintf(" 28");
317 if (s.uEDX & RT_BIT(29)) RTPrintf(" LongMode");
318 if (s.uEDX & RT_BIT(30)) RTPrintf(" 3DNowExt");
319 if (s.uEDX & RT_BIT(31)) RTPrintf(" 3DNow");
320 RTPrintf("\n");
321
322 RTPrintf("Features ECX: ");
323 if (s.uECX & RT_BIT(0)) RTPrintf(" LahfSahf");
324 if (s.uECX & RT_BIT(1)) RTPrintf(" CmpLegacy");
325 if (s.uECX & RT_BIT(2)) RTPrintf(" SVM");
326 if (s.uECX & RT_BIT(3)) RTPrintf(" 3");
327 if (s.uECX & RT_BIT(4)) RTPrintf(" AltMovCr8");
328 for (iBit = 5; iBit < 32; iBit++)
329 if (s.uECX & RT_BIT(iBit))
330 RTPrintf(" %d", iBit);
331 RTPrintf("\n");
332 }
333
334 char szString[4*4*3+1] = {0};
335 if (cExtFunctions >= 0x80000002)
336 ASMCpuId(0x80000002, &szString[0 + 0], &szString[0 + 4], &szString[0 + 8], &szString[0 + 12]);
337 if (cExtFunctions >= 0x80000003)
338 ASMCpuId(0x80000003, &szString[16 + 0], &szString[16 + 4], &szString[16 + 8], &szString[16 + 12]);
339 if (cExtFunctions >= 0x80000004)
340 ASMCpuId(0x80000004, &szString[32 + 0], &szString[32 + 4], &szString[32 + 8], &szString[32 + 12]);
341 if (cExtFunctions >= 0x80000002)
342 RTPrintf("Full Name: %s\n", szString);
343
344 if (cExtFunctions >= 0x80000005)
345 {
346 ASMCpuId(0x80000005, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
347 RTPrintf("TLB 2/4M Instr/Uni: %s %3d entries\n"
348 "TLB 2/4M Data: %s %3d entries\n",
349 getCacheAss((s.uEAX >> 8) & 0xff), (s.uEAX >> 0) & 0xff,
350 getCacheAss((s.uEAX >> 24) & 0xff), (s.uEAX >> 16) & 0xff);
351 RTPrintf("TLB 4K Instr/Uni: %s %3d entries\n"
352 "TLB 4K Data: %s %3d entries\n",
353 getCacheAss((s.uEBX >> 8) & 0xff), (s.uEBX >> 0) & 0xff,
354 getCacheAss((s.uEBX >> 24) & 0xff), (s.uEBX >> 16) & 0xff);
355 RTPrintf("L1 Instr Cache Line Size: %d bytes\n"
356 "L1 Instr Cache Lines Per Tag: %d\n"
357 "L1 Instr Cache Associativity: %s\n"
358 "L1 Instr Cache Size: %d KB\n",
359 (s.uEDX >> 0) & 0xff,
360 (s.uEDX >> 8) & 0xff,
361 getCacheAss((s.uEDX >> 16) & 0xff),
362 (s.uEDX >> 24) & 0xff);
363 RTPrintf("L1 Data Cache Line Size: %d bytes\n"
364 "L1 Data Cache Lines Per Tag: %d\n"
365 "L1 Data Cache Associativity: %s\n"
366 "L1 Data Cache Size: %d KB\n",
367 (s.uECX >> 0) & 0xff,
368 (s.uECX >> 8) & 0xff,
369 getCacheAss((s.uECX >> 16) & 0xff),
370 (s.uECX >> 24) & 0xff);
371 }
372
373 if (cExtFunctions >= 0x80000006)
374 {
375 ASMCpuId(0x80000006, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
376 RTPrintf("L2 TLB 2/4M Instr/Uni: %s %4d entries\n"
377 "L2 TLB 2/4M Data: %s %4d entries\n",
378 getL2CacheAss((s.uEAX >> 12) & 0xf), (s.uEAX >> 0) & 0xfff,
379 getL2CacheAss((s.uEAX >> 28) & 0xf), (s.uEAX >> 16) & 0xfff);
380 RTPrintf("L2 TLB 4K Instr/Uni: %s %4d entries\n"
381 "L2 TLB 4K Data: %s %4d entries\n",
382 getL2CacheAss((s.uEBX >> 12) & 0xf), (s.uEBX >> 0) & 0xfff,
383 getL2CacheAss((s.uEBX >> 28) & 0xf), (s.uEBX >> 16) & 0xfff);
384 RTPrintf("L2 Cache Line Size: %d bytes\n"
385 "L2 Cache Lines Per Tag: %d\n"
386 "L2 Cache Associativity: %s\n"
387 "L2 Cache Size: %d KB\n",
388 (s.uEDX >> 0) & 0xff,
389 (s.uEDX >> 8) & 0xf,
390 getL2CacheAss((s.uEDX >> 12) & 0xf),
391 (s.uEDX >> 16) & 0xffff);
392 }
393
394 if (cExtFunctions >= 0x80000007)
395 {
396 ASMCpuId(0x80000007, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
397 RTPrintf("APM Features: ");
398 if (s.uEDX & RT_BIT(0)) RTPrintf(" TS");
399 if (s.uEDX & RT_BIT(1)) RTPrintf(" FID");
400 if (s.uEDX & RT_BIT(2)) RTPrintf(" VID");
401 if (s.uEDX & RT_BIT(3)) RTPrintf(" TTP");
402 if (s.uEDX & RT_BIT(4)) RTPrintf(" TM");
403 if (s.uEDX & RT_BIT(5)) RTPrintf(" STC");
404 if (s.uEDX & RT_BIT(6)) RTPrintf(" 6");
405 if (s.uEDX & RT_BIT(7)) RTPrintf(" 7");
406 if (s.uEDX & RT_BIT(8)) RTPrintf(" TscInvariant");
407 for (iBit = 9; iBit < 32; iBit++)
408 if (s.uEDX & RT_BIT(iBit))
409 RTPrintf(" %d", iBit);
410 RTPrintf("\n");
411 }
412
413 if (cExtFunctions >= 0x80000008)
414 {
415 ASMCpuId(0x80000008, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
416 RTPrintf("Physical Address Width: %d bits\n"
417 "Virtual Address Width: %d bits\n",
418 (s.uEAX >> 0) & 0xff,
419 (s.uEAX >> 8) & 0xff);
420 RTPrintf("Physical Core Count: %d\n",
421 ((s.uECX >> 0) & 0xff) + 1);
422 if ((s.uECX >> 12) & 0xf)
423 RTPrintf("ApicIdCoreIdSize: %d bits\n", (s.uECX >> 12) & 0xf);
424 }
425
426 if (cExtFunctions >= 0x8000000a)
427 {
428 ASMCpuId(0x8000000a, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
429 RTPrintf("SVM Revision: %d (%#x)\n"
430 "Number of Address Space IDs: %d (%#x)\n",
431 s.uEAX & 0xff, s.uEAX & 0xff,
432 s.uEBX, s.uEBX);
433 }
434}
435#endif /* !PIC || !X86 */
436
437
438static void tstASMAtomicXchgU8(void)
439{
440 struct
441 {
442 uint8_t u8Dummy0;
443 uint8_t u8;
444 uint8_t u8Dummy1;
445 } s;
446
447 s.u8 = 0;
448 s.u8Dummy0 = s.u8Dummy1 = 0x42;
449 CHECKOP(ASMAtomicXchgU8(&s.u8, 1), 0, "%#x", uint8_t);
450 CHECKVAL(s.u8, 1, "%#x");
451
452 CHECKOP(ASMAtomicXchgU8(&s.u8, 0), 1, "%#x", uint8_t);
453 CHECKVAL(s.u8, 0, "%#x");
454
455 CHECKOP(ASMAtomicXchgU8(&s.u8, 0xff), 0, "%#x", uint8_t);
456 CHECKVAL(s.u8, 0xff, "%#x");
457
458 CHECKOP(ASMAtomicXchgU8(&s.u8, 0x87), 0xffff, "%#x", uint8_t);
459 CHECKVAL(s.u8, 0x87, "%#x");
460 CHECKVAL(s.u8Dummy0, 0x42, "%#x");
461 CHECKVAL(s.u8Dummy1, 0x42, "%#x");
462}
463
464
465static void tstASMAtomicXchgU16(void)
466{
467 struct
468 {
469 uint16_t u16Dummy0;
470 uint16_t u16;
471 uint16_t u16Dummy1;
472 } s;
473
474 s.u16 = 0;
475 s.u16Dummy0 = s.u16Dummy1 = 0x1234;
476 CHECKOP(ASMAtomicXchgU16(&s.u16, 1), 0, "%#x", uint16_t);
477 CHECKVAL(s.u16, 1, "%#x");
478
479 CHECKOP(ASMAtomicXchgU16(&s.u16, 0), 1, "%#x", uint16_t);
480 CHECKVAL(s.u16, 0, "%#x");
481
482 CHECKOP(ASMAtomicXchgU16(&s.u16, 0xffff), 0, "%#x", uint16_t);
483 CHECKVAL(s.u16, 0xffff, "%#x");
484
485 CHECKOP(ASMAtomicXchgU16(&s.u16, 0x8765), 0xffff, "%#x", uint16_t);
486 CHECKVAL(s.u16, 0x8765, "%#x");
487 CHECKVAL(s.u16Dummy0, 0x1234, "%#x");
488 CHECKVAL(s.u16Dummy1, 0x1234, "%#x");
489}
490
491
492static void tstASMAtomicXchgU32(void)
493{
494 struct
495 {
496 uint32_t u32Dummy0;
497 uint32_t u32;
498 uint32_t u32Dummy1;
499 } s;
500
501 s.u32 = 0;
502 s.u32Dummy0 = s.u32Dummy1 = 0x11223344;
503
504 CHECKOP(ASMAtomicXchgU32(&s.u32, 1), 0, "%#x", uint32_t);
505 CHECKVAL(s.u32, 1, "%#x");
506
507 CHECKOP(ASMAtomicXchgU32(&s.u32, 0), 1, "%#x", uint32_t);
508 CHECKVAL(s.u32, 0, "%#x");
509
510 CHECKOP(ASMAtomicXchgU32(&s.u32, ~0U), 0, "%#x", uint32_t);
511 CHECKVAL(s.u32, ~0U, "%#x");
512
513 CHECKOP(ASMAtomicXchgU32(&s.u32, 0x87654321), ~0U, "%#x", uint32_t);
514 CHECKVAL(s.u32, 0x87654321, "%#x");
515
516 CHECKVAL(s.u32Dummy0, 0x11223344, "%#x");
517 CHECKVAL(s.u32Dummy1, 0x11223344, "%#x");
518}
519
520
521static void tstASMAtomicXchgU64(void)
522{
523 struct
524 {
525 uint64_t u64Dummy0;
526 uint64_t u64;
527 uint64_t u64Dummy1;
528 } s;
529
530 s.u64 = 0;
531 s.u64Dummy0 = s.u64Dummy1 = 0x1122334455667788ULL;
532
533 CHECKOP(ASMAtomicXchgU64(&s.u64, 1), 0ULL, "%#llx", uint64_t);
534 CHECKVAL(s.u64, 1ULL, "%#llx");
535
536 CHECKOP(ASMAtomicXchgU64(&s.u64, 0), 1ULL, "%#llx", uint64_t);
537 CHECKVAL(s.u64, 0ULL, "%#llx");
538
539 CHECKOP(ASMAtomicXchgU64(&s.u64, ~0ULL), 0ULL, "%#llx", uint64_t);
540 CHECKVAL(s.u64, ~0ULL, "%#llx");
541
542 CHECKOP(ASMAtomicXchgU64(&s.u64, 0xfedcba0987654321ULL), ~0ULL, "%#llx", uint64_t);
543 CHECKVAL(s.u64, 0xfedcba0987654321ULL, "%#llx");
544
545 CHECKVAL(s.u64Dummy0, 0x1122334455667788ULL, "%#x");
546 CHECKVAL(s.u64Dummy1, 0x1122334455667788ULL, "%#x");
547}
548
549
550#ifdef RT_ARCH_AMD64
551static void tstASMAtomicXchgU128(void)
552{
553 struct
554 {
555 RTUINT128U u128Dummy0;
556 RTUINT128U u128;
557 RTUINT128U u128Dummy1;
558 } s;
559 RTUINT128U u128Ret;
560 RTUINT128U u128Arg;
561
562
563 s.u128Dummy0.s.Lo = s.u128Dummy0.s.Hi = 0x1122334455667788;
564 s.u128.s.Lo = 0;
565 s.u128.s.Hi = 0;
566 s.u128Dummy1 = s.u128Dummy0;
567
568 u128Arg.s.Lo = 1;
569 u128Arg.s.Hi = 0;
570 u128Ret.u = ASMAtomicXchgU128(&s.u128.u, u128Arg.u);
571 CHECKVAL(u128Ret.s.Lo, 0ULL, "%#llx");
572 CHECKVAL(u128Ret.s.Hi, 0ULL, "%#llx");
573 CHECKVAL(s.u128.s.Lo, 1ULL, "%#llx");
574 CHECKVAL(s.u128.s.Hi, 0ULL, "%#llx");
575
576 u128Arg.s.Lo = 0;
577 u128Arg.s.Hi = 0;
578 u128Ret.u = ASMAtomicXchgU128(&s.u128.u, u128Arg.u);
579 CHECKVAL(u128Ret.s.Lo, 1ULL, "%#llx");
580 CHECKVAL(u128Ret.s.Hi, 0ULL, "%#llx");
581 CHECKVAL(s.u128.s.Lo, 0ULL, "%#llx");
582 CHECKVAL(s.u128.s.Hi, 0ULL, "%#llx");
583
584 u128Arg.s.Lo = ~0ULL;
585 u128Arg.s.Hi = ~0ULL;
586 u128Ret.u = ASMAtomicXchgU128(&s.u128.u, u128Arg.u);
587 CHECKVAL(u128Ret.s.Lo, 0ULL, "%#llx");
588 CHECKVAL(u128Ret.s.Hi, 0ULL, "%#llx");
589 CHECKVAL(s.u128.s.Lo, ~0ULL, "%#llx");
590 CHECKVAL(s.u128.s.Hi, ~0ULL, "%#llx");
591
592
593 u128Arg.s.Lo = 0xfedcba0987654321ULL;
594 u128Arg.s.Hi = 0x8897a6b5c4d3e2f1ULL;
595 u128Ret.u = ASMAtomicXchgU128(&s.u128.u, u128Arg.u);
596 CHECKVAL(u128Ret.s.Lo, ~0ULL, "%#llx");
597 CHECKVAL(u128Ret.s.Hi, ~0ULL, "%#llx");
598 CHECKVAL(s.u128.s.Lo, 0xfedcba0987654321ULL, "%#llx");
599 CHECKVAL(s.u128.s.Hi, 0x8897a6b5c4d3e2f1ULL, "%#llx");
600
601 CHECKVAL(s.u128Dummy0.s.Lo, 0x1122334455667788, "%#llx");
602 CHECKVAL(s.u128Dummy0.s.Hi, 0x1122334455667788, "%#llx");
603 CHECKVAL(s.u128Dummy1.s.Lo, 0x1122334455667788, "%#llx");
604 CHECKVAL(s.u128Dummy1.s.Hi, 0x1122334455667788, "%#llx");
605}
606#endif
607
608
609static void tstASMAtomicXchgPtr(void)
610{
611 void *pv = NULL;
612
613 CHECKOP(ASMAtomicXchgPtr(&pv, (void *)(~(uintptr_t)0)), NULL, "%p", void *);
614 CHECKVAL(pv, (void *)(~(uintptr_t)0), "%p");
615
616 CHECKOP(ASMAtomicXchgPtr(&pv, (void *)0x87654321), (void *)(~(uintptr_t)0), "%p", void *);
617 CHECKVAL(pv, (void *)0x87654321, "%p");
618
619 CHECKOP(ASMAtomicXchgPtr(&pv, NULL), (void *)0x87654321, "%p", void *);
620 CHECKVAL(pv, NULL, "%p");
621}
622
623
624static void tstASMAtomicCmpXchgU32(void)
625{
626 uint32_t u32 = 0xffffffff;
627
628 CHECKOP(ASMAtomicCmpXchgU32(&u32, 0, 0), false, "%d", bool);
629 CHECKVAL(u32, 0xffffffff, "%x");
630
631 CHECKOP(ASMAtomicCmpXchgU32(&u32, 0, 0xffffffff), true, "%d", bool);
632 CHECKVAL(u32, 0, "%x");
633
634 CHECKOP(ASMAtomicCmpXchgU32(&u32, 0x8008efd, 0xffffffff), false, "%d", bool);
635 CHECKVAL(u32, 0, "%x");
636
637 CHECKOP(ASMAtomicCmpXchgU32(&u32, 0x8008efd, 0), true, "%d", bool);
638 CHECKVAL(u32, 0x8008efd, "%x");
639}
640
641
642static void tstASMAtomicCmpXchgU64(void)
643{
644 uint64_t u64 = 0xffffffffffffffULL;
645
646 CHECKOP(ASMAtomicCmpXchgU64(&u64, 0, 0), false, "%d", bool);
647 CHECKVAL(u64, 0xffffffffffffffULL, "%x");
648
649 CHECKOP(ASMAtomicCmpXchgU64(&u64, 0, 0xffffffffffffffULL), true, "%d", bool);
650 CHECKVAL(u64, 0, "%x");
651
652 CHECKOP(ASMAtomicCmpXchgU64(&u64, 0x80040008008efdULL, 0xffffffff), false, "%d", bool);
653 CHECKVAL(u64, 0, "%x");
654
655 CHECKOP(ASMAtomicCmpXchgU64(&u64, 0x80040008008efdULL, 0xffffffff00000000ULL), false, "%d", bool);
656 CHECKVAL(u64, 0, "%x");
657
658 CHECKOP(ASMAtomicCmpXchgU64(&u64, 0x80040008008efdULL, 0), true, "%d", bool);
659 CHECKVAL(u64, 0x80040008008efdULL, "%x");
660}
661
662
663static void tstASMAtomicCmpXchgExU32(void)
664{
665 uint32_t u32 = 0xffffffff;
666 uint32_t u32Old = 0x80005111;
667
668 CHECKOP(ASMAtomicCmpXchgExU32(&u32, 0, 0, &u32Old), false, "%d", bool);
669 CHECKVAL(u32, 0xffffffff, "%x");
670 CHECKVAL(u32Old, 0xffffffff, "%x");
671
672 CHECKOP(ASMAtomicCmpXchgExU32(&u32, 0, 0xffffffff, &u32Old), true, "%d", bool);
673 CHECKVAL(u32, 0, "%x");
674 CHECKVAL(u32Old, 0xffffffff, "%x");
675
676 CHECKOP(ASMAtomicCmpXchgExU32(&u32, 0x8008efd, 0xffffffff, &u32Old), false, "%d", bool);
677 CHECKVAL(u32, 0, "%x");
678 CHECKVAL(u32Old, 0, "%x");
679
680 CHECKOP(ASMAtomicCmpXchgExU32(&u32, 0x8008efd, 0, &u32Old), true, "%d", bool);
681 CHECKVAL(u32, 0x8008efd, "%x");
682 CHECKVAL(u32Old, 0, "%x");
683
684 CHECKOP(ASMAtomicCmpXchgExU32(&u32, 0, 0x8008efd, &u32Old), true, "%d", bool);
685 CHECKVAL(u32, 0, "%x");
686 CHECKVAL(u32Old, 0x8008efd, "%x");
687}
688
689
690static void tstASMAtomicCmpXchgExU64(void)
691{
692 uint64_t u64 = 0xffffffffffffffffULL;
693 uint64_t u64Old = 0x8000000051111111ULL;
694
695 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0, 0, &u64Old), false, "%d", bool);
696 CHECKVAL(u64, 0xffffffffffffffffULL, "%llx");
697 CHECKVAL(u64Old, 0xffffffffffffffffULL, "%llx");
698
699 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0, 0xffffffffffffffffULL, &u64Old), true, "%d", bool);
700 CHECKVAL(u64, 0ULL, "%llx");
701 CHECKVAL(u64Old, 0xffffffffffffffffULL, "%llx");
702
703 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0x80040008008efdULL, 0xffffffff, &u64Old), false, "%d", bool);
704 CHECKVAL(u64, 0ULL, "%llx");
705 CHECKVAL(u64Old, 0ULL, "%llx");
706
707 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0x80040008008efdULL, 0xffffffff00000000ULL, &u64Old), false, "%d", bool);
708 CHECKVAL(u64, 0ULL, "%llx");
709 CHECKVAL(u64Old, 0ULL, "%llx");
710
711 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0x80040008008efdULL, 0, &u64Old), true, "%d", bool);
712 CHECKVAL(u64, 0x80040008008efdULL, "%llx");
713 CHECKVAL(u64Old, 0ULL, "%llx");
714
715 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0, 0x80040008008efdULL, &u64Old), true, "%d", bool);
716 CHECKVAL(u64, 0ULL, "%llx");
717 CHECKVAL(u64Old, 0x80040008008efdULL, "%llx");
718}
719
720
721static void tstASMAtomicReadU64(void)
722{
723 uint64_t u64 = 0;
724
725 CHECKOP(ASMAtomicReadU64(&u64), 0ULL, "%#llx", uint64_t);
726 CHECKVAL(u64, 0ULL, "%#llx");
727
728 u64 = ~0ULL;
729 CHECKOP(ASMAtomicReadU64(&u64), ~0ULL, "%#llx", uint64_t);
730 CHECKVAL(u64, ~0ULL, "%#llx");
731
732 u64 = 0xfedcba0987654321ULL;
733 CHECKOP(ASMAtomicReadU64(&u64), 0xfedcba0987654321ULL, "%#llx", uint64_t);
734 CHECKVAL(u64, 0xfedcba0987654321ULL, "%#llx");
735}
736
737
738static void tstASMAtomicDecIncS32(void)
739{
740 int32_t i32Rc;
741 int32_t i32 = 10;
742#define MYCHECK(op, rc) \
743 do { \
744 i32Rc = op; \
745 if (i32Rc != (rc)) \
746 { \
747 RTPrintf("%s, %d: FAILURE: %s -> %d expected %d\n", __FUNCTION__, __LINE__, #op, i32Rc, rc); \
748 g_cErrors++; \
749 } \
750 if (i32 != (rc)) \
751 { \
752 RTPrintf("%s, %d: FAILURE: %s => i32=%d expected %d\n", __FUNCTION__, __LINE__, #op, i32, rc); \
753 g_cErrors++; \
754 } \
755 } while (0)
756 MYCHECK(ASMAtomicDecS32(&i32), 9);
757 MYCHECK(ASMAtomicDecS32(&i32), 8);
758 MYCHECK(ASMAtomicDecS32(&i32), 7);
759 MYCHECK(ASMAtomicDecS32(&i32), 6);
760 MYCHECK(ASMAtomicDecS32(&i32), 5);
761 MYCHECK(ASMAtomicDecS32(&i32), 4);
762 MYCHECK(ASMAtomicDecS32(&i32), 3);
763 MYCHECK(ASMAtomicDecS32(&i32), 2);
764 MYCHECK(ASMAtomicDecS32(&i32), 1);
765 MYCHECK(ASMAtomicDecS32(&i32), 0);
766 MYCHECK(ASMAtomicDecS32(&i32), -1);
767 MYCHECK(ASMAtomicDecS32(&i32), -2);
768 MYCHECK(ASMAtomicIncS32(&i32), -1);
769 MYCHECK(ASMAtomicIncS32(&i32), 0);
770 MYCHECK(ASMAtomicIncS32(&i32), 1);
771 MYCHECK(ASMAtomicIncS32(&i32), 2);
772 MYCHECK(ASMAtomicIncS32(&i32), 3);
773 MYCHECK(ASMAtomicDecS32(&i32), 2);
774 MYCHECK(ASMAtomicIncS32(&i32), 3);
775 MYCHECK(ASMAtomicDecS32(&i32), 2);
776 MYCHECK(ASMAtomicIncS32(&i32), 3);
777#undef MYCHECK
778
779}
780
781
782static void tstASMAtomicAndOrU32(void)
783{
784 uint32_t u32 = 0xffffffff;
785
786 ASMAtomicOrU32(&u32, 0xffffffff);
787 CHECKVAL(u32, 0xffffffff, "%x");
788
789 ASMAtomicAndU32(&u32, 0xffffffff);
790 CHECKVAL(u32, 0xffffffff, "%x");
791
792 ASMAtomicAndU32(&u32, 0x8f8f8f8f);
793 CHECKVAL(u32, 0x8f8f8f8f, "%x");
794
795 ASMAtomicOrU32(&u32, 0x70707070);
796 CHECKVAL(u32, 0xffffffff, "%x");
797
798 ASMAtomicAndU32(&u32, 1);
799 CHECKVAL(u32, 1, "%x");
800
801 ASMAtomicOrU32(&u32, 0x80000000);
802 CHECKVAL(u32, 0x80000001, "%x");
803
804 ASMAtomicAndU32(&u32, 0x80000000);
805 CHECKVAL(u32, 0x80000000, "%x");
806
807 ASMAtomicAndU32(&u32, 0);
808 CHECKVAL(u32, 0, "%x");
809
810 ASMAtomicOrU32(&u32, 0x42424242);
811 CHECKVAL(u32, 0x42424242, "%x");
812}
813
814
815void tstASMMemZeroPage(void)
816{
817 struct
818 {
819 uint64_t u64Magic1;
820 uint8_t abPage[PAGE_SIZE];
821 uint64_t u64Magic2;
822 } Buf1, Buf2, Buf3;
823
824 Buf1.u64Magic1 = UINT64_C(0xffffffffffffffff);
825 memset(Buf1.abPage, 0x55, sizeof(Buf1.abPage));
826 Buf1.u64Magic2 = UINT64_C(0xffffffffffffffff);
827 Buf2.u64Magic1 = UINT64_C(0xffffffffffffffff);
828 memset(Buf2.abPage, 0x77, sizeof(Buf2.abPage));
829 Buf2.u64Magic2 = UINT64_C(0xffffffffffffffff);
830 Buf3.u64Magic1 = UINT64_C(0xffffffffffffffff);
831 memset(Buf3.abPage, 0x99, sizeof(Buf3.abPage));
832 Buf3.u64Magic2 = UINT64_C(0xffffffffffffffff);
833 ASMMemZeroPage(Buf1.abPage);
834 ASMMemZeroPage(Buf2.abPage);
835 ASMMemZeroPage(Buf3.abPage);
836 if ( Buf1.u64Magic1 != UINT64_C(0xffffffffffffffff)
837 || Buf1.u64Magic2 != UINT64_C(0xffffffffffffffff)
838 || Buf1.u64Magic1 != UINT64_C(0xffffffffffffffff)
839 || Buf1.u64Magic2 != UINT64_C(0xffffffffffffffff)
840 || Buf2.u64Magic1 != UINT64_C(0xffffffffffffffff)
841 || Buf2.u64Magic2 != UINT64_C(0xffffffffffffffff))
842 {
843 RTPrintf("tstInlineAsm: ASMMemZeroPage violated one/both magic(s)!\n");
844 g_cErrors++;
845 }
846 for (unsigned i = 0; i < sizeof(Buf1.abPage); i++)
847 if (Buf1.abPage[i])
848 {
849 RTPrintf("tstInlineAsm: ASMMemZeroPage didn't clear byte at offset %#x!\n", i);
850 g_cErrors++;
851 }
852 for (unsigned i = 0; i < sizeof(Buf1.abPage); i++)
853 if (Buf1.abPage[i])
854 {
855 RTPrintf("tstInlineAsm: ASMMemZeroPage didn't clear byte at offset %#x!\n", i);
856 g_cErrors++;
857 }
858 for (unsigned i = 0; i < sizeof(Buf2.abPage); i++)
859 if (Buf2.abPage[i])
860 {
861 RTPrintf("tstInlineAsm: ASMMemZeroPage didn't clear byte at offset %#x!\n", i);
862 g_cErrors++;
863 }
864}
865
866
867void tstASMMath(void)
868{
869 uint64_t u64 = ASMMult2xU32RetU64(UINT32_C(0x80000000), UINT32_C(0x10000000));
870 CHECKVAL(u64, UINT64_C(0x0800000000000000), "%#018RX64");
871
872 uint32_t u32 = ASMDivU64ByU32RetU32(UINT64_C(0x0800000000000000), UINT32_C(0x10000000));
873 CHECKVAL(u32, UINT32_C(0x80000000), "%#010RX32");
874
875 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x0000000000000001), UINT32_C(0x00000001), UINT32_C(0x00000001));
876 CHECKVAL(u64, UINT64_C(0x0000000000000001), "%#018RX64");
877 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x0000000100000000), UINT32_C(0x80000000), UINT32_C(0x00000002));
878 CHECKVAL(u64, UINT64_C(0x4000000000000000), "%#018RX64");
879 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xfedcba9876543210), UINT32_C(0xffffffff), UINT32_C(0xffffffff));
880 CHECKVAL(u64, UINT64_C(0xfedcba9876543210), "%#018RX64");
881 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xffffffffffffffff), UINT32_C(0xffffffff), UINT32_C(0xffffffff));
882 CHECKVAL(u64, UINT64_C(0xffffffffffffffff), "%#018RX64");
883 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xffffffffffffffff), UINT32_C(0xfffffff0), UINT32_C(0xffffffff));
884 CHECKVAL(u64, UINT64_C(0xfffffff0fffffff0), "%#018RX64");
885 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x3415934810359583), UINT32_C(0x58734981), UINT32_C(0xf8694045));
886 CHECKVAL(u64, UINT64_C(0x128b9c3d43184763), "%#018RX64");
887 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x3415934810359583), UINT32_C(0xf8694045), UINT32_C(0x58734981));
888 CHECKVAL(u64, UINT64_C(0x924719355cd35a27), "%#018RX64");
889
890#if 0 /* bird: question is whether this should trap or not:
891 *
892 * frank: Of course it must trap:
893 *
894 * 0xfffffff8 * 0x77d7daf8 = 0x77d7daf441412840
895 *
896 * During the following division, the quotient must fit into a 32-bit register.
897 * Therefore the smallest valid divisor is
898 *
899 * (0x77d7daf441412840 >> 32) + 1 = 0x77d7daf5
900 *
901 * which is definitely greater than 0x3b9aca00.
902 *
903 * bird: No, the C version does *not* crash. So, the question is whether there any
904 * code depending on it not crashing.
905 *
906 * Of course the assembly versions of the code crash right now for the reasons you've
907 * given, but the the 32-bit MSC version does not crash.
908 *
909 * frank: The C version does not crash but delivers incorrect results for this case.
910 * The reason is
911 *
912 * u.s.Hi = (unsigned long)(u64Hi / u32C);
913 *
914 * Here the division is actually 64-bit by 64-bit but the 64-bit result is truncated
915 * to 32 bit. If using this (optimized and fast) function we should just be sure that
916 * the operands are in a valid range.
917 */
918 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xfffffff8c65d6731), UINT32_C(0x77d7daf8), UINT32_C(0x3b9aca00));
919 CHECKVAL(u64, UINT64_C(0x02b8f9a2aa74e3dc), "%#018RX64");
920#endif
921}
922
923
924int main(int argc, char *argv[])
925{
926 RTR3Init();
927 RTPrintf("tstInlineAsm: TESTING\n");
928
929 /*
930 * Execute the tests.
931 */
932#if !defined(PIC) || !defined(RT_ARCH_X86)
933 tstASMCpuId();
934#endif
935 tstASMAtomicXchgU8();
936 tstASMAtomicXchgU16();
937 tstASMAtomicXchgU32();
938 tstASMAtomicXchgU64();
939#ifdef RT_ARCH_AMD64
940 tstASMAtomicXchgU128();
941#endif
942 tstASMAtomicXchgPtr();
943 tstASMAtomicCmpXchgU32();
944 tstASMAtomicCmpXchgU64();
945 tstASMAtomicCmpXchgExU32();
946 tstASMAtomicCmpXchgExU64();
947 tstASMAtomicReadU64();
948 tstASMAtomicDecIncS32();
949 tstASMAtomicAndOrU32();
950 tstASMMemZeroPage();
951 tstASMMath();
952
953 /*
954 * Show the result.
955 */
956 if (!g_cErrors)
957 RTPrintf("tstInlineAsm: SUCCESS\n", g_cErrors);
958 else
959 RTPrintf("tstInlineAsm: FAILURE - %d errors\n", g_cErrors);
960 return !!g_cErrors;
961}
962
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette