Bug 1248555: Introduce variants of SpecificNaN / BitwiseCast that preserve the signaling NaN bit; r=froydnj
authorBenjamin Bouvier <benj@benj.me>
Mon, 01 Aug 2016 20:02:05 +0200
changeset 307846 89a131cc0bfdfe00262a53738a59219ad9e91389
parent 307845 c39c24ce6b51f17740cb827ca3df77b66e43a7a7
child 307847 08cbf5bdf4f4b637b9a4d3ff1a5cd40d11ae60c2
push id80200
push userbbouvier@mozilla.com
push dateWed, 03 Aug 2016 10:12:14 +0000
treeherdermozilla-inbound@3e7e914abf3d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1248555
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1248555: Introduce variants of SpecificNaN / BitwiseCast that preserve the signaling NaN bit; r=froydnj MozReview-Commit-ID: 5A8p06nBqyI
mfbt/Casting.h
mfbt/FloatingPoint.h
--- a/mfbt/Casting.h
+++ b/mfbt/Casting.h
@@ -12,36 +12,58 @@
 #include "mozilla/Assertions.h"
 #include "mozilla/TypeTraits.h"
 
 #include <limits.h>
 
 namespace mozilla {
 
 /**
- * Return a value of type |To|, containing the underlying bit pattern of
+ * Sets the outparam value of type |To| with the same underlying bit pattern of
  * |aFrom|.
  *
  * |To| and |From| must be types of the same size; be careful of cross-platform
  * size differences, or this might fail to compile on some but not all
  * platforms.
+ *
+ * There is also a variant that returns the value directly.  In most cases, the
+ * two variants should be identical.  However, in the specific case of x86
+ * chips, the behavior differs: returning floating-point values directly is done
+ * through the x87 stack, and x87 loads and stores turn signaling NaNs into
+ * quiet NaNs... silently.  Returning floating-point values via outparam,
+ * however, is done entirely within the SSE registers when SSE2 floating-point
+ * is enabled in the compiler, which has semantics-preserving behavior you would
+ * expect.
+ *
+ * If preserving the distinction between signaling NaNs and quiet NaNs is
+ * important to you, you should use the outparam version.  In all other cases,
+ * you should use the direct return version.
  */
 template<typename To, typename From>
-inline To
-BitwiseCast(const From aFrom)
+inline void
+BitwiseCast(const From aFrom, To* aResult)
 {
   static_assert(sizeof(From) == sizeof(To),
                 "To and From must have the same size");
   union
   {
     From mFrom;
     To mTo;
   } u;
   u.mFrom = aFrom;
-  return u.mTo;
+  *aResult = u.mTo;
+}
+
+template<typename To, typename From>
+inline To
+BitwiseCast(const From aFrom)
+{
+  To temp;
+  BitwiseCast<To, From>(aFrom, &temp);
+  return temp;
 }
 
 namespace detail {
 
 enum ToSignedness { ToIsSigned, ToIsUnsigned };
 enum FromSignedness { FromIsSigned, FromIsUnsigned };
 
 template<typename From,
--- a/mfbt/FloatingPoint.h
+++ b/mfbt/FloatingPoint.h
@@ -240,30 +240,54 @@ NegativeInfinity()
    * Negative infinity has all exponent bits set, sign bit set to 1, and no
    * significand.
    */
   typedef FloatingPoint<T> Traits;
   return BitwiseCast<T>(Traits::kSignBit | Traits::kExponentBits);
 }
 
 
-/** Constructs a NaN value with the specified sign bit and significand bits. */
+/**
+ * Constructs a NaN value with the specified sign bit and significand bits.
+ *
+ * There is also a variant that returns the value directly.  In most cases, the
+ * two variants should be identical.  However, in the specific case of x86
+ * chips, the behavior differs: returning floating-point values directly is done
+ * through the x87 stack, and x87 loads and stores turn signaling NaNs into
+ * quiet NaNs... silently.  Returning floating-point values via outparam,
+ * however, is done entirely within the SSE registers when SSE2 floating-point
+ * is enabled in the compiler, which has semantics-preserving behavior you would
+ * expect.
+ *
+ * If preserving the distinction between signaling NaNs and quiet NaNs is
+ * important to you, you should use the outparam version.  In all other cases,
+ * you should use the direct return version.
+ */
 template<typename T>
-static MOZ_ALWAYS_INLINE T
-SpecificNaN(int signbit, typename FloatingPoint<T>::Bits significand)
+static MOZ_ALWAYS_INLINE void
+SpecificNaN(int signbit, typename FloatingPoint<T>::Bits significand, T* result)
 {
   typedef FloatingPoint<T> Traits;
   MOZ_ASSERT(signbit == 0 || signbit == 1);
   MOZ_ASSERT((significand & ~Traits::kSignificandBits) == 0);
   MOZ_ASSERT(significand & Traits::kSignificandBits);
 
-  T t = BitwiseCast<T>((signbit ? Traits::kSignBit : 0) |
-                       Traits::kExponentBits |
-                       significand);
-  MOZ_ASSERT(IsNaN(t));
+  BitwiseCast<T>((signbit ? Traits::kSignBit : 0) |
+                  Traits::kExponentBits |
+                  significand,
+                  result);
+  MOZ_ASSERT(IsNaN(*result));
+}
+
+template<typename T>
+static MOZ_ALWAYS_INLINE T
+SpecificNaN(int signbit, typename FloatingPoint<T>::Bits significand)
+{
+  T t;
+  SpecificNaN(signbit, significand, &t);
   return t;
 }
 
 /** Computes the smallest non-zero positive float/double value. */
 template<typename T>
 static MOZ_ALWAYS_INLINE T
 MinNumberValue()
 {