From 609ce6de8d005fc554a314e2a8251a764b893ad9 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Wed, 1 Jun 2022 15:35:50 +0000 Subject: [PATCH] tint/sem: Consider sign bit for Constant helpers. Constant::AnyZero(), Constant::AllZero() now consider -0.0 as non-zero, as this is different from WGSL's zero-initializer value for floating point numbers. Also consider FP sign for Constant::AllEqual(). Bug: tint:1504 Change-Id: I00503880ee29bd741b94cc98909a8a823e32522a Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/92243 Commit-Queue: Ben Clayton Kokoro: Kokoro Reviewed-by: James Price --- src/tint/sem/constant.cc | 19 +++++++++-- src/tint/sem/constant.h | 6 ++-- src/tint/sem/constant_test.cc | 61 +++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 6 deletions(-) diff --git a/src/tint/sem/constant.cc b/src/tint/sem/constant.cc index a2cfe8fa75..80869920cc 100644 --- a/src/tint/sem/constant.cc +++ b/src/tint/sem/constant.cc @@ -14,6 +14,7 @@ #include "src/tint/sem/constant.h" +#include #include #include "src/tint/debug.h" @@ -26,6 +27,17 @@ namespace { size_t CountElements(const Constant::Elements& elements) { return std::visit([](auto&& vec) { return vec.size(); }, elements); } + +template +bool IsNegativeFloat(T value) { + (void)value; + if constexpr (IsFloatingPoint) { + return std::signbit(value); + } else { + return false; + } +} + } // namespace Constant::Constant() {} @@ -47,7 +59,7 @@ bool Constant::AnyZero() const { return WithElements([&](auto&& vec) { using T = typename std::decay_t::value_type; for (auto el : vec) { - if (el == T(0)) { + if (el == T(0) && !IsNegativeFloat(el.value)) { return true; } } @@ -59,7 +71,7 @@ bool Constant::AllZero() const { return WithElements([&](auto&& vec) { using T = typename std::decay_t::value_type; for (auto el : vec) { - if (el != T(0)) { + if (el != T(0) || IsNegativeFloat(el.value)) { return false; } } @@ -71,8 +83,9 @@ bool Constant::AllEqual(size_t start, size_t end) const { return WithElements([&](auto&& vec) { if (!vec.empty()) { auto value = vec[start]; + bool float_sign = IsNegativeFloat(vec[start].value); for (size_t i = start + 1; i < end; i++) { - if (vec[i] != value) { + if (vec[i] != value || float_sign != IsNegativeFloat(vec[i].value)) { return false; } } diff --git a/src/tint/sem/constant.h b/src/tint/sem/constant.h index c99b97920e..4b0b0b927d 100644 --- a/src/tint/sem/constant.h +++ b/src/tint/sem/constant.h @@ -129,13 +129,13 @@ class Constant { /// @returns the elements as a vector of AFloat inline const AFloats& FElements() const { return std::get(elems_); } - /// @returns true if any element is zero + /// @returns true if any element is positive zero bool AnyZero() const; - /// @returns true if all elements are zero + /// @returns true if all elements are positive zero bool AllZero() const; - /// @returns true if all elements are the same value + /// @returns true if all elements are the same value, with the same sign-bit. bool AllEqual() const { return AllEqual(0, ElementCount()); } /// @param start the first element index diff --git a/src/tint/sem/constant_test.cc b/src/tint/sem/constant_test.cc index 6ad3cd6491..c334827501 100644 --- a/src/tint/sem/constant_test.cc +++ b/src/tint/sem/constant_test.cc @@ -202,6 +202,20 @@ TEST_F(ConstantTest, AnyZero) { EXPECT_EQ(Constant(vec3_ai, {1_a, 0_a, 3_a}).AnyZero(), true); EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 0_a}).AnyZero(), true); EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 0_a}).AnyZero(), true); + + auto* vec3_af = create(create(), 3u); + EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AnyZero(), false); + EXPECT_EQ(Constant(vec3_af, {0._a, 2._a, 3._a}).AnyZero(), true); + EXPECT_EQ(Constant(vec3_af, {1._a, 0._a, 3._a}).AnyZero(), true); + EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 0._a}).AnyZero(), true); + EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 0._a}).AnyZero(), true); + + EXPECT_EQ(Constant(vec3_af, {1._a, -2._a, 3._a}).AnyZero(), false); + EXPECT_EQ(Constant(vec3_af, {0._a, -2._a, 3._a}).AnyZero(), true); + EXPECT_EQ(Constant(vec3_af, {1._a, -0._a, 3._a}).AnyZero(), false); + EXPECT_EQ(Constant(vec3_af, {1._a, -2._a, 0._a}).AnyZero(), true); + EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 0._a}).AnyZero(), true); + EXPECT_EQ(Constant(vec3_af, {-0._a, -0._a, -0._a}).AnyZero(), false); } TEST_F(ConstantTest, AllZero) { @@ -211,6 +225,20 @@ TEST_F(ConstantTest, AllZero) { EXPECT_EQ(Constant(vec3_ai, {1_a, 0_a, 3_a}).AllZero(), false); EXPECT_EQ(Constant(vec3_ai, {1_a, 2_a, 0_a}).AllZero(), false); EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 0_a}).AllZero(), true); + + auto* vec3_af = create(create(), 3u); + EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AllZero(), false); + EXPECT_EQ(Constant(vec3_af, {0._a, 2._a, 3._a}).AllZero(), false); + EXPECT_EQ(Constant(vec3_af, {1._a, 0._a, 3._a}).AllZero(), false); + EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 0._a}).AllZero(), false); + EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 0._a}).AllZero(), true); + + EXPECT_EQ(Constant(vec3_af, {1._a, -2._a, 3._a}).AllZero(), false); + EXPECT_EQ(Constant(vec3_af, {0._a, -2._a, 3._a}).AllZero(), false); + EXPECT_EQ(Constant(vec3_af, {1._a, -0._a, 3._a}).AllZero(), false); + EXPECT_EQ(Constant(vec3_af, {1._a, -2._a, 0._a}).AllZero(), false); + EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 0._a}).AllZero(), false); + EXPECT_EQ(Constant(vec3_af, {-0._a, -0._a, -0._a}).AllZero(), false); } TEST_F(ConstantTest, AllEqual) { @@ -221,6 +249,17 @@ TEST_F(ConstantTest, AllEqual) { EXPECT_EQ(Constant(vec3_ai, {1_a, 1_a, 1_a}).AllEqual(), true); EXPECT_EQ(Constant(vec3_ai, {2_a, 2_a, 2_a}).AllEqual(), true); EXPECT_EQ(Constant(vec3_ai, {3_a, 3_a, 3_a}).AllEqual(), true); + EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 0_a}).AllEqual(), true); + + auto* vec3_af = create(create(), 3u); + EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AllEqual(), false); + EXPECT_EQ(Constant(vec3_af, {1._a, 1._a, 3._a}).AllEqual(), false); + EXPECT_EQ(Constant(vec3_af, {1._a, 3._a, 3._a}).AllEqual(), false); + EXPECT_EQ(Constant(vec3_af, {1._a, 1._a, 1._a}).AllEqual(), true); + EXPECT_EQ(Constant(vec3_af, {2._a, 2._a, 2._a}).AllEqual(), true); + EXPECT_EQ(Constant(vec3_af, {3._a, 3._a, 3._a}).AllEqual(), true); + EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 0._a}).AllEqual(), true); + EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 0._a}).AllEqual(), false); } TEST_F(ConstantTest, AllEqualRange) { @@ -231,6 +270,28 @@ TEST_F(ConstantTest, AllEqualRange) { EXPECT_EQ(Constant(vec3_ai, {1_a, 1_a, 1_a}).AllEqual(1, 3), true); EXPECT_EQ(Constant(vec3_ai, {2_a, 2_a, 2_a}).AllEqual(1, 3), true); EXPECT_EQ(Constant(vec3_ai, {2_a, 2_a, 3_a}).AllEqual(1, 3), false); + EXPECT_EQ(Constant(vec3_ai, {1_a, 0_a, 0_a}).AllEqual(1, 3), true); + EXPECT_EQ(Constant(vec3_ai, {0_a, 1_a, 0_a}).AllEqual(1, 3), false); + EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 1_a}).AllEqual(1, 3), false); + EXPECT_EQ(Constant(vec3_ai, {0_a, 0_a, 0_a}).AllEqual(1, 3), true); + + auto* vec3_af = create(create(), 3u); + EXPECT_EQ(Constant(vec3_af, {1._a, 2._a, 3._a}).AllEqual(1, 3), false); + EXPECT_EQ(Constant(vec3_af, {1._a, 1._a, 3._a}).AllEqual(1, 3), false); + EXPECT_EQ(Constant(vec3_af, {1._a, 3._a, 3._a}).AllEqual(1, 3), true); + EXPECT_EQ(Constant(vec3_af, {1._a, 1._a, 1._a}).AllEqual(1, 3), true); + EXPECT_EQ(Constant(vec3_af, {2._a, 2._a, 2._a}).AllEqual(1, 3), true); + EXPECT_EQ(Constant(vec3_af, {2._a, 2._a, 3._a}).AllEqual(1, 3), false); + EXPECT_EQ(Constant(vec3_af, {1._a, 0._a, 0._a}).AllEqual(1, 3), true); + EXPECT_EQ(Constant(vec3_af, {0._a, 1._a, 0._a}).AllEqual(1, 3), false); + EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 1._a}).AllEqual(1, 3), false); + EXPECT_EQ(Constant(vec3_af, {0._a, 0._a, 0._a}).AllEqual(1, 3), true); + EXPECT_EQ(Constant(vec3_af, {1._a, -0._a, 0._a}).AllEqual(1, 3), false); + EXPECT_EQ(Constant(vec3_af, {0._a, -1._a, 0._a}).AllEqual(1, 3), false); + EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 1._a}).AllEqual(1, 3), false); + EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, 0._a}).AllEqual(1, 3), false); + EXPECT_EQ(Constant(vec3_af, {0._a, -0._a, -0._a}).AllEqual(1, 3), true); + EXPECT_EQ(Constant(vec3_af, {-0._a, -0._a, -0._a}).AllEqual(1, 3), true); } } // namespace