2

Following code returns True if CPU has AVX1 or AVX2. Does anybody know how to modify this code to detect exactly AVX2 instruction support?

function isAvxSupported: Boolean;
asm
{$IFDEF CPUX86}
    push ebx
{$ENDIF}
{$IFDEF CPUX64}
    mov r10, rbx
{$ENDIF}
    xor eax, eax
    cpuid
    cmp eax, 1
    jb @not_supported
    mov eax, 1
    cpuid
    and ecx, 018000000h
    cmp ecx, 018000000h
    jne @not_supported
    xor ecx, ecx
    db 0Fh, 01h, 0D0h //XGETBV
    and eax, 110b
    cmp eax, 110b
    jne @not_supported
    mov eax, 1
    jmp @done
@not_supported:
    xor eax, eax
@done:
{$IFDEF CPUX86}
    pop ebx
{$ENDIF}
{$IFDEF CPUX64}
    mov rbx, r10
{$ENDIF}
end;
Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
Atak_Snajpera
  • 619
  • 9
  • 24
  • Have you read the documentation for this CPUID / XGETBV usage? Do you understand this code? – David Heffernan Jan 04 '17 at 16:36
  • I will try to hack this code ( http://www.delphitricks.com/source-code/systeminfo/retrieve_cpu_information.html ) and add detection for AVX2. However I can't figure out what is this if (_edx and $04000000) = $04000000 ... What is this $04000000 value? I know that AVX2 has value 5 according to this https://en.wikipedia.org/wiki/CPUID – Atak_Snajpera Jan 04 '17 at 17:09
  • http://stackoverflow.com/questions/6121792/ – MBo Jan 04 '17 at 18:17

2 Answers2

4

Essentially, before using AVX2, you need to check

  1. if the AVX2 instruction set is supported by checking CPUID.(EAX=07H, ECX=0H):EBX.AVX2[bit 5]=1
  2. if use of YMM registers is enabled by the OS

Step 1 can be done e.g. using this function:


function IsAVX2supported: boolean;
asm
    // Save EBX
    {$IFDEF CPUx86}
      push ebx
    {$ELSE CPUx64}
      mov r10, rbx
    {$ENDIF}
    //Check CPUID.0
    xor eax, eax
    cpuid //modifies EAX,EBX,ECX,EDX
    cmp al, 7 // do we have a CPUID leaf 7 ?
    jge @Leaf7
      xor eax, eax
      jmp @Exit
    @Leaf7:
      //Check CPUID.7
      mov eax, 7h
      xor ecx, ecx
      cpuid
      bt ebx, 5 //AVX2: CPUID.(EAX=07H, ECX=0H):EBX.AVX2[bit 5]=1
      setc al
   @Exit:
   // Restore EBX
   {$IFDEF CPUx86}
     pop ebx
   {$ELSE CPUx64}
     mov rbx, r10
   {$ENDIF}
end;

Step 2 can be done e.g. using this function:


function OSEnabledXmmYmm: boolean;
// necessary to check before using AVX, FMA or AES instructions!
asm
  {$IFDEF CPUx86}
  push ebx
  {$ELSE CPUx64}
  mov r10, rbx
  {$ENDIF}
  mov eax,1
  cpuid
  bt ecx, 27  // CPUID.1:ECX.OSXSAVE[bit 27] = 1 (XGETBV enabled for application use; implies XGETBV is an available instruction also)
  jnc @not_supported
    xor ecx,ecx //Specify control register XCR0 = XFEATURE_ENABLED_MASK register
    db 0Fh, 01h, 0D0h // xgetbv //Reads XCR (extended control register) -> EDX:EAX
    {lgdt eax = db 0Fh, 01h = privileged instruction, so don't go here unless xgetbv is allowed}
      //CHECK XFEATURE_ENABLED_MASK[2:1] = ‘11b’
      and eax, 06h //06h= 00000000000000000000000000000110b
      cmp eax, 06h//; check OS has enabled both XMM (bit 1) and YMM (bit 2) state management support
    jne @not_supported
      mov eax,1
      jmp @out
  @not_supported:
    xor eax,eax
  @out:
 {$IFDEF CPUx86}
  pop ebx
  {$ELSE CPUx64}
  mov rbx, r10
  {$ENDIF}
end;

Of course, you can also use this to modify the function you posted to just have a single function to call.

PhiS
  • 4,540
  • 25
  • 35
-1

OK I think that detecting AVX2 is as simple as this

function isAVX2Supported():boolean;
var _ebx: Longword;
begin

  asm
    mov eax,7 // EAX=7 -> https://en.wikipedia.org/wiki/CPUID
    db $0F,$A2 // db $0F,$A2 = CPUID instruction
    mov _ebx,ebx
  end;
  if (_ebx and $20) = $20 then isAVX2Supported:=true //Bit 5 = 100000 = $20 (HEX) 
  else isAVX2Supported:=false;

end;
Atak_Snajpera
  • 619
  • 9
  • 24
  • 1) note that begin asm end end will not work on x64; 2) not every CPU will support leaf 7 on CPUID and 3) if you also want to /use/ AVX2, you'll also have to check if this is supported/enabled by the OS – PhiS Jan 04 '17 at 18:51
  • 1) I'm using old Delphi 7 so this is not a problem. 2) Does this mean crash? 3) Is it safe to assume that if detected OS is NT6.1 then AVX is always enabled ? – Atak_Snajpera Jan 04 '17 at 18:58
  • @Atak_Snajpera: 2) you might get different data than you are expecting. Per [Intel documentation](http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-2a-manual.html): "***If a value entered for CPUID.EAX is higher than the maximum input value for basic or extended function for that processor then the data for the highest basic information leaf is returned**... If a value entered for CPUID.EAX is less than or equal to the maximum input value and **the leaf is not supported on that processor then 0 is returned in all the registers**.*" – Remy Lebeau Jan 04 '17 at 19:10
  • 1) ok then; 2) probably not, but depending on CPU, the result *might* be undefined (or zero, on some CPUs) and hence there is a chance of 'detecting' AVX2 when it's not there; 3) I don't know. Remy's comments are from the Intel documentation, but you'd have to check with all vendors. – PhiS Jan 04 '17 at 19:11