Line data Source code
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 <cmath>
29 : #include <float.h>
30 :
31 : namespace WebCore {
32 :
33 : // Deal with denormals. They can very seriously impact performance on x86.
34 :
35 : // Define HAVE_DENORMAL if we support flushing denormals to zero.
36 :
37 : #if defined (XP_WIN) && defined(_MSC_VER)
38 : // Windows compiled using MSVC with SSE2
39 : #define HAVE_DENORMAL 1
40 : #endif
41 :
42 : #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
43 : // X86 chips can flush denormals
44 : #define HAVE_DENORMAL 1
45 : #endif
46 :
47 : #if defined(__arm__) || defined(__aarch64__)
48 : #define HAVE_DENORMAL 1
49 : #endif
50 :
51 : #ifdef HAVE_DENORMAL
52 : class DenormalDisabler {
53 : public:
54 0 : DenormalDisabler()
55 0 : : m_savedCSR(0)
56 : {
57 0 : disableDenormals();
58 0 : }
59 :
60 0 : ~DenormalDisabler()
61 0 : {
62 0 : restoreState();
63 0 : }
64 :
65 : // This is a nop if we can flush denormals to zero in hardware.
66 0 : static inline float flushDenormalFloatToZero(float f)
67 : {
68 0 : return f;
69 : }
70 : private:
71 : unsigned m_savedCSR;
72 :
73 : #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
74 0 : inline void disableDenormals()
75 : {
76 0 : m_savedCSR = getCSR();
77 0 : setCSR(m_savedCSR | 0x8040);
78 0 : }
79 :
80 0 : inline void restoreState()
81 : {
82 0 : setCSR(m_savedCSR);
83 0 : }
84 :
85 0 : inline int getCSR()
86 : {
87 : int result;
88 0 : asm volatile("stmxcsr %0" : "=m" (result));
89 0 : return result;
90 : }
91 :
92 0 : inline void setCSR(int a)
93 : {
94 0 : int temp = a;
95 0 : asm volatile("ldmxcsr %0" : : "m" (temp));
96 0 : }
97 :
98 : #elif defined (XP_WIN) && defined(_MSC_VER)
99 : inline void disableDenormals()
100 : {
101 : // Save the current state, and set mode to flush denormals.
102 : //
103 : // http://stackoverflow.com/questions/637175/possible-bug-in-controlfp-s-may-not-restore-control-word-correctly
104 : _controlfp_s(&m_savedCSR, 0, 0);
105 : unsigned unused;
106 : _controlfp_s(&unused, _DN_FLUSH, _MCW_DN);
107 : }
108 :
109 : inline void restoreState()
110 : {
111 : unsigned unused;
112 : _controlfp_s(&unused, m_savedCSR, _MCW_DN);
113 : }
114 : #elif defined(__arm__) || defined(__aarch64__)
115 : inline void disableDenormals()
116 : {
117 : m_savedCSR = getStatusWord();
118 : // Bit 24 is the flush-to-zero mode control bit. Setting it to 1 flushes denormals to 0.
119 : setStatusWord(m_savedCSR | (1 << 24));
120 : }
121 :
122 : inline void restoreState()
123 : {
124 : setStatusWord(m_savedCSR);
125 : }
126 :
127 : inline int getStatusWord()
128 : {
129 : int result;
130 : #if defined(__aarch64__)
131 : asm volatile("mrs %x[result], FPCR" : [result] "=r" (result));
132 : #else
133 : asm volatile("vmrs %[result], FPSCR" : [result] "=r" (result));
134 : #endif
135 : return result;
136 : }
137 :
138 : inline void setStatusWord(int a)
139 : {
140 : #if defined(__aarch64__)
141 : asm volatile("msr FPCR, %x[src]" : : [src] "r" (a));
142 : #else
143 : asm volatile("vmsr FPSCR, %[src]" : : [src] "r" (a));
144 : #endif
145 : }
146 :
147 : #endif
148 :
149 : };
150 :
151 : #else
152 : // FIXME: add implementations for other architectures and compilers
153 : class DenormalDisabler {
154 : public:
155 : DenormalDisabler() { }
156 :
157 : // Assume the worst case that other architectures and compilers
158 : // need to flush denormals to zero manually.
159 : static inline float flushDenormalFloatToZero(float f)
160 : {
161 : return (fabs(f) < FLT_MIN) ? 0.0f : f;
162 : }
163 : };
164 :
165 : #endif
166 :
167 : } // namespace WebCore
168 : #endif // DenormalDisabler_h
|