Bug 1157635 - Update DenormalDisabler.h from chromium rev e3bc1d8cebf65a51bb23abf204cf1ba059f1e865; r?karlt
Since this was originally landed, chromium has added support disabling denormalized
numbers on ARM and ARM64.
MozReview-Commit-ID: 7hdZNpJqA9q
--- a/dom/media/webaudio/blink/DenormalDisabler.h
+++ b/dom/media/webaudio/blink/DenormalDisabler.h
@@ -28,83 +28,129 @@
#include <cmath>
#include <float.h>
namespace WebCore {
// Deal with denormals. They can very seriously impact performance on x86.
// Define HAVE_DENORMAL if we support flushing denormals to zero.
-#if defined(XP_WIN) && defined(_MSC_VER)
-#define HAVE_DENORMAL
+
+#if defined (XP_WIN) && defined(_MSC_VER)
+// Windows compiled using MSVC with SSE2
+#define HAVE_DENORMAL 1
#endif
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-#define HAVE_DENORMAL
+// X86 chips can flush denormals
+#define HAVE_DENORMAL 1
+#endif
+
+#if defined(__arm__) || defined(__aarch64__)
+#define HAVE_DENORMAL 1
#endif
#ifdef HAVE_DENORMAL
class DenormalDisabler {
public:
DenormalDisabler()
: m_savedCSR(0)
{
-#if defined(XP_WIN) && defined(_MSC_VER)
- // Save the current state, and set mode to flush denormals.
- //
- // http://stackoverflow.com/questions/637175/possible-bug-in-controlfp-s-may-not-restore-control-word-correctly
- _controlfp_s(&m_savedCSR, 0, 0);
- unsigned int unused;
- _controlfp_s(&unused, _DN_FLUSH, _MCW_DN);
-#else
- m_savedCSR = getCSR();
- setCSR(m_savedCSR | 0x8040);
-#endif
+ disableDenormals();
}
~DenormalDisabler()
{
-#if defined(XP_WIN) && defined(_MSC_VER)
- unsigned int unused;
- _controlfp_s(&unused, m_savedCSR, _MCW_DN);
-#else
- setCSR(m_savedCSR);
-#endif
+ restoreState();
}
// This is a nop if we can flush denormals to zero in hardware.
static inline float flushDenormalFloatToZero(float f)
{
-#if defined(XP_WIN) && defined(_MSC_VER) && _M_IX86_FP
- // For systems using x87 instead of sse, there's no hardware support
- // to flush denormals automatically. Hence, we need to flush
- // denormals to zero manually.
- return (fabs(f) < FLT_MIN) ? 0.0f : f;
-#else
return f;
-#endif
}
private:
+ unsigned m_savedCSR;
+
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+ inline void disableDenormals()
+ {
+ m_savedCSR = getCSR();
+ setCSR(m_savedCSR | 0x8040);
+ }
+
+ inline void restoreState()
+ {
+ setCSR(m_savedCSR);
+ }
+
inline int getCSR()
{
int result;
asm volatile("stmxcsr %0" : "=m" (result));
return result;
}
inline void setCSR(int a)
{
int temp = a;
asm volatile("ldmxcsr %0" : : "m" (temp));
}
+#elif defined (XP_WIN) && defined(_MSC_VER)
+ inline void disableDenormals()
+ {
+ // Save the current state, and set mode to flush denormals.
+ //
+ // http://stackoverflow.com/questions/637175/possible-bug-in-controlfp-s-may-not-restore-control-word-correctly
+ _controlfp_s(&m_savedCSR, 0, 0);
+ unsigned unused;
+ _controlfp_s(&unused, _DN_FLUSH, _MCW_DN);
+ }
+
+ inline void restoreState()
+ {
+ unsigned unused;
+ _controlfp_s(&unused, m_savedCSR, _MCW_DN);
+ }
+#elif defined(__arm__) || defined(__aarch64__)
+ inline void disableDenormals()
+ {
+ m_savedCSR = getStatusWord();
+ // Bit 24 is the flush-to-zero mode control bit. Setting it to 1 flushes denormals to 0.
+ setStatusWord(m_savedCSR | (1 << 24));
+ }
+
+ inline void restoreState()
+ {
+ setStatusWord(m_savedCSR);
+ }
+
+ inline int getStatusWord()
+ {
+ int result;
+#if defined(__aarch64__)
+ asm volatile("mrs %x[result], FPCR" : [result] "=r" (result));
+#else
+ asm volatile("vmrs %[result], FPSCR" : [result] "=r" (result));
+#endif
+ return result;
+ }
+
+ inline void setStatusWord(int a)
+ {
+#if defined(__aarch64__)
+ asm volatile("msr FPCR, %x[src]" : : [src] "r" (a));
+#else
+ asm volatile("vmsr FPSCR, %[src]" : : [src] "r" (a));
+#endif
+ }
+
#endif
- unsigned int m_savedCSR;
};
#else
// FIXME: add implementations for other architectures and compilers
class DenormalDisabler {
public:
DenormalDisabler() { }