summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/system_wrappers/source/denormal_disabler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/system_wrappers/source/denormal_disabler.cc')
-rw-r--r--third_party/libwebrtc/system_wrappers/source/denormal_disabler.cc111
1 files changed, 111 insertions, 0 deletions
diff --git a/third_party/libwebrtc/system_wrappers/source/denormal_disabler.cc b/third_party/libwebrtc/system_wrappers/source/denormal_disabler.cc
new file mode 100644
index 0000000000..bb9c05643c
--- /dev/null
+++ b/third_party/libwebrtc/system_wrappers/source/denormal_disabler.cc
@@ -0,0 +1,111 @@
+/*
+ * 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