1 // Copyright 2011 Google Inc. All Rights Reserved. 2 // 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the COPYING file in the root of the source 5 // tree. An additional intellectual property rights grant can be found 6 // in the file PATENTS. All contributing project authors may 7 // be found in the AUTHORS file in the root of the source tree. 8 // ----------------------------------------------------------------------------- 9 // 10 // CPU detection 11 // 12 // Author: Christian Duvivier (cduvivier (at) google.com) 13 14 #include "./dsp.h" 15 16 #if defined(__ANDROID__) 17 #include "cpu-features.h" 18 #endif 19 20 //------------------------------------------------------------------------------ 21 // SSE2 detection. 22 // 23 24 // apple/darwin gcc-4.0.1 defines __PIC__, but not __pic__ with -fPIC. 25 #if (defined(__pic__) || defined(__PIC__)) && defined(__i386__) 26 static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) { 27 __asm__ volatile ( 28 "mov %%ebx, %%edi\n" 29 "cpuid\n" 30 "xchg %%edi, %%ebx\n" 31 : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) 32 : "a"(info_type), "c"(0)); 33 } 34 #elif defined(__x86_64__) && \ 35 (defined(__code_model_medium__) || defined(__code_model_large__)) && \ 36 defined(__PIC__) 37 static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) { 38 __asm__ volatile ( 39 "xchg{q}\t{%%rbx}, %q1\n" 40 "cpuid\n" 41 "xchg{q}\t{%%rbx}, %q1\n" 42 : "=a"(cpu_info[0]), "=&r"(cpu_info[1]), "=c"(cpu_info[2]), 43 "=d"(cpu_info[3]) 44 : "a"(info_type), "c"(0)); 45 } 46 #elif defined(__i386__) || defined(__x86_64__) 47 static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) { 48 __asm__ volatile ( 49 "cpuid\n" 50 : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) 51 : "a"(info_type), "c"(0)); 52 } 53 #elif (defined(_M_X64) || defined(_M_IX86)) && \ 54 defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 150030729 // >= VS2008 SP1 55 #include <intrin.h> 56 #define GetCPUInfo(info, type) __cpuidex(info, type, 0) // set ecx=0 57 #elif defined(WEBP_MSC_SSE2) 58 #define GetCPUInfo __cpuid 59 #endif 60 61 // NaCl has no support for xgetbv or the raw opcode. 62 #if !defined(__native_client__) && (defined(__i386__) || defined(__x86_64__)) 63 static WEBP_INLINE uint64_t xgetbv(void) { 64 const uint32_t ecx = 0; 65 uint32_t eax, edx; 66 // Use the raw opcode for xgetbv for compatibility with older toolchains. 67 __asm__ volatile ( 68 ".byte 0x0f, 0x01, 0xd0\n" 69 : "=a"(eax), "=d"(edx) : "c" (ecx)); 70 return ((uint64_t)edx << 32) | eax; 71 } 72 #elif (defined(_M_X64) || defined(_M_IX86)) && \ 73 defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 160040219 // >= VS2010 SP1 74 #include <immintrin.h> 75 #define xgetbv() _xgetbv(0) 76 #elif defined(_MSC_VER) && defined(_M_IX86) 77 static WEBP_INLINE uint64_t xgetbv(void) { 78 uint32_t eax_, edx_; 79 __asm { 80 xor ecx, ecx // ecx = 0 81 // Use the raw opcode for xgetbv for compatibility with older toolchains. 82 __asm _emit 0x0f __asm _emit 0x01 __asm _emit 0xd0 83 mov eax_, eax 84 mov edx_, edx 85 } 86 return ((uint64_t)edx_ << 32) | eax_; 87 } 88 #else 89 #define xgetbv() 0U // no AVX for older x64 or unrecognized toolchains. 90 #endif 91 92 #if defined(__i386__) || defined(__x86_64__) || defined(WEBP_MSC_SSE2) 93 static int x86CPUInfo(CPUFeature feature) { 94 int max_cpuid_value; 95 int cpu_info[4]; 96 97 // get the highest feature value cpuid supports 98 GetCPUInfo(cpu_info, 0); 99 max_cpuid_value = cpu_info[0]; 100 if (max_cpuid_value < 1) { 101 return 0; 102 } 103 104 GetCPUInfo(cpu_info, 1); 105 if (feature == kSSE2) { 106 return 0 != (cpu_info[3] & 0x04000000); 107 } 108 if (feature == kSSE3) { 109 return 0 != (cpu_info[2] & 0x00000001); 110 } 111 if (feature == kSSE4_1) { 112 return 0 != (cpu_info[2] & 0x00080000); 113 } 114 if (feature == kAVX) { 115 // bits 27 (OSXSAVE) & 28 (256-bit AVX) 116 if ((cpu_info[2] & 0x18000000) == 0x18000000) { 117 // XMM state and YMM state enabled by the OS. 118 return (xgetbv() & 0x6) == 0x6; 119 } 120 } 121 if (feature == kAVX2) { 122 if (x86CPUInfo(kAVX) && max_cpuid_value >= 7) { 123 GetCPUInfo(cpu_info, 7); 124 return ((cpu_info[1] & 0x00000020) == 0x00000020); 125 } 126 } 127 return 0; 128 } 129 VP8CPUInfo VP8GetCPUInfo = x86CPUInfo; 130 #elif defined(WEBP_ANDROID_NEON) // NB: needs to be before generic NEON test. 131 static int AndroidCPUInfo(CPUFeature feature) { 132 const AndroidCpuFamily cpu_family = android_getCpuFamily(); 133 const uint64_t cpu_features = android_getCpuFeatures(); 134 if (feature == kNEON) { 135 return (cpu_family == ANDROID_CPU_FAMILY_ARM && 136 0 != (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON)); 137 } 138 return 0; 139 } 140 VP8CPUInfo VP8GetCPUInfo = AndroidCPUInfo; 141 #elif defined(WEBP_USE_NEON) 142 // define a dummy function to enable turning off NEON at runtime by setting 143 // VP8DecGetCPUInfo = NULL 144 static int armCPUInfo(CPUFeature feature) { 145 (void)feature; 146 return 1; 147 } 148 VP8CPUInfo VP8GetCPUInfo = armCPUInfo; 149 #elif defined(WEBP_USE_MIPS32) || defined(WEBP_USE_MIPS_DSP_R2) 150 static int mipsCPUInfo(CPUFeature feature) { 151 if ((feature == kMIPS32) || (feature == kMIPSdspR2)) { 152 return 1; 153 } else { 154 return 0; 155 } 156 157 } 158 VP8CPUInfo VP8GetCPUInfo = mipsCPUInfo; 159 #else 160 VP8CPUInfo VP8GetCPUInfo = NULL; 161 #endif 162 163