Bug 1157635 - Update DenormalDisabler.h from chromium rev e3bc1d8cebf65a51bb23abf204cf1ba059f1e865; r?karlt draft
authorDan Minor <dminor@mozilla.com>
Fri, 05 Aug 2016 14:22:24 -0400
changeset 445313 72baa2871d0284581282c40d62d1a838eb8f441f
parent 444478 05328d3102efd4d5fc0696489734d7771d24459f
child 445314 03ba2849386369dabe85ce4c82414231e81e2dcb
child 445322 c9ca123bdfafc08f057e9848d18c428dd5544bb1
child 445859 4af3dde520dd60dbc200fc04a9f6b26eceb1acc4
push id37477
push userdminor@mozilla.com
push dateTue, 29 Nov 2016 12:03:50 +0000
reviewerskarlt
bugs1157635
milestone53.0a1
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
dom/media/webaudio/blink/DenormalDisabler.h
--- 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() { }