1 /* 2 * Copyright (C) 2011, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 23 * DAMAGE. 24 */ 25 26 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_DENORMAL_DISABLER_H_ 27 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_DENORMAL_DISABLER_H_ 28 29 #include <float.h> 30 #include "build/build_config.h" 31 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" 32 #include "third_party/blink/renderer/platform/wtf/math_extras.h" 33 34 namespace blink { 35 36 // Deal with denormals. They can very seriously impact performance on x86. 37 38 // Define HAVE_DENORMAL if we support flushing denormals to zero. 39 40 #if defined(OS_WIN) && defined(COMPILER_MSVC) 41 // Windows compiled using MSVC with SSE2 42 #define HAVE_DENORMAL 1 43 #endif 44 45 #if defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY) 46 // X86 chips can flush denormals 47 #define HAVE_DENORMAL 1 48 #endif 49 50 #if defined(ARCH_CPU_ARM_FAMILY) 51 #define HAVE_DENORMAL 1 52 #endif 53 54 #if defined(HAVE_DENORMAL) 55 class DenormalDisabler { 56 DISALLOW_NEW(); 57 58 public: DenormalDisabler()59 DenormalDisabler() : saved_csr_(0) { DisableDenormals(); } 60 ~DenormalDisabler()61 ~DenormalDisabler() { RestoreState(); } 62 63 // This is a nop if we can flush denormals to zero in hardware. FlushDenormalFloatToZero(float f)64 static inline float FlushDenormalFloatToZero(float f) { return f; } 65 66 private: 67 unsigned saved_csr_; 68 69 #if defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY) DisableDenormals()70 inline void DisableDenormals() { 71 saved_csr_ = GetCSR(); 72 SetCSR(saved_csr_ | 0x8040); 73 } 74 RestoreState()75 inline void RestoreState() { SetCSR(saved_csr_); } 76 GetCSR()77 inline int GetCSR() { 78 int result; 79 asm volatile("stmxcsr %0" : "=m"(result)); 80 return result; 81 } 82 SetCSR(int a)83 inline void SetCSR(int a) { 84 int temp = a; 85 asm volatile("ldmxcsr %0" : : "m"(temp)); 86 } 87 88 #elif defined(OS_WIN) && defined(COMPILER_MSVC) DisableDenormals()89 inline void DisableDenormals() { 90 // Save the current state, and set mode to flush denormals. 91 // 92 // http://stackoverflow.com/questions/637175/possible-bug-in-controlfp-s-may-not-restore-control-word-correctly 93 _controlfp_s(&saved_csr_, 0, 0); 94 unsigned unused; 95 _controlfp_s(&unused, _DN_FLUSH, _MCW_DN); 96 } 97 RestoreState()98 inline void RestoreState() { 99 unsigned unused; 100 _controlfp_s(&unused, saved_csr_, _MCW_DN); 101 } 102 #elif defined(ARCH_CPU_ARM_FAMILY) DisableDenormals()103 inline void DisableDenormals() { 104 saved_csr_ = GetStatusWord(); 105 // Bit 24 is the flush-to-zero mode control bit. Setting it to 1 flushes 106 // denormals to 0. 107 SetStatusWord(saved_csr_ | (1 << 24)); 108 } 109 RestoreState()110 inline void RestoreState() { SetStatusWord(saved_csr_); } 111 GetStatusWord()112 inline int GetStatusWord() { 113 int result; 114 #if defined(ARCH_CPU_ARM64) 115 asm volatile("mrs %x[result], FPCR" : [result] "=r"(result)); 116 #else 117 asm volatile("vmrs %[result], FPSCR" : [result] "=r"(result)); 118 #endif 119 return result; 120 } 121 SetStatusWord(int a)122 inline void SetStatusWord(int a) { 123 #if defined(ARCH_CPU_ARM64) 124 asm volatile("msr FPCR, %x[src]" : : [src] "r"(a)); 125 #else 126 asm volatile("vmsr FPSCR, %[src]" : : [src] "r"(a)); 127 #endif 128 } 129 130 #endif 131 }; 132 133 #else 134 // FIXME: add implementations for other architectures and compilers 135 class DenormalDisabler { 136 STACK_ALLOCATED(); 137 138 public: 139 DenormalDisabler() {} 140 141 // Assume the worst case that other architectures and compilers 142 // need to flush denormals to zero manually. 143 static inline float FlushDenormalFloatToZero(float f) { 144 return (fabs(f) < FLT_MIN) ? 0.0f : f; 145 } 146 }; 147 148 #endif 149 150 } // namespace blink 151 152 #undef HAVE_DENORMAL 153 #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_AUDIO_DENORMAL_DISABLER_H_ 154