tint: Have Number equality consider sign
Sign is important for equality when it comes to backend generation of floating point numbers. Change-Id: I1e2610fe9bae98a5c5f756a55385e092919b5aa3 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/95080 Commit-Queue: Ben Clayton <bclayton@chromium.org> Reviewed-by: Dan Sinclair <dsinclair@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
4287a53bf7
commit
cf52af7b0f
|
@ -16,6 +16,7 @@
|
|||
#define SRC_TINT_NUMBER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
@ -135,61 +136,6 @@ inline std::ostream& operator<<(std::ostream& out, Number<T> num) {
|
|||
return out << num.value;
|
||||
}
|
||||
|
||||
/// Equality operator.
|
||||
/// @param a the LHS number
|
||||
/// @param b the RHS number
|
||||
/// @returns true if the numbers `a` and `b` are exactly equal.
|
||||
template <typename A, typename B>
|
||||
bool operator==(Number<A> a, Number<B> b) {
|
||||
using T = decltype(a.value + b.value);
|
||||
return std::equal_to<T>()(static_cast<T>(a.value), static_cast<T>(b.value));
|
||||
}
|
||||
|
||||
/// Inequality operator.
|
||||
/// @param a the LHS number
|
||||
/// @param b the RHS number
|
||||
/// @returns true if the numbers `a` and `b` are exactly unequal.
|
||||
template <typename A, typename B>
|
||||
bool operator!=(Number<A> a, Number<B> b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
/// Equality operator.
|
||||
/// @param a the LHS number
|
||||
/// @param b the RHS number
|
||||
/// @returns true if the numbers `a` and `b` are exactly equal.
|
||||
template <typename A, typename B>
|
||||
std::enable_if_t<IsNumeric<B>, bool> operator==(Number<A> a, B b) {
|
||||
return a == Number<B>(b);
|
||||
}
|
||||
|
||||
/// Inequality operator.
|
||||
/// @param a the LHS number
|
||||
/// @param b the RHS number
|
||||
/// @returns true if the numbers `a` and `b` are exactly unequal.
|
||||
template <typename A, typename B>
|
||||
std::enable_if_t<IsNumeric<B>, bool> operator!=(Number<A> a, B b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
/// Equality operator.
|
||||
/// @param a the LHS number
|
||||
/// @param b the RHS number
|
||||
/// @returns true if the numbers `a` and `b` are exactly equal.
|
||||
template <typename A, typename B>
|
||||
std::enable_if_t<IsNumeric<A>, bool> operator==(A a, Number<B> b) {
|
||||
return Number<A>(a) == b;
|
||||
}
|
||||
|
||||
/// Inequality operator.
|
||||
/// @param a the LHS number
|
||||
/// @param b the RHS number
|
||||
/// @returns true if the numbers `a` and `b` are exactly unequal.
|
||||
template <typename A, typename B>
|
||||
std::enable_if_t<IsNumeric<A>, bool> operator!=(A a, Number<B> b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
/// The partial specification of Number for f16 type, storing the f16 value as float,
|
||||
/// and enforcing proper explicit casting.
|
||||
template <>
|
||||
|
@ -295,6 +241,70 @@ utils::Result<TO, ConversionFailure> CheckedConvert(Number<FROM> num) {
|
|||
return TO(value); // Success
|
||||
}
|
||||
|
||||
/// Equality operator.
|
||||
/// @param a the LHS number
|
||||
/// @param b the RHS number
|
||||
/// @returns true if the numbers `a` and `b` are exactly equal. Also considers sign bit.
|
||||
template <typename A, typename B>
|
||||
bool operator==(Number<A> a, Number<B> b) {
|
||||
// Use the highest-precision integer or floating-point type to perform the comparisons.
|
||||
using T =
|
||||
std::conditional_t<IsFloatingPoint<A> || IsFloatingPoint<B>, AFloat::type, AInt::type>;
|
||||
auto va = static_cast<T>(a.value);
|
||||
auto vb = static_cast<T>(b.value);
|
||||
if constexpr (IsFloatingPoint<T>) {
|
||||
if (std::signbit(va) != std::signbit(vb)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return std::equal_to<T>()(va, vb);
|
||||
}
|
||||
|
||||
/// Inequality operator.
|
||||
/// @param a the LHS number
|
||||
/// @param b the RHS number
|
||||
/// @returns true if the numbers `a` and `b` are exactly unequal. Also considers sign bit.
|
||||
template <typename A, typename B>
|
||||
bool operator!=(Number<A> a, Number<B> b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
/// Equality operator.
|
||||
/// @param a the LHS number
|
||||
/// @param b the RHS number
|
||||
/// @returns true if the numbers `a` and `b` are exactly equal.
|
||||
template <typename A, typename B>
|
||||
std::enable_if_t<IsNumeric<B>, bool> operator==(Number<A> a, B b) {
|
||||
return a == Number<B>(b);
|
||||
}
|
||||
|
||||
/// Inequality operator.
|
||||
/// @param a the LHS number
|
||||
/// @param b the RHS number
|
||||
/// @returns true if the numbers `a` and `b` are exactly unequal.
|
||||
template <typename A, typename B>
|
||||
std::enable_if_t<IsNumeric<B>, bool> operator!=(Number<A> a, B b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
/// Equality operator.
|
||||
/// @param a the LHS number
|
||||
/// @param b the RHS number
|
||||
/// @returns true if the numbers `a` and `b` are exactly equal.
|
||||
template <typename A, typename B>
|
||||
std::enable_if_t<IsNumeric<A>, bool> operator==(A a, Number<B> b) {
|
||||
return Number<A>(a) == b;
|
||||
}
|
||||
|
||||
/// Inequality operator.
|
||||
/// @param a the LHS number
|
||||
/// @param b the RHS number
|
||||
/// @returns true if the numbers `a` and `b` are exactly unequal.
|
||||
template <typename A, typename B>
|
||||
std::enable_if_t<IsNumeric<A>, bool> operator!=(A a, Number<B> b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
/// Define 'TINT_HAS_OVERFLOW_BUILTINS' if the compiler provide overflow checking builtins.
|
||||
/// If the compiler does not support these builtins, then these are emulated with algorithms
|
||||
/// described in:
|
||||
|
|
|
@ -65,6 +65,79 @@ constexpr double kLowestF16NextULP = -kHighestF16NextULP;
|
|||
// warning.
|
||||
TINT_BEGIN_DISABLE_WARNING(CONSTANT_OVERFLOW);
|
||||
|
||||
TEST(NumberTest, Equality) {
|
||||
EXPECT_TRUE(0_a == 0_a);
|
||||
EXPECT_TRUE(10_a == 10_a);
|
||||
EXPECT_TRUE(-10_a == -10_a);
|
||||
|
||||
EXPECT_TRUE(0_i == 0_i);
|
||||
EXPECT_TRUE(10_i == 10_i);
|
||||
EXPECT_TRUE(-10_i == -10_i);
|
||||
|
||||
EXPECT_TRUE(0_u == 0_u);
|
||||
EXPECT_TRUE(10_u == 10_u);
|
||||
|
||||
EXPECT_TRUE(0._a == 0._a);
|
||||
EXPECT_TRUE(-0._a == -0._a);
|
||||
EXPECT_TRUE(10._a == 10._a);
|
||||
EXPECT_TRUE(-10._a == -10._a);
|
||||
|
||||
EXPECT_TRUE(0_f == 0_f);
|
||||
EXPECT_TRUE(-0_f == -0_f);
|
||||
EXPECT_TRUE(10_f == 10_f);
|
||||
EXPECT_TRUE(-10_f == -10_f);
|
||||
|
||||
EXPECT_TRUE(0_h == 0_h);
|
||||
EXPECT_TRUE(-0_h == -0_h);
|
||||
EXPECT_TRUE(10_h == 10_h);
|
||||
EXPECT_TRUE(-10_h == -10_h);
|
||||
}
|
||||
|
||||
TEST(NumberTest, Inequality) {
|
||||
EXPECT_TRUE(0_a != 1_a);
|
||||
EXPECT_TRUE(10_a != 11_a);
|
||||
EXPECT_TRUE(11_a != 10_a);
|
||||
EXPECT_TRUE(-10_a != -11_a);
|
||||
EXPECT_TRUE(-11_a != -10_a);
|
||||
|
||||
EXPECT_TRUE(0_i != 1_i);
|
||||
EXPECT_TRUE(1_i != 0_i);
|
||||
EXPECT_TRUE(10_i != 11_i);
|
||||
EXPECT_TRUE(11_i != 10_i);
|
||||
EXPECT_TRUE(-10_i != -11_i);
|
||||
EXPECT_TRUE(-11_i != -10_i);
|
||||
|
||||
EXPECT_TRUE(0_u != 1_u);
|
||||
EXPECT_TRUE(1_u != 0_u);
|
||||
EXPECT_TRUE(10_u != 11_u);
|
||||
EXPECT_TRUE(11_u != 10_u);
|
||||
|
||||
EXPECT_TRUE(0._a != -0._a);
|
||||
EXPECT_TRUE(-0._a != 0._a);
|
||||
EXPECT_TRUE(10._a != 11._a);
|
||||
EXPECT_TRUE(11._a != 10._a);
|
||||
EXPECT_TRUE(-10._a != -11._a);
|
||||
EXPECT_TRUE(-11._a != -10._a);
|
||||
|
||||
EXPECT_TRUE(0_f != -0_f);
|
||||
EXPECT_TRUE(-0_f != 0_f);
|
||||
EXPECT_TRUE(-0_f != -1_f);
|
||||
EXPECT_TRUE(-1_f != -0_f);
|
||||
EXPECT_TRUE(10_f != -10_f);
|
||||
EXPECT_TRUE(-10_f != 10_f);
|
||||
EXPECT_TRUE(10_f != 11_f);
|
||||
EXPECT_TRUE(-10_f != -11_f);
|
||||
|
||||
EXPECT_TRUE(0_h != -0_h);
|
||||
EXPECT_TRUE(-0_h != 0_h);
|
||||
EXPECT_TRUE(-0_h != -1_h);
|
||||
EXPECT_TRUE(-1_h != -0_h);
|
||||
EXPECT_TRUE(10_h != -10_h);
|
||||
EXPECT_TRUE(-10_h != 10_h);
|
||||
EXPECT_TRUE(10_h != 11_h);
|
||||
EXPECT_TRUE(-10_h != -11_h);
|
||||
}
|
||||
|
||||
TEST(NumberTest, CheckedConvertIdentity) {
|
||||
EXPECT_EQ(CheckedConvert<AInt>(0_a), 0_a);
|
||||
EXPECT_EQ(CheckedConvert<AFloat>(0_a), 0.0_a);
|
||||
|
@ -211,7 +284,7 @@ TEST(NumberTest, QuantizeF16) {
|
|||
EXPECT_EQ(f16(lowestNegativeSubnormalF16PlusULP), -0x0.ff8p-14);
|
||||
EXPECT_EQ(f16(highestNegativeSubnormalF16MinusULP), highestNegativeSubnormalF16);
|
||||
EXPECT_EQ(f16(highestNegativeSubnormalF16), highestNegativeSubnormalF16);
|
||||
EXPECT_EQ(f16(highestNegativeSubnormalF16PlusULP), 0.0);
|
||||
EXPECT_EQ(f16(highestNegativeSubnormalF16PlusULP), -0.0);
|
||||
// Test the mantissa discarding.
|
||||
EXPECT_EQ(f16(-0x0.064p-14), -0x0.064p-14);
|
||||
EXPECT_EQ(f16(-0x0.067fecp-14), -0x0.064p-14);
|
||||
|
|
Loading…
Reference in New Issue