Bug 1910421: Support float16 in mozilla::FloatingPoint. r=jandem

Fixes the conversion in `mozilla::FloatingPoint` so we can add the specialisation
`mozilla::detail::FloatingPointTrait<js::float16>`.

And then update "TypedArrayObject.cpp" to directly use `mozilla::FloatingPoint`.

Differential Revision: https://phabricator.services.mozilla.com/D217981
This commit is contained in:
André Bargull 2024-08-01 06:02:40 +00:00
parent 2583eedbbc
commit c672727397
3 changed files with 34 additions and 28 deletions

View File

@ -7,6 +7,8 @@
#ifndef vm_Float16_h
#define vm_Float16_h
#include "mozilla/FloatingPoint.h"
#include <cstdint>
#include <cstring>
#include <limits>
@ -299,4 +301,13 @@ class std::numeric_limits<js::float16> {
}
};
template <>
struct mozilla::detail::FloatingPointTrait<js::float16> {
protected:
using Bits = uint16_t;
static constexpr unsigned kExponentWidth = 5;
static constexpr unsigned kSignificandWidth = 10;
};
#endif // vm_Float16_h

View File

@ -3904,22 +3904,6 @@ bool js::DefineTypedArrayElement(JSContext* cx, Handle<TypedArrayObject*> obj,
return result.succeed();
}
template <typename T>
struct FloatingPoint {
using Bits = typename mozilla::FloatingPoint<T>::Bits;
static constexpr Bits kSignBit = mozilla::FloatingPoint<T>::kSignBit;
static constexpr Bits NegativeInfinity =
kSignBit | mozilla::FloatingPoint<T>::kExponentBits;
};
template <>
struct FloatingPoint<js::float16> {
using Bits = uint16_t;
static constexpr Bits kSignBit = 0x8000;
static constexpr Bits PositiveInfinity = 0x7C00;
static constexpr Bits NegativeInfinity = kSignBit | PositiveInfinity;
};
template <typename T, typename U>
static constexpr typename std::enable_if_t<
std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, U>
@ -3941,14 +3925,15 @@ static constexpr
UnsignedSortValue(UnsignedT val) {
// Flip sign bit for positive numbers; flip all bits for negative numbers,
// except negative NaNs.
using FloatingPoint = ::FloatingPoint<T>;
using FloatingPoint = mozilla::FloatingPoint<T>;
static_assert(std::is_same_v<typename FloatingPoint::Bits, UnsignedT>,
"FloatingPoint::Bits matches the unsigned int representation");
// FF80'0000 is negative infinity, (FF80'0000, FFFF'FFFF] are all NaNs with
// the sign-bit set (and the equivalent holds for double and float16 values).
// So any value larger than negative infinity is a negative NaN.
if (val > FloatingPoint::NegativeInfinity) {
constexpr UnsignedT NegativeInfinity = mozilla::InfinityBits<T, 1>::value;
if (val > NegativeInfinity) {
return val;
}
if (val & FloatingPoint::kSignBit) {
@ -3990,21 +3975,26 @@ static constexpr
template <typename T, typename U>
static constexpr typename std::enable_if_t<std::is_same_v<T, js::float16>, U>
ToCountingSortKey(U val) {
using FloatingPoint = ::FloatingPoint<T>;
using FloatingPoint = mozilla::FloatingPoint<T>;
static_assert(std::is_same_v<typename FloatingPoint::Bits, U>,
"FloatingPoint::Bits matches the unsigned int representation");
constexpr U PositiveInfinity = mozilla::InfinityBits<T, 0>::value;
constexpr U NegativeInfinity = mozilla::InfinityBits<T, 1>::value;
// Any value larger than negative infinity is a negative NaN. Place those at
// the very end.
if (val > FloatingPoint::NegativeInfinity) {
if (val > NegativeInfinity) {
return val;
}
// Map negative values, starting at negative infinity which is mapped to zero.
if (val & FloatingPoint::kSignBit) {
return FloatingPoint::NegativeInfinity - val;
return NegativeInfinity - val;
}
// Map positive values right after the last negative value (negative zero).
return val + (FloatingPoint::PositiveInfinity + 1);
return val + (PositiveInfinity + 1);
}
/**
@ -4013,20 +4003,25 @@ ToCountingSortKey(U val) {
template <typename T, typename U>
static constexpr typename std::enable_if_t<std::is_same_v<T, js::float16>, U>
FromCountingSortKey(U val) {
using FloatingPoint = ::FloatingPoint<T>;
using FloatingPoint = mozilla::FloatingPoint<T>;
static_assert(std::is_same_v<typename FloatingPoint::Bits, U>,
"FloatingPoint::Bits matches the unsigned int representation");
constexpr U PositiveInfinity = mozilla::InfinityBits<T, 0>::value;
constexpr U NegativeInfinity = mozilla::InfinityBits<T, 1>::value;
// Negative NaN are unchanged.
if (val > FloatingPoint::NegativeInfinity) {
if (val > NegativeInfinity) {
return val;
}
// Any value larger than 0x7C00 was a positive number, including positive NaN.
if (val > FloatingPoint::PositiveInfinity) {
return val - (FloatingPoint::PositiveInfinity + 1);
if (val > PositiveInfinity) {
return val - (PositiveInfinity + 1);
}
// Any other value was a negative number, excluding negative NaN.
return FloatingPoint::NegativeInfinity - val;
return NegativeInfinity - val;
}
template <typename T>

View File

@ -151,7 +151,7 @@ struct FloatingPoint final : private detail::FloatingPointTrait<T> {
static_assert((kExponentBits & kSignificandBits) == 0,
"exponent bits shouldn't overlap significand bits");
static_assert((kSignBit | kExponentBits | kSignificandBits) == ~Bits(0),
static_assert((kSignBit | kExponentBits | kSignificandBits) == Bits(~0),
"all bits accounted for");
};