Issue #1240 - Part 3a - Adjust mozilla::FloatingPoint<T>'s definition. So only the barest details are specified for floating-point encodings, with every other number, bit mask, &c. mathematically derived. Also add a bunch of documentation comments. https://bugzilla.mozilla.org/show_bug.cgi?id=1508725 Prerequisite for our V8 fast forward.

This commit is contained in:
Brian Smith 2023-07-13 03:02:29 -05:00 • committed by roytam1
commit ddd49121a6
3 changed files with 77 additions and 37 deletions

View file

@ -507,7 +507,7 @@ class MOZ_NON_PARAM alignas(8) Value
#if defined(JS_NUNBOX32) #if defined(JS_NUNBOX32)
return uint32_t(toTag()) <= uint32_t(JSVAL_TAG_CLEAR); return uint32_t(toTag()) <= uint32_t(JSVAL_TAG_CLEAR);
#elif defined(JS_PUNBOX64) #elif defined(JS_PUNBOX64)
return (data.asBits | mozilla::DoubleTypeTraits::kSignBit) <= JSVAL_SHIFTED_TAG_MAX_DOUBLE; return (data.asBits | mozilla::FloatingPoint<double>::kSignBit) <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
#endif #endif
} }
@ -1090,7 +1090,7 @@ IsCanonicalized(double d)
uint64_t bits; uint64_t bits;
mozilla::BitwiseCast<uint64_t>(d, &bits); mozilla::BitwiseCast<uint64_t>(d, &bits);
return (bits & ~mozilla::DoubleTypeTraits::kSignBit) == detail::CanonicalizedNaNBits; return (bits & ~mozilla::FloatingPoint<double>::kSignBit) == detail::CanonicalizedNaNBits;
} }
static inline Value static inline Value

View file

@ -54,7 +54,7 @@ template<class T>
bool bool
js::wasm::RenderNaN(StringBuffer& sb, Raw<T> num) js::wasm::RenderNaN(StringBuffer& sb, Raw<T> num)
{ {
typedef typename mozilla::SelectTrait<T> Traits; typedef typename mozilla::FloatingPoint<T> Traits;
MOZ_ASSERT(IsNaN(num.fp())); MOZ_ASSERT(IsNaN(num.fp()));

View file

@ -33,33 +33,38 @@ namespace mozilla {
* compiler bustage, particularly PGO-specific bustage. * compiler bustage, particularly PGO-specific bustage.
*/ */
struct FloatTypeTraits namespace detail {
/*
* These implementations assume float/double are 32/64-bit single/double
* format number types compatible with the IEEE-754 standard. C++ doesn't
* require this, but we required it in implementations of these algorithms that
* preceded this header, so we shouldn't break anything to continue doing so.
*/
template<typename T>
struct FloatingPointTrait;
template<>
struct FloatingPointTrait<float>
{ {
protected:
typedef uint32_t Bits; typedef uint32_t Bits;
static const unsigned kExponentBias = 127; static constexpr unsigned kExponentWidth = 8;
static const unsigned kExponentShift = 23; static constexpr unsigned kSignificandWidth = 23;
static const Bits kSignBit = 0x80000000UL;
static const Bits kExponentBits = 0x7F800000UL;
static const Bits kSignificandBits = 0x007FFFFFUL;
}; };
struct DoubleTypeTraits template<>
struct FloatingPointTrait<double>
{ {
protected:
typedef uint64_t Bits; typedef uint64_t Bits;
static const unsigned kExponentBias = 1023; static constexpr unsigned kExponentWidth = 11;
static const unsigned kExponentShift = 52; static constexpr unsigned kSignificandWidth = 52;
static const Bits kSignBit = 0x8000000000000000ULL;
static const Bits kExponentBits = 0x7ff0000000000000ULL;
static const Bits kSignificandBits = 0x000fffffffffffffULL;
}; };
template<typename T> struct SelectTrait; } // namespace detail
template<> struct SelectTrait<float> : public FloatTypeTraits {};
template<> struct SelectTrait<double> : public DoubleTypeTraits {};
/* /*
* This struct contains details regarding the encoding of floating-point * This struct contains details regarding the encoding of floating-point
@ -88,30 +93,65 @@ template<> struct SelectTrait<double> : public DoubleTypeTraits {};
* http://en.wikipedia.org/wiki/Floating_point#IEEE_754:_floating_point_in_modern_computers * http://en.wikipedia.org/wiki/Floating_point#IEEE_754:_floating_point_in_modern_computers
*/ */
template<typename T> template<typename T>
struct FloatingPoint : public SelectTrait<T> struct FloatingPoint final : private detail::FloatingPointTrait<T>
{ {
typedef SelectTrait<T> Base; private:
typedef typename Base::Bits Bits; using Base = detail::FloatingPointTrait<T>;
static_assert((Base::kSignBit & Base::kExponentBits) == 0, public:
/**
* An unsigned integral type suitable for accessing the bitwise representation
* of T.
*/
using Bits = typename Base::Bits;
static_assert(sizeof(T) == sizeof(Bits), "Bits must be same size as T");
/** The bit-width of the exponent component of T. */
using Base::kExponentWidth;
/** The bit-width of the significand component of T. */
using Base::kSignificandWidth;
static_assert(1 + kExponentWidth + kSignificandWidth ==
CHAR_BIT * sizeof(T),
"sign bit plus bit widths should sum to overall bit width");
/**
* The exponent field in an IEEE-754 floating point number consists of bits
* encoding an unsigned number. The *actual* represented exponent (for all
* values finite and not denormal) is that value, minus a bias |kExponentBias|
* so that a useful range of numbers is represented.
*/
static constexpr unsigned kExponentBias = (1U << (kExponentWidth - 1)) - 1;
/**
* The amount by which the bits of the exponent-field in an IEEE-754 floating
* point number are shifted from the LSB of the floating point type.
*/
static constexpr unsigned kExponentShift = kSignificandWidth;
/** The sign bit in the floating point representation. */
static constexpr Bits kSignBit =
static_cast<Bits>(1) << (CHAR_BIT * sizeof(Bits) - 1);
/** The exponent bits in the floating point representation. */
static constexpr Bits kExponentBits =
((static_cast<Bits>(1) << kExponentWidth) - 1) << kSignificandWidth;
/** The significand bits in the floating point representation. */
static constexpr Bits kSignificandBits =
(static_cast<Bits>(1) << kSignificandWidth) - 1;
static_assert((kSignBit & kExponentBits) == 0,
"sign bit shouldn't overlap exponent bits"); "sign bit shouldn't overlap exponent bits");
static_assert((Base::kSignBit & Base::kSignificandBits) == 0, static_assert((kSignBit & kSignificandBits) == 0,
"sign bit shouldn't overlap significand bits"); "sign bit shouldn't overlap significand bits");
static_assert((Base::kExponentBits & Base::kSignificandBits) == 0, static_assert((kExponentBits & kSignificandBits) == 0,
"exponent bits shouldn't overlap significand bits"); "exponent bits shouldn't overlap significand bits");
static_assert((Base::kSignBit | Base::kExponentBits | Base::kSignificandBits) == static_assert((kSignBit | kExponentBits | kSignificandBits) == ~Bits(0),
~Bits(0),
"all bits accounted for"); "all bits accounted for");
/*
* These implementations assume float/double are 32/64-bit single/double
* format number types compatible with the IEEE-754 standard. C++ don't
* require this to be the case. But we required this in implementations of
* these algorithms that preceded this header, so we shouldn't break anything
* if we keep doing so.
*/
static_assert(sizeof(T) == sizeof(Bits), "Bits must be same size as T");
}; };
/** Determines whether a float/double is NaN. */ /** Determines whether a float/double is NaN. */