1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/libyuv/source/cpu_id.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,279 @@ 1.4 +/* 1.5 + * Copyright 2011 The LibYuv Project Authors. All rights reserved. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license 1.8 + * that can be found in the LICENSE file in the root of the source 1.9 + * tree. An additional intellectual property rights grant can be found 1.10 + * in the file PATENTS. All contributing project authors may 1.11 + * be found in the AUTHORS file in the root of the source tree. 1.12 + */ 1.13 + 1.14 +#include "libyuv/cpu_id.h" 1.15 + 1.16 +#ifdef _MSC_VER 1.17 +#include <intrin.h> // For __cpuidex() 1.18 +#endif 1.19 +#if !defined(__pnacl__) && !defined(__CLR_VER) && \ 1.20 + !defined(__native_client__) && defined(_M_X64) && \ 1.21 + defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219) 1.22 +#include <immintrin.h> // For _xgetbv() 1.23 +#endif 1.24 + 1.25 +#if !defined(__native_client__) 1.26 +#include <stdlib.h> // For getenv() 1.27 +#endif 1.28 + 1.29 +// For ArmCpuCaps() but unittested on all platforms 1.30 +#include <stdio.h> 1.31 +#include <string.h> 1.32 + 1.33 +#include "libyuv/basic_types.h" // For CPU_X86 1.34 + 1.35 +#ifdef __cplusplus 1.36 +namespace libyuv { 1.37 +extern "C" { 1.38 +#endif 1.39 + 1.40 +// For functions that use the stack and have runtime checks for overflow, 1.41 +// use SAFEBUFFERS to avoid additional check. 1.42 +#if defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219) 1.43 +#define SAFEBUFFERS __declspec(safebuffers) 1.44 +#else 1.45 +#define SAFEBUFFERS 1.46 +#endif 1.47 + 1.48 +// Low level cpuid for X86. Returns zeros on other CPUs. 1.49 +#if !defined(__pnacl__) && !defined(__CLR_VER) && \ 1.50 + (defined(_M_IX86) || defined(_M_X64) || \ 1.51 + defined(__i386__) || defined(__x86_64__)) 1.52 +LIBYUV_API 1.53 +void CpuId(uint32 info_eax, uint32 info_ecx, uint32* cpu_info) { 1.54 +#if defined(_MSC_VER) 1.55 +#if (_MSC_FULL_VER >= 160040219) 1.56 + __cpuidex((int*)(cpu_info), info_eax, info_ecx); 1.57 +#elif defined(_M_IX86) 1.58 + __asm { 1.59 + mov eax, info_eax 1.60 + mov ecx, info_ecx 1.61 + mov edi, cpu_info 1.62 + cpuid 1.63 + mov [edi], eax 1.64 + mov [edi + 4], ebx 1.65 + mov [edi + 8], ecx 1.66 + mov [edi + 12], edx 1.67 + } 1.68 +#else 1.69 + if (info_ecx == 0) { 1.70 + __cpuid((int*)(cpu_info), info_eax); 1.71 + } else { 1.72 + cpu_info[3] = cpu_info[2] = cpu_info[1] = cpu_info[0] = 0; 1.73 + } 1.74 +#endif 1.75 +#else // defined(_MSC_VER) 1.76 + uint32 info_ebx, info_edx; 1.77 + asm volatile ( // NOLINT 1.78 +#if defined( __i386__) && defined(__PIC__) 1.79 + // Preserve ebx for fpic 32 bit. 1.80 + "mov %%ebx, %%edi \n" 1.81 + "cpuid \n" 1.82 + "xchg %%edi, %%ebx \n" 1.83 + : "=D" (info_ebx), 1.84 +#else 1.85 + "cpuid \n" 1.86 + : "=b" (info_ebx), 1.87 +#endif // defined( __i386__) && defined(__PIC__) 1.88 + "+a" (info_eax), "+c" (info_ecx), "=d" (info_edx)); 1.89 + cpu_info[0] = info_eax; 1.90 + cpu_info[1] = info_ebx; 1.91 + cpu_info[2] = info_ecx; 1.92 + cpu_info[3] = info_edx; 1.93 +#endif // defined(_MSC_VER) 1.94 +} 1.95 + 1.96 +#if !defined(__native_client__) 1.97 +#define HAS_XGETBV 1.98 +// X86 CPUs have xgetbv to detect OS saves high parts of ymm registers. 1.99 +int TestOsSaveYmm() { 1.100 + uint32 xcr0 = 0u; 1.101 +#if defined(_MSC_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) 1.102 + xcr0 = (uint32)(_xgetbv(_XCR_XFEATURE_ENABLED_MASK)); 1.103 +#elif defined(_MSC_VER) && defined(_M_IX86) 1.104 + __asm { 1.105 + xor ecx, ecx // xcr 0 1.106 + _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0 // For VS2010 and earlier. 1.107 + mov xcr0, eax 1.108 + } 1.109 +#elif defined(__i386__) || defined(__x86_64__) 1.110 + asm(".byte 0x0f, 0x01, 0xd0" : "=a" (xcr0) : "c" (0) : "%edx"); 1.111 +#endif // defined(_MSC_VER) 1.112 + return((xcr0 & 6) == 6); // Is ymm saved? 1.113 +} 1.114 +#endif // !defined(__native_client__) 1.115 +#else 1.116 +LIBYUV_API 1.117 +void CpuId(uint32 eax, uint32 ecx, uint32* cpu_info) { 1.118 + cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; 1.119 +} 1.120 +#endif 1.121 + 1.122 +// based on libvpx arm_cpudetect.c 1.123 +// For Arm, but public to allow testing on any CPU 1.124 +LIBYUV_API SAFEBUFFERS 1.125 +int ArmCpuCaps(const char* cpuinfo_name) { 1.126 + FILE* f = fopen(cpuinfo_name, "r"); 1.127 + if (f) { 1.128 + char cpuinfo_line[512]; 1.129 + while (fgets(cpuinfo_line, sizeof(cpuinfo_line) - 1, f)) { 1.130 + if (memcmp(cpuinfo_line, "Features", 8) == 0) { 1.131 + char* p = strstr(cpuinfo_line, " neon"); 1.132 + if (p && (p[5] == ' ' || p[5] == '\n')) { 1.133 + fclose(f); 1.134 + return kCpuHasNEON; 1.135 + } 1.136 + } 1.137 + } 1.138 + fclose(f); 1.139 + } 1.140 + return 0; 1.141 +} 1.142 + 1.143 +#if defined(__mips__) && defined(__linux__) 1.144 +static int MipsCpuCaps(const char* search_string) { 1.145 + const char* file_name = "/proc/cpuinfo"; 1.146 + char cpuinfo_line[256]; 1.147 + FILE* f = NULL; 1.148 + if ((f = fopen(file_name, "r")) != NULL) { 1.149 + while (fgets(cpuinfo_line, sizeof(cpuinfo_line) - 1, f) != NULL) { 1.150 + if (strstr(cpuinfo_line, search_string) != NULL) { 1.151 + fclose(f); 1.152 + return kCpuHasMIPS_DSP; 1.153 + } 1.154 + } 1.155 + fclose(f); 1.156 + } 1.157 + /* Did not find string in the proc file, or not Linux ELF. */ 1.158 + return 0; 1.159 +} 1.160 +#endif 1.161 + 1.162 +// CPU detect function for SIMD instruction sets. 1.163 +LIBYUV_API 1.164 +int cpu_info_ = kCpuInit; // cpu_info is not initialized yet. 1.165 + 1.166 +// Test environment variable for disabling CPU features. Any non-zero value 1.167 +// to disable. Zero ignored to make it easy to set the variable on/off. 1.168 +#if !defined(__native_client__) && !defined(_M_ARM) 1.169 + 1.170 +static LIBYUV_BOOL TestEnv(const char* name) { 1.171 + const char* var = getenv(name); 1.172 + if (var) { 1.173 + if (var[0] != '0') { 1.174 + return LIBYUV_TRUE; 1.175 + } 1.176 + } 1.177 + return LIBYUV_FALSE; 1.178 +} 1.179 +#else // nacl does not support getenv(). 1.180 +static LIBYUV_BOOL TestEnv(const char*) { 1.181 + return LIBYUV_FALSE; 1.182 +} 1.183 +#endif 1.184 + 1.185 +LIBYUV_API SAFEBUFFERS 1.186 +int InitCpuFlags(void) { 1.187 +#if !defined(__pnacl__) && !defined(__CLR_VER) && defined(CPU_X86) 1.188 + 1.189 + uint32 cpu_info1[4] = { 0, 0, 0, 0 }; 1.190 + uint32 cpu_info7[4] = { 0, 0, 0, 0 }; 1.191 + CpuId(1, 0, cpu_info1); 1.192 + CpuId(7, 0, cpu_info7); 1.193 + cpu_info_ = ((cpu_info1[3] & 0x04000000) ? kCpuHasSSE2 : 0) | 1.194 + ((cpu_info1[2] & 0x00000200) ? kCpuHasSSSE3 : 0) | 1.195 + ((cpu_info1[2] & 0x00080000) ? kCpuHasSSE41 : 0) | 1.196 + ((cpu_info1[2] & 0x00100000) ? kCpuHasSSE42 : 0) | 1.197 + ((cpu_info7[1] & 0x00000200) ? kCpuHasERMS : 0) | 1.198 + ((cpu_info1[2] & 0x00001000) ? kCpuHasFMA3 : 0) | 1.199 + kCpuHasX86; 1.200 +#ifdef HAS_XGETBV 1.201 + if ((cpu_info1[2] & 0x18000000) == 0x18000000 && // AVX and OSSave 1.202 + TestOsSaveYmm()) { // Saves YMM. 1.203 + cpu_info_ |= ((cpu_info7[1] & 0x00000020) ? kCpuHasAVX2 : 0) | 1.204 + kCpuHasAVX; 1.205 + } 1.206 +#endif 1.207 + // Environment variable overrides for testing. 1.208 + if (TestEnv("LIBYUV_DISABLE_X86")) { 1.209 + cpu_info_ &= ~kCpuHasX86; 1.210 + } 1.211 + if (TestEnv("LIBYUV_DISABLE_SSE2")) { 1.212 + cpu_info_ &= ~kCpuHasSSE2; 1.213 + } 1.214 + if (TestEnv("LIBYUV_DISABLE_SSSE3")) { 1.215 + cpu_info_ &= ~kCpuHasSSSE3; 1.216 + } 1.217 + if (TestEnv("LIBYUV_DISABLE_SSE41")) { 1.218 + cpu_info_ &= ~kCpuHasSSE41; 1.219 + } 1.220 + if (TestEnv("LIBYUV_DISABLE_SSE42")) { 1.221 + cpu_info_ &= ~kCpuHasSSE42; 1.222 + } 1.223 + if (TestEnv("LIBYUV_DISABLE_AVX")) { 1.224 + cpu_info_ &= ~kCpuHasAVX; 1.225 + } 1.226 + if (TestEnv("LIBYUV_DISABLE_AVX2")) { 1.227 + cpu_info_ &= ~kCpuHasAVX2; 1.228 + } 1.229 + if (TestEnv("LIBYUV_DISABLE_ERMS")) { 1.230 + cpu_info_ &= ~kCpuHasERMS; 1.231 + } 1.232 + if (TestEnv("LIBYUV_DISABLE_FMA3")) { 1.233 + cpu_info_ &= ~kCpuHasFMA3; 1.234 + } 1.235 +#elif defined(__mips__) && defined(__linux__) 1.236 + // Linux mips parse text file for dsp detect. 1.237 + cpu_info_ = MipsCpuCaps("dsp"); // set kCpuHasMIPS_DSP. 1.238 +#if defined(__mips_dspr2) 1.239 + cpu_info_ |= kCpuHasMIPS_DSPR2; 1.240 +#endif 1.241 + cpu_info_ |= kCpuHasMIPS; 1.242 + 1.243 + if (getenv("LIBYUV_DISABLE_MIPS")) { 1.244 + cpu_info_ &= ~kCpuHasMIPS; 1.245 + } 1.246 + if (getenv("LIBYUV_DISABLE_MIPS_DSP")) { 1.247 + cpu_info_ &= ~kCpuHasMIPS_DSP; 1.248 + } 1.249 + if (getenv("LIBYUV_DISABLE_MIPS_DSPR2")) { 1.250 + cpu_info_ &= ~kCpuHasMIPS_DSPR2; 1.251 + } 1.252 +#elif defined(__arm__) 1.253 +#if defined(__linux__) && (defined(__ARM_NEON__) || defined(LIBYUV_NEON)) && \ 1.254 + !defined(__native_client__) 1.255 + // Linux arm parse text file for neon detect. 1.256 + cpu_info_ = ArmCpuCaps("/proc/cpuinfo"); 1.257 +#elif defined(__ARM_NEON__) || defined(__native_client__) 1.258 + // gcc -mfpu=neon defines __ARM_NEON__ 1.259 + // Enable Neon if you want support for Neon and Arm, and use MaskCpuFlags 1.260 + // to disable Neon on devices that do not have it. 1.261 + cpu_info_ = kCpuHasNEON; 1.262 +#endif 1.263 + cpu_info_ |= kCpuHasARM; 1.264 + if (TestEnv("LIBYUV_DISABLE_NEON")) { 1.265 + cpu_info_ &= ~kCpuHasNEON; 1.266 + } 1.267 +#endif // __arm__ 1.268 + if (TestEnv("LIBYUV_DISABLE_ASM")) { 1.269 + cpu_info_ = 0; 1.270 + } 1.271 + return cpu_info_; 1.272 +} 1.273 + 1.274 +LIBYUV_API 1.275 +void MaskCpuFlags(int enable_flags) { 1.276 + cpu_info_ = InitCpuFlags() & enable_flags; 1.277 +} 1.278 + 1.279 +#ifdef __cplusplus 1.280 +} // extern "C" 1.281 +} // namespace libyuv 1.282 +#endif