x86: AVX-512 support
[x264/x264-sandbox.git] / common / cpu.c
index 172957e..8638186 100644 (file)
@@ -47,8 +47,7 @@ const x264_cpu_name_t x264_cpu_names[] =
 {
 #if HAVE_MMX
 //  {"MMX",         X264_CPU_MMX},  // we don't support asm on mmx1 cpus anymore
-//  {"CMOV",        X264_CPU_CMOV}, // we require this unconditionally, so don't print it
-#define MMX2 X264_CPU_MMX|X264_CPU_MMX2|X264_CPU_CMOV
+#define MMX2 X264_CPU_MMX|X264_CPU_MMX2
     {"MMX2",        MMX2},
     {"MMXEXT",      MMX2},
     {"SSE",         MMX2|X264_CPU_SSE},
@@ -71,13 +70,13 @@ const x264_cpu_name_t x264_cpu_names[] =
     {"BMI2",        AVX|X264_CPU_LZCNT|X264_CPU_BMI1|X264_CPU_BMI2},
 #define AVX2 AVX|X264_CPU_FMA3|X264_CPU_LZCNT|X264_CPU_BMI1|X264_CPU_BMI2|X264_CPU_AVX2
     {"AVX2",        AVX2},
+    {"AVX512",      AVX2|X264_CPU_AVX512},
 #undef AVX2
 #undef AVX
 #undef SSE2
 #undef MMX2
     {"Cache32",         X264_CPU_CACHELINE_32},
     {"Cache64",         X264_CPU_CACHELINE_64},
-    {"SlowCTZ",         X264_CPU_SLOW_CTZ},
     {"SlowAtom",        X264_CPU_SLOW_ATOM},
     {"SlowPshufb",      X264_CPU_SLOW_PSHUFB},
     {"SlowPalignr",     X264_CPU_SLOW_PALIGNR},
@@ -120,7 +119,7 @@ static void sigill_handler( int sig )
 #if HAVE_MMX
 int x264_cpu_cpuid_test( void );
 void x264_cpu_cpuid( uint32_t op, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx );
-void x264_cpu_xgetbv( uint32_t op, uint32_t *eax, uint32_t *edx );
+uint64_t x264_cpu_xgetbv( int xcr );
 
 uint32_t x264_cpu_detect( void )
 {
@@ -128,15 +127,14 @@ uint32_t x264_cpu_detect( void )
     uint32_t eax, ebx, ecx, edx;
     uint32_t vendor[4] = {0};
     uint32_t max_extended_cap, max_basic_cap;
-    int cache;
+    uint64_t xcr0 = 0;
 
 #if !ARCH_X86_64
     if( !x264_cpu_cpuid_test() )
         return 0;
 #endif
 
-    x264_cpu_cpuid( 0, &eax, vendor+0, vendor+2, vendor+1 );
-    max_basic_cap = eax;
+    x264_cpu_cpuid( 0, &max_basic_cap, vendor+0, vendor+2, vendor+1 );
     if( max_basic_cap == 0 )
         return 0;
 
@@ -147,28 +145,24 @@ uint32_t x264_cpu_detect( void )
         return cpu;
     if( edx&0x02000000 )
         cpu |= X264_CPU_MMX2|X264_CPU_SSE;
-    if( edx&0x00008000 )
-        cpu |= X264_CPU_CMOV;
-    else
-        return cpu;
     if( edx&0x04000000 )
         cpu |= X264_CPU_SSE2;
     if( ecx&0x00000001 )
         cpu |= X264_CPU_SSE3;
     if( ecx&0x00000200 )
-        cpu |= X264_CPU_SSSE3;
+        cpu |= X264_CPU_SSSE3|X264_CPU_SSE2_IS_FAST;
     if( ecx&0x00080000 )
         cpu |= X264_CPU_SSE4;
     if( ecx&0x00100000 )
         cpu |= X264_CPU_SSE42;
-    /* Check OXSAVE and AVX bits */
-    if( (ecx&0x18000000) == 0x18000000 )
+
+    if( ecx&0x08000000 ) /* XGETBV supported and XSAVE enabled by OS */
     {
-        /* Check for OS support */
-        x264_cpu_xgetbv( 0, &eax, &edx );
-        if( (eax&0x6) == 0x6 )
+        xcr0 = x264_cpu_xgetbv( 0 );
+        if( (xcr0&0x6) == 0x6 ) /* XMM/YMM state */
         {
-            cpu |= X264_CPU_AVX;
+            if( ecx&0x10000000 )
+                cpu |= X264_CPU_AVX;
             if( ecx&0x00001000 )
                 cpu |= X264_CPU_FMA3;
         }
@@ -177,20 +171,25 @@ uint32_t x264_cpu_detect( void )
     if( max_basic_cap >= 7 )
     {
         x264_cpu_cpuid( 7, &eax, &ebx, &ecx, &edx );
-        /* AVX2 requires OS support, but BMI1/2 don't. */
-        if( (cpu&X264_CPU_AVX) && (ebx&0x00000020) )
-            cpu |= X264_CPU_AVX2;
+
         if( ebx&0x00000008 )
-        {
             cpu |= X264_CPU_BMI1;
-            if( ebx&0x00000100 )
-                cpu |= X264_CPU_BMI2;
+        if( ebx&0x00000100 )
+            cpu |= X264_CPU_BMI2;
+
+        if( (xcr0&0x6) == 0x6 ) /* XMM/YMM state */
+        {
+            if( ebx&0x00000020 )
+                cpu |= X264_CPU_AVX2;
+
+            if( (xcr0&0xE0) == 0xE0 ) /* OPMASK/ZMM state */
+            {
+                if( (ebx&0xD0030000) == 0xD0030000 )
+                    cpu |= X264_CPU_AVX512;
+            }
         }
     }
 
-    if( cpu & X264_CPU_SSSE3 )
-        cpu |= X264_CPU_SSE2_IS_FAST;
-
     x264_cpu_cpuid( 0x80000000, &eax, &ebx, &ecx, &edx );
     max_extended_cap = eax;
 
@@ -230,8 +229,6 @@ uint32_t x264_cpu_detect( void )
         {
             if( edx&0x00400000 )
                 cpu |= X264_CPU_MMX2;
-            if( !(cpu&X264_CPU_LZCNT) )
-                cpu |= X264_CPU_SLOW_CTZ;
             if( (cpu&X264_CPU_SSE2) && !(cpu&X264_CPU_SSE2_IS_FAST) )
                 cpu |= X264_CPU_SSE2_IS_SLOW; /* AMD CPUs come in two types: terrible at SSE and great at it */
         }
@@ -256,7 +253,6 @@ uint32_t x264_cpu_detect( void )
             else if( model == 28 )
             {
                 cpu |= X264_CPU_SLOW_ATOM;
-                cpu |= X264_CPU_SLOW_CTZ;
                 cpu |= X264_CPU_SLOW_PSHUFB;
             }
             /* Conroe has a slow shuffle unit. Check the model number to make sure not
@@ -270,7 +266,7 @@ uint32_t x264_cpu_detect( void )
     {
         /* cacheline size is specified in 3 places, any of which may be missing */
         x264_cpu_cpuid( 1, &eax, &ebx, &ecx, &edx );
-        cache = (ebx&0xff00)>>5; // cflush size
+        int cache = (ebx&0xff00)>>5; // cflush size
         if( !cache && max_extended_cap >= 0x80000006 )
         {
             x264_cpu_cpuid( 0x80000006, &eax, &ebx, &ecx, &edx );