mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 22:00:47 +01:00

With MSVC, compiling with AVX2 support will also result in the generation of BMI2 instructions. Some early Haswell CPUs reportedly support AVX2 but not BMI2. We have seen crashes (illegal instruction) on these CPUs in our AVX2 code paths on MULX instructions (part of BMI2). Including a check for BMI2 when checking for AVX2 support is expected to solve the issue. Please see the bug referenced below for more background on this issue. Bug: chromium:1315519 Change-Id: I3a0a9838f1f632704ba505ecbb81a6f8b1889319 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/260323 Commit-Queue: Gustaf Ullberg <gustaf@webrtc.org> Reviewed-by: Sam Zackrisson <saza@webrtc.org> Reviewed-by: Henrik Andreasson <henrika@google.com> Reviewed-by: Niels Moller <nisse@webrtc.org> Cr-Commit-Position: refs/heads/main@{#36701}
116 lines
3.4 KiB
C++
116 lines
3.4 KiB
C++
/*
|
|
* 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
|
|
return 0;
|
|
}
|
|
#else
|
|
// Default to straight C for other platforms.
|
|
int GetCPUInfo(CPUFeature feature) {
|
|
(void)feature;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
} // namespace webrtc
|