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@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__) 26static 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__) 37static 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__) 47static 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__)) 63static 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) 77static 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) 93static 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} 129VP8CPUInfo VP8GetCPUInfo = x86CPUInfo; 130#elif defined(WEBP_ANDROID_NEON) // NB: needs to be before generic NEON test. 131static 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} 140VP8CPUInfo 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 144static int armCPUInfo(CPUFeature feature) { 145 (void)feature; 146 return 1; 147} 148VP8CPUInfo VP8GetCPUInfo = armCPUInfo; 149#elif defined(WEBP_USE_MIPS32) || defined(WEBP_USE_MIPS_DSP_R2) 150static int mipsCPUInfo(CPUFeature feature) { 151 if ((feature == kMIPS32) || (feature == kMIPSdspR2)) { 152 return 1; 153 } else { 154 return 0; 155 } 156 157} 158VP8CPUInfo VP8GetCPUInfo = mipsCPUInfo; 159#else 160VP8CPUInfo VP8GetCPUInfo = NULL; 161#endif 162 163