• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24 
25 #ifndef DenormalDisabler_h
26 #define DenormalDisabler_h
27 
28 #include "wtf/CPU.h"
29 #include "wtf/MathExtras.h"
30 #include <float.h>
31 
32 namespace blink {
33 
34 // Deal with denormals. They can very seriously impact performance on x86.
35 
36 // Define HAVE_DENORMAL if we support flushing denormals to zero.
37 
38 #if OS(WIN) && COMPILER(MSVC)
39 // Windows compiled using MSVC with SSE2
40 #define HAVE_DENORMAL 1
41 #endif
42 
43 #if COMPILER(GCC) && (CPU(X86) || CPU(X86_64))
44 // X86 chips can flush denormals
45 #define HAVE_DENORMAL 1
46 #endif
47 
48 #if CPU(ARM) || CPU(ARM64)
49 #define HAVE_DENORMAL 1
50 #endif
51 
52 #if HAVE(DENORMAL)
53 class DenormalDisabler {
54 public:
DenormalDisabler()55     DenormalDisabler()
56             : m_savedCSR(0)
57     {
58         disableDenormals();
59     }
60 
~DenormalDisabler()61     ~DenormalDisabler()
62     {
63         restoreState();
64     }
65 
66     // This is a nop if we can flush denormals to zero in hardware.
flushDenormalFloatToZero(float f)67     static inline float flushDenormalFloatToZero(float f)
68     {
69         return f;
70     }
71 private:
72     unsigned m_savedCSR;
73 
74 #if COMPILER(GCC) && (CPU(X86) || CPU(X86_64))
disableDenormals()75     inline void disableDenormals()
76     {
77         m_savedCSR = getCSR();
78         setCSR(m_savedCSR | 0x8040);
79     }
80 
restoreState()81     inline void restoreState()
82     {
83         setCSR(m_savedCSR);
84     }
85 
getCSR()86     inline int getCSR()
87     {
88         int result;
89         asm volatile("stmxcsr %0" : "=m" (result));
90         return result;
91     }
92 
setCSR(int a)93     inline void setCSR(int a)
94     {
95         int temp = a;
96         asm volatile("ldmxcsr %0" : : "m" (temp));
97     }
98 
99 #elif OS(WIN) && COMPILER(MSVC)
disableDenormals()100     inline void disableDenormals()
101     {
102         // Save the current state, and set mode to flush denormals.
103         //
104         // http://stackoverflow.com/questions/637175/possible-bug-in-controlfp-s-may-not-restore-control-word-correctly
105         _controlfp_s(&m_savedCSR, 0, 0);
106         unsigned unused;
107         _controlfp_s(&unused, _DN_FLUSH, _MCW_DN);
108     }
109 
restoreState()110     inline void restoreState()
111     {
112         unsigned unused;
113         _controlfp_s(&unused, m_savedCSR, _MCW_DN);
114     }
115 #elif CPU(ARM) || CPU(ARM64)
disableDenormals()116     inline void disableDenormals()
117     {
118         m_savedCSR = getStatusWord();
119         // Bit 24 is the flush-to-zero mode control bit. Setting it to 1 flushes denormals to 0.
120         setStatusWord(m_savedCSR | (1 << 24));
121     }
122 
restoreState()123     inline void restoreState()
124     {
125         setStatusWord(m_savedCSR);
126     }
127 
getStatusWord()128     inline int getStatusWord()
129     {
130         int result;
131 #if CPU(ARM64)
132         asm volatile("mrs %[result], FPCR" : [result] "=r" (result));
133 #else
134         asm volatile("vmrs %[result], FPSCR" : [result] "=r" (result));
135 #endif
136         return result;
137     }
138 
setStatusWord(int a)139     inline void setStatusWord(int a)
140     {
141 #if CPU(ARM64)
142         asm volatile("msr FPCR, %[src]" : : [src] "r" (a));
143 #else
144         asm volatile("vmsr FPSCR, %[src]" : : [src] "r" (a));
145 #endif
146     }
147 
148 #endif
149 
150 };
151 
152 #else
153 // FIXME: add implementations for other architectures and compilers
154 class DenormalDisabler {
155 public:
156     DenormalDisabler() { }
157 
158     // Assume the worst case that other architectures and compilers
159     // need to flush denormals to zero manually.
160     static inline float flushDenormalFloatToZero(float f)
161     {
162         return (fabs(f) < FLT_MIN) ? 0.0f : f;
163     }
164 };
165 
166 #endif
167 
168 } // namespace blink
169 
170 #undef HAVE_DENORMAL
171 #endif // DenormalDisabler_h
172