From c8ec8e4eec1f1d63890ca86baa67800361c97bc0 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Sat, 28 May 2022 18:30:00 +0200 Subject: [PATCH 1/3] Introduce bit_cast_constexpr --- lib/fizzy/cxx20/bit.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/fizzy/cxx20/bit.hpp b/lib/fizzy/cxx20/bit.hpp index f88a56b48..069f5275e 100644 --- a/lib/fizzy/cxx20/bit.hpp +++ b/lib/fizzy/cxx20/bit.hpp @@ -20,6 +20,8 @@ namespace fizzy using std::bit_cast; } // namespace fizzy +#define bit_cast_constexpr constexpr + #else namespace fizzy @@ -41,6 +43,8 @@ template } } // namespace fizzy +#define bit_cast_constexpr + #endif /* __cpp_lib_bit_cast */ #ifdef __cpp_lib_bitops From 71d4b4ab6113e1191952e3453513038450c07a49 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Sat, 28 May 2022 18:30:06 +0200 Subject: [PATCH 2/3] Use bit_cast_constexpr --- lib/fizzy/execute.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/fizzy/execute.cpp b/lib/fizzy/execute.cpp index ef7d7d61e..4e2281ff1 100644 --- a/lib/fizzy/execute.cpp +++ b/lib/fizzy/execute.cpp @@ -336,12 +336,12 @@ inline constexpr T popcnt(T value) noexcept template T signbit(T value) noexcept = delete; -inline bool signbit(float value) noexcept +inline bit_cast_constexpr bool signbit(float value) noexcept { return (bit_cast(value) & F32SignMask) != 0; } -inline bool signbit(double value) noexcept +inline bit_cast_constexpr bool signbit(double value) noexcept { return (bit_cast(value) & F64SignMask) != 0; } @@ -350,13 +350,13 @@ template T fabs(T value) noexcept = delete; template <> -inline float fabs(float value) noexcept +inline bit_cast_constexpr float fabs(float value) noexcept { return bit_cast(bit_cast(value) & F32AbsMask); } template <> -inline double fabs(double value) noexcept +inline bit_cast_constexpr double fabs(double value) noexcept { return bit_cast(bit_cast(value) & F64AbsMask); } @@ -365,13 +365,13 @@ template T fneg(T value) noexcept = delete; template <> -inline float fneg(float value) noexcept +inline bit_cast_constexpr float fneg(float value) noexcept { return bit_cast(bit_cast(value) ^ F32SignMask); } template <> -inline double fneg(double value) noexcept +inline bit_cast_constexpr double fneg(double value) noexcept { return bit_cast(bit_cast(value) ^ F64SignMask); } @@ -380,7 +380,7 @@ template T copysign(T a, T b) noexcept = delete; template <> -inline float copysign(float a, float b) noexcept +inline bit_cast_constexpr float copysign(float a, float b) noexcept { const auto a_u = bit_cast(a); const auto b_u = bit_cast(b); @@ -388,7 +388,7 @@ inline float copysign(float a, float b) noexcept } template <> -inline double copysign(double a, double b) noexcept +inline bit_cast_constexpr double copysign(double a, double b) noexcept { const auto a_u = bit_cast(a); const auto b_u = bit_cast(b); From a5edb7c5eb1ea804e8c44efb1b8a22da85724ef9 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Sat, 28 May 2022 18:32:30 +0200 Subject: [PATCH 3/3] Introduce isnan helper --- lib/fizzy/execute.cpp | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/lib/fizzy/execute.cpp b/lib/fizzy/execute.cpp index 4e2281ff1..1d96c4a18 100644 --- a/lib/fizzy/execute.cpp +++ b/lib/fizzy/execute.cpp @@ -26,6 +26,10 @@ constexpr uint32_t F32AbsMask = 0x7fffffff; constexpr uint32_t F32SignMask = ~F32AbsMask; constexpr uint64_t F64AbsMask = 0x7fffffffffffffff; constexpr uint64_t F64SignMask = ~F64AbsMask; +constexpr uint32_t F32ExpMask = 0x7f800000; +constexpr uint32_t F32FracMask = 0x007fffff; +constexpr uint64_t F64ExpMask = 0x7ff0000000000000; +constexpr uint64_t F64FracMask = 0x000fffffffffffff; template inline T read(const uint8_t*& input) noexcept @@ -346,6 +350,21 @@ inline bit_cast_constexpr bool signbit(double value) noexcept return (bit_cast(value) & F64SignMask) != 0; } +template +T isnan(T value) noexcept = delete; + +inline bit_cast_constexpr bool isnan(float value) noexcept +{ + const auto v = bit_cast(value); + return ((v & F32ExpMask) == F32ExpMask) && ((v & F32FracMask) != 0); +} + +inline bit_cast_constexpr bool isnan(double value) noexcept +{ + const auto v = bit_cast(value); + return ((v & F64ExpMask) == F64ExpMask) && ((v & F64FracMask) != 0); +} + template T fabs(T value) noexcept = delete; @@ -399,7 +418,7 @@ template inline T fceil(T value) noexcept { static_assert(std::is_floating_point_v); - if (std::isnan(value)) + if (isnan(value)) return std::numeric_limits::quiet_NaN(); // Positive canonical NaN. // The FE_INEXACT error is ignored (whenever the implementation reports it at all). @@ -410,7 +429,7 @@ template inline T ffloor(T value) noexcept { static_assert(std::is_floating_point_v); - if (std::isnan(value)) + if (isnan(value)) return std::numeric_limits::quiet_NaN(); // Positive canonical NaN. // The FE_INEXACT error is ignored (whenever the implementation reports it at all). @@ -429,7 +448,7 @@ template inline T ftrunc(T value) noexcept { static_assert(std::is_floating_point_v); - if (std::isnan(value)) + if (isnan(value)) return std::numeric_limits::quiet_NaN(); // Positive canonical NaN. // The FE_INEXACT error is ignored (whenever the implementation reports it at all). @@ -441,7 +460,7 @@ T fnearest(T value) noexcept { static_assert(std::is_floating_point_v); - if (std::isnan(value)) + if (isnan(value)) return std::numeric_limits::quiet_NaN(); // Positive canonical NaN. // Check if the input integer (as floating-point type) is even. @@ -467,11 +486,11 @@ __attribute__((no_sanitize("float-divide-by-zero"))) inline constexpr T fdiv(T a } template -inline T fmin(T a, T b) noexcept +inline bit_cast_constexpr T fmin(T a, T b) noexcept { static_assert(std::is_floating_point_v); - if (std::isnan(a) || std::isnan(b)) + if (isnan(a) || isnan(b)) return std::numeric_limits::quiet_NaN(); // Positive canonical NaN. if (a == 0 && b == 0 && (signbit(a) || signbit(b))) @@ -481,11 +500,11 @@ inline T fmin(T a, T b) noexcept } template -inline T fmax(T a, T b) noexcept +inline bit_cast_constexpr T fmax(T a, T b) noexcept { static_assert(std::is_floating_point_v); - if (std::isnan(a) || std::isnan(b)) + if (isnan(a) || isnan(b)) return std::numeric_limits::quiet_NaN(); // Positive canonical NaN. if (a == 0 && b == 0 && (!signbit(a) || !signbit(b)))