Some API deprecation -- ExperimentalAgc and ExperimentalNs are gone. We're continuing to carry iSAC even though it's gone upstream, but maybe we'll want to drop that soon.
112 lines
3.7 KiB
C++
112 lines
3.7 KiB
C++
/*
|
|
* Copyright (c) 2021 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.
|
|
*/
|
|
|
|
#include "system_wrappers/include/denormal_disabler.h"
|
|
|
|
#include "rtc_base/checks.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
|
|
#if defined(WEBRTC_ARCH_X86_FAMILY) && defined(__clang__)
|
|
#define WEBRTC_DENORMAL_DISABLER_X86_SUPPORTED
|
|
#endif
|
|
|
|
#if defined(WEBRTC_DENORMAL_DISABLER_X86_SUPPORTED) || \
|
|
defined(WEBRTC_ARCH_ARM_FAMILY)
|
|
#define WEBRTC_DENORMAL_DISABLER_SUPPORTED
|
|
#endif
|
|
|
|
constexpr int kUnspecifiedStatusWord = -1;
|
|
|
|
#if defined(WEBRTC_DENORMAL_DISABLER_SUPPORTED)
|
|
|
|
// Control register bit mask to disable denormals on the hardware.
|
|
#if defined(WEBRTC_DENORMAL_DISABLER_X86_SUPPORTED)
|
|
// On x86 two bits are used: flush-to-zero (FTZ) and denormals-are-zero (DAZ).
|
|
constexpr int kDenormalBitMask = 0x8040;
|
|
#elif defined(WEBRTC_ARCH_ARM_FAMILY)
|
|
// On ARM one bit is used: flush-to-zero (FTZ).
|
|
constexpr int kDenormalBitMask = 1 << 24;
|
|
#endif
|
|
|
|
// Reads the relevant CPU control register and returns its value for supported
|
|
// architectures and compilers. Otherwise returns `kUnspecifiedStatusWord`.
|
|
int ReadStatusWord() {
|
|
int result = kUnspecifiedStatusWord;
|
|
#if defined(WEBRTC_DENORMAL_DISABLER_X86_SUPPORTED)
|
|
asm volatile("stmxcsr %0" : "=m"(result));
|
|
#elif defined(WEBRTC_ARCH_ARM_FAMILY) && defined(WEBRTC_ARCH_32_BITS)
|
|
asm volatile("vmrs %[result], FPSCR" : [result] "=r"(result));
|
|
#elif defined(WEBRTC_ARCH_ARM_FAMILY) && defined(WEBRTC_ARCH_64_BITS)
|
|
asm volatile("mrs %x[result], FPCR" : [result] "=r"(result));
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
// Writes `status_word` in the relevant CPU control register if the architecture
|
|
// and the compiler are supported.
|
|
void SetStatusWord(int status_word) {
|
|
#if defined(WEBRTC_DENORMAL_DISABLER_X86_SUPPORTED)
|
|
asm volatile("ldmxcsr %0" : : "m"(status_word));
|
|
#elif defined(WEBRTC_ARCH_ARM_FAMILY) && defined(WEBRTC_ARCH_32_BITS)
|
|
asm volatile("vmsr FPSCR, %[src]" : : [src] "r"(status_word));
|
|
#elif defined(WEBRTC_ARCH_ARM_FAMILY) && defined(WEBRTC_ARCH_64_BITS)
|
|
asm volatile("msr FPCR, %x[src]" : : [src] "r"(status_word));
|
|
#endif
|
|
}
|
|
|
|
// Returns true if the status word indicates that denormals are enabled.
|
|
constexpr bool DenormalsEnabled(int status_word) {
|
|
return (status_word & kDenormalBitMask) != kDenormalBitMask;
|
|
}
|
|
|
|
#endif // defined(WEBRTC_DENORMAL_DISABLER_SUPPORTED)
|
|
|
|
} // namespace
|
|
|
|
#if defined(WEBRTC_DENORMAL_DISABLER_SUPPORTED)
|
|
DenormalDisabler::DenormalDisabler() : DenormalDisabler(/*enabled=*/true) {}
|
|
|
|
DenormalDisabler::DenormalDisabler(bool enabled)
|
|
: status_word_(enabled ? ReadStatusWord() : kUnspecifiedStatusWord),
|
|
disabling_activated_(enabled && DenormalsEnabled(status_word_)) {
|
|
if (disabling_activated_) {
|
|
RTC_DCHECK_NE(status_word_, kUnspecifiedStatusWord);
|
|
SetStatusWord(status_word_ | kDenormalBitMask);
|
|
RTC_DCHECK(!DenormalsEnabled(ReadStatusWord()));
|
|
}
|
|
}
|
|
|
|
bool DenormalDisabler::IsSupported() {
|
|
return true;
|
|
}
|
|
|
|
DenormalDisabler::~DenormalDisabler() {
|
|
if (disabling_activated_) {
|
|
RTC_DCHECK_NE(status_word_, kUnspecifiedStatusWord);
|
|
SetStatusWord(status_word_);
|
|
}
|
|
}
|
|
#else
|
|
DenormalDisabler::DenormalDisabler() : DenormalDisabler(/*enabled=*/false) {}
|
|
|
|
DenormalDisabler::DenormalDisabler(bool enabled)
|
|
: status_word_(kUnspecifiedStatusWord), disabling_activated_(false) {}
|
|
|
|
bool DenormalDisabler::IsSupported() {
|
|
return false;
|
|
}
|
|
|
|
DenormalDisabler::~DenormalDisabler() = default;
|
|
#endif
|
|
|
|
} // namespace webrtc
|