Browse Source

+ AVXSupport function to detect if the CPU and OS support AVX

git-svn-id: trunk@22641 -
florian 13 years ago
parent
commit
c57f463ede
2 changed files with 59 additions and 8 deletions
  1. 31 8
      rtl/i386/cpu.pp
  2. 28 0
      rtl/x86_64/cpu.pp

+ 31 - 8
rtl/i386/cpu.pp

@@ -13,6 +13,7 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
  **********************************************************************}
+{$mode objfpc}
 unit cpu;
   interface
 
@@ -25,13 +26,16 @@ unit cpu;
     { returns the contents of the cr0 register }
     function cr0 : longint;
 
+    function AVXSupport: boolean;inline;
+
     var
       is_sse3_cpu : boolean = false;
 
   implementation
 
 {$ASMMODE INTEL}
-
+    var
+      _AVXSupport : boolean;
 
     function cpuid_support : boolean;assembler;
       {
@@ -76,10 +80,19 @@ unit cpu;
 
 
 {$ASMMODE ATT}
-    function sse3_support : boolean;
+    function XGETBV(i : dword) : int64;assembler;
+      asm
+        movl %eax,%ecx
+        // older FPCs don't know the xgetbv opcode
+        .byte 0x0f,0x01,0xd0
+      end;
+
+
+    procedure SetupSupport;
       var
          _ecx : longint;
       begin
+        is_sse3_cpu:=false;
          if cpuid_support then
            begin
               asm
@@ -89,13 +102,23 @@ unit cpu;
                  movl %ecx,_ecx
                  popl %ebx
               end;
-              sse3_support:=(_ecx and $1)<>0;
-           end
-         else
-           { a cpu with without cpuid instruction supports never sse3 }
-           sse3_support:=false;
+              is_sse3_cpu:=(_ecx and $1)<>0;
+              _AVXSupport:=
+                { XGETBV suspport? }
+                ((_ecx and $08000000)<>0) and
+                { xmm and ymm state enabled? }
+                ((XGETBV(0) and %110)=%110) and
+                { avx supported? }
+                ((_ecx and $10000000)<>0);
+           end;
+      end;
+
+
+    function AVXSupport: boolean;inline;
+      begin
+        result:=_AVXSupport;
       end;
 
 begin
-  is_sse3_cpu:=sse3_support;
+  SetupSupport;
 end.

+ 28 - 0
rtl/x86_64/cpu.pp

@@ -30,6 +30,7 @@ unit cpu;
 
     function InterlockedCompareExchange128Support : boolean;inline;
     function AESSupport : boolean;inline;
+    function AVXSupport : boolean;inline;
 
     var
       is_sse3_cpu : boolean = false;
@@ -40,6 +41,7 @@ unit cpu;
 
     var
       _AESSupport,
+      _AVXSupport,
       _InterlockedCompareExchange128Support : boolean;
 
     function InterlockedCompareExchange128Support : boolean;inline;
@@ -52,6 +54,10 @@ unit cpu;
         result:=_AESSupport;
       end;
 
+    function AVXSupport: boolean;
+      begin
+        result:=_AVXSupport;
+      end;
 
     function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec; assembler;
      {
@@ -119,6 +125,19 @@ unit cpu;
     {$endif win64}
 
 
+    function XGETBV(i : dword) : int64;assembler;
+      asm
+    {$ifndef win64}
+        movq %rdi,%rcx
+    {$endif win64}
+        // older FPCs don't know the xgetbv opcode
+        .byte 0x0f,0x01,0xd0
+        andl $0xffffffff,%eax
+        shll $32,%rdx
+        orq %rdx,%rax
+      end;
+
+
     procedure SetupSupport;
       var
         _ecx : longint;
@@ -132,6 +151,15 @@ unit cpu;
         end;
         _InterlockedCompareExchange128Support:=(_ecx and $2000)<>0;
         _AESSupport:=(_ecx and $2000000)<>0;
+
+        _AVXSupport:=
+          { XGETBV suspport? }
+          ((_ecx and $08000000)<>0) and
+          { xmm and ymm state enabled? }
+          ((XGETBV(0) and %110)=%110) and
+          { avx supported? }
+          ((_ecx and $10000000)<>0);
+
         is_sse3_cpu:=(_ecx and $1)<>0;
       end;