| /* |
| * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| // Parts of this file derived from Chromium's base/cpu.cc. |
| |
| #include "rtc_base/system/arch.h" |
| #include "system_wrappers/include/cpu_features_wrapper.h" |
| #include "system_wrappers/include/field_trial.h" |
| |
| #if defined(WEBRTC_ARCH_X86_FAMILY) && defined(_MSC_VER) |
| #include <intrin.h> |
| #endif |
| |
| namespace webrtc { |
| |
| // No CPU feature is available => straight C path. |
| int GetCPUInfoNoASM(CPUFeature feature) { |
| (void)feature; |
| return 0; |
| } |
| |
| #if defined(WEBRTC_ARCH_X86_FAMILY) |
| |
| #if defined(WEBRTC_ENABLE_AVX2) |
| // xgetbv returns the value of an Intel Extended Control Register (XCR). |
| // Currently only XCR0 is defined by Intel so `xcr` should always be zero. |
| static uint64_t xgetbv(uint32_t xcr) { |
| #if defined(_MSC_VER) |
| return _xgetbv(xcr); |
| #else |
| uint32_t eax, edx; |
| |
| __asm__ volatile("xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr)); |
| return (static_cast<uint64_t>(edx) << 32) | eax; |
| #endif // _MSC_VER |
| } |
| #endif // WEBRTC_ENABLE_AVX2 |
| |
| #ifndef _MSC_VER |
| // Intrinsic for "cpuid". |
| #if defined(__pic__) && defined(__i386__) |
| static inline void __cpuid(int cpu_info[4], int info_type) { |
| __asm__ volatile( |
| "mov %%ebx, %%edi\n" |
| "cpuid\n" |
| "xchg %%edi, %%ebx\n" |
| : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), |
| "=d"(cpu_info[3]) |
| : "a"(info_type)); |
| } |
| #else |
| static inline void __cpuid(int cpu_info[4], int info_type) { |
| __asm__ volatile("cpuid\n" |
| : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), |
| "=d"(cpu_info[3]) |
| : "a"(info_type), "c"(0)); |
| } |
| #endif |
| #endif // _MSC_VER |
| #endif // WEBRTC_ARCH_X86_FAMILY |
| |
| #if defined(WEBRTC_ARCH_X86_FAMILY) |
| // Actual feature detection for x86. |
| int GetCPUInfo(CPUFeature feature) { |
| int cpu_info[4]; |
| __cpuid(cpu_info, 1); |
| if (feature == kSSE2) { |
| return 0 != (cpu_info[3] & 0x04000000); |
| } |
| if (feature == kSSE3) { |
| return 0 != (cpu_info[2] & 0x00000001); |
| } |
| #if defined(WEBRTC_ENABLE_AVX2) |
| if (feature == kAVX2 && |
| !webrtc::field_trial::IsEnabled("WebRTC-Avx2SupportKillSwitch")) { |
| int cpu_info7[4]; |
| __cpuid(cpu_info7, 0); |
| int num_ids = cpu_info7[0]; |
| if (num_ids < 7) { |
| return 0; |
| } |
| // Interpret CPU feature information. |
| __cpuid(cpu_info7, 7); |
| |
| // AVX instructions can be used when |
| // a) AVX are supported by the CPU, |
| // b) XSAVE is supported by the CPU, |
| // c) XSAVE is enabled by the kernel. |
| // Compiling with MSVC and /arch:AVX2 surprisingly generates BMI2 |
| // instructions (see crbug.com/1315519). |
| return (cpu_info[2] & 0x10000000) != 0 /* AVX */ && |
| (cpu_info[2] & 0x04000000) != 0 /* XSAVE */ && |
| (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ && |
| (xgetbv(0) & 0x00000006) == 6 /* XSAVE enabled by kernel */ && |
| (cpu_info7[1] & 0x00000020) != 0 /* AVX2 */ && |
| (cpu_info7[1] & 0x00000100) != 0 /* BMI2 */; |
| } |
| #endif // WEBRTC_ENABLE_AVX2 |
| if (feature == kFMA3) { |
| return 0 != (cpu_info[2] & 0x00001000); |
| } |
| return 0; |
| } |
| #else |
| // Default to straight C for other platforms. |
| int GetCPUInfo(CPUFeature feature) { |
| (void)feature; |
| return 0; |
| } |
| #endif |
| |
| } // namespace webrtc |