1

How I can read this instruction directly:

unsigned int eax, ebx, ecx, edx;
unsigned int leaf, subleaf;
unsigned int  intbuf[12];`
char *buffer;
int i,j,k,base,start,stop,length;
float freq_GHz;
float frequency;

subleaf=0;

base = 0;
for (leaf=0x80000002; leaf<0x80000005; leaf++) {
    
    __asm__ __volatile__ ("cpuid" : \
      "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (leaf), "c" (subleaf));


    intbuf[base] = eax;
    intbuf[base+1] = ebx;
    intbuf[base+2] = ecx;
    intbuf[base+3] = edx;
    base += 4;
}

I've been trying to read it like this but its not working:

for (leaf = 0x80000002; leaf < 0x80000005; leaf++) {
        
        int regs[4];
        __cpuid(regs, leaf);
        
        intbuf[base] = (*regs),eax;
            intbuf[base + 1] = (*regs),ebx;
            intbuf[base + 2] = (*regs),ecx;
            intbuf[base + 3] = (*regs),edx;
        base += 4;
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
daniel
  • 25
  • 3
  • 1
    What is e.g `(*regs),ebx` supposed to do? That's using the comma-expression, `*regs` (which is equal to `regs[0]`) is discarded and you only get the value of `ebx`. – Some programmer dude Mar 06 '23 at 09:04

1 Answers1

3

The regs array that you pass to the __cpuid call1 will, on return, have the values of the four registers, EAX, EBX, ECX and EDX, in order (i.e. in the array elements, regs[0] thru regs[3]). You access those elements using normal array operators, and there is no need for any temporary 'register' variables like your eax.

Thus, your 'pure' C++ code would look something like this:

int intbuf[12];
int base = 0;
for (leaf = 0x80000002; leaf < 0x80000005; leaf++)
{        
    int regs[4];
    __cpuid(regs, leaf);    
    intbuf[base] = regs[0];     // EAX
    intbuf[base + 1] = regs[1]; // EBX
    intbuf[base + 2] = regs[2]; // ECX
    intbuf[base + 3] = regs[3]; // EDX
    base += 4;
}

If you want to keep intbuf as an array of unsigned int, then you should add a cast to the assignments inside the loop, like:

//...
    intbuf[base + 1] = static_cast<unsigned int>(regs[1]); // EBX

1 This answer is based on the operation of the MSVC implementation of the __cpuid function; other compilers' versions may differ slightly but the general principle will likely remain the same.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • 1
    If the type of `intbuf` was compatible, you could just do `__cpuid(intbuf + base, leaf)`. But yeah, unfortunately MSVC's `__cpuid` uses an `int[4]` output array. https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex?view=msvc-170 . They're typically bitfields, it makes much more sense to use `unsigned` with them. Some leafs do have integer values like cache sizes, though. – Peter Cordes Mar 06 '23 at 09:52
  • 2
    `static_cast` is overkill. `__cpuid` is an intrinsic for an x86 / x86-64 instruction, so this code can only run on x86 CPUs. x86 CPUs use 2's complement, so will any sane C++ implementation for them, and conversion from same-width signed to unsigned preserves the bit-pattern. (Also, C++20 standardizes 2's complement and forbids padding bits) So yes this will optimize away whether you write an explicit cast or leave it implicit, or if you use `memcpy`. But the `static_cast` seems odd to me, like clutter that makes it less easy to immediately see the `regs[1]` part. – Peter Cordes Mar 06 '23 at 09:56
  • 2
    @Peter I agree that it is 'overkill' in any real, sane world. However, without that (or some other) cast, the MSVC compiler will issue warnings. – Adrian Mole Mar 06 '23 at 10:02