• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "system_wrappers/include/denormal_disabler.h"
12 
13 #include "rtc_base/checks.h"
14 
15 namespace webrtc {
16 namespace {
17 
18 #if defined(WEBRTC_ARCH_X86_FAMILY) && defined(__clang__)
19 #define WEBRTC_DENORMAL_DISABLER_X86_SUPPORTED
20 #endif
21 
22 #if defined(WEBRTC_DENORMAL_DISABLER_X86_SUPPORTED) || \
23     defined(WEBRTC_ARCH_ARM_FAMILY)
24 #define WEBRTC_DENORMAL_DISABLER_SUPPORTED
25 #endif
26 
27 constexpr int kUnspecifiedStatusWord = -1;
28 
29 #if defined(WEBRTC_DENORMAL_DISABLER_SUPPORTED)
30 
31 // Control register bit mask to disable denormals on the hardware.
32 #if defined(WEBRTC_DENORMAL_DISABLER_X86_SUPPORTED)
33 // On x86 two bits are used: flush-to-zero (FTZ) and denormals-are-zero (DAZ).
34 constexpr int kDenormalBitMask = 0x8040;
35 #elif defined(WEBRTC_ARCH_ARM_FAMILY)
36 // On ARM one bit is used: flush-to-zero (FTZ).
37 constexpr int kDenormalBitMask = 1 << 24;
38 #endif
39 
40 // Reads the relevant CPU control register and returns its value for supported
41 // architectures and compilers. Otherwise returns `kUnspecifiedStatusWord`.
ReadStatusWord()42 int ReadStatusWord() {
43   int result = kUnspecifiedStatusWord;
44 #if defined(WEBRTC_DENORMAL_DISABLER_X86_SUPPORTED)
45   asm volatile("stmxcsr %0" : "=m"(result));
46 #elif defined(WEBRTC_ARCH_ARM_FAMILY) && defined(WEBRTC_ARCH_32_BITS)
47   asm volatile("vmrs %[result], FPSCR" : [result] "=r"(result));
48 #elif defined(WEBRTC_ARCH_ARM_FAMILY) && defined(WEBRTC_ARCH_64_BITS)
49   asm volatile("mrs %x[result], FPCR" : [result] "=r"(result));
50 #endif
51   return result;
52 }
53 
54 // Writes `status_word` in the relevant CPU control register if the architecture
55 // and the compiler are supported.
SetStatusWord(int status_word)56 void SetStatusWord(int status_word) {
57 #if defined(WEBRTC_DENORMAL_DISABLER_X86_SUPPORTED)
58   asm volatile("ldmxcsr %0" : : "m"(status_word));
59 #elif defined(WEBRTC_ARCH_ARM_FAMILY) && defined(WEBRTC_ARCH_32_BITS)
60   asm volatile("vmsr FPSCR, %[src]" : : [src] "r"(status_word));
61 #elif defined(WEBRTC_ARCH_ARM_FAMILY) && defined(WEBRTC_ARCH_64_BITS)
62   asm volatile("msr FPCR, %x[src]" : : [src] "r"(status_word));
63 #endif
64 }
65 
66 // Returns true if the status word indicates that denormals are enabled.
DenormalsEnabled(int status_word)67 constexpr bool DenormalsEnabled(int status_word) {
68   return (status_word & kDenormalBitMask) != kDenormalBitMask;
69 }
70 
71 #endif  // defined(WEBRTC_DENORMAL_DISABLER_SUPPORTED)
72 
73 }  // namespace
74 
75 #if defined(WEBRTC_DENORMAL_DISABLER_SUPPORTED)
DenormalDisabler(bool enabled)76 DenormalDisabler::DenormalDisabler(bool enabled)
77     : status_word_(enabled ? ReadStatusWord() : kUnspecifiedStatusWord),
78       disabling_activated_(enabled && DenormalsEnabled(status_word_)) {
79   if (disabling_activated_) {
80     RTC_DCHECK_NE(status_word_, kUnspecifiedStatusWord);
81     SetStatusWord(status_word_ | kDenormalBitMask);
82     RTC_DCHECK(!DenormalsEnabled(ReadStatusWord()));
83   }
84 }
85 
IsSupported()86 bool DenormalDisabler::IsSupported() {
87   return true;
88 }
89 
~DenormalDisabler()90 DenormalDisabler::~DenormalDisabler() {
91   if (disabling_activated_) {
92     RTC_DCHECK_NE(status_word_, kUnspecifiedStatusWord);
93     SetStatusWord(status_word_);
94   }
95 }
96 #else
DenormalDisabler(bool enabled)97 DenormalDisabler::DenormalDisabler(bool enabled)
98     : status_word_(kUnspecifiedStatusWord), disabling_activated_(false) {}
99 
IsSupported()100 bool DenormalDisabler::IsSupported() {
101   return false;
102 }
103 
104 DenormalDisabler::~DenormalDisabler() = default;
105 #endif
106 
107 }  // namespace webrtc
108