From 1741f4443ecb11fdd80a4be550f171f9885a52fa Mon Sep 17 00:00:00 2001 From: Antonio Maiorano Date: Sat, 3 Sep 2022 21:31:23 +0000 Subject: [PATCH] tint: add CheckedDiv for abstract numbers Bug: tint:1581 Change-Id: Iafed168a916ac3a1062bcf53299e8ff17fc389fb Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/101041 Reviewed-by: Ben Clayton Kokoro: Kokoro Commit-Queue: Antonio Maiorano --- src/tint/number.h | 22 +++++++++++++++++ src/tint/number_test.cc | 54 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/src/tint/number.h b/src/tint/number.h index 032844c8ef..e96cfc7ba6 100644 --- a/src/tint/number.h +++ b/src/tint/number.h @@ -479,6 +479,28 @@ inline std::optional CheckedMul(AFloat a, AFloat b) { return AFloat{result}; } +/// @returns a / b, or an empty optional if the resulting value overflowed the AInt +inline std::optional CheckedDiv(AInt a, AInt b) { + if (b == 0) { + return {}; + } + + if (b == -1 && a == AInt::Lowest()) { + return {}; + } + + return AInt{a.value / b.value}; +} + +/// @returns a / b, or an empty optional if the resulting value overflowed the AFloat +inline std::optional CheckedDiv(AFloat a, AFloat b) { + auto result = a.value / b.value; + if (!std::isfinite(result)) { + return {}; + } + return AFloat{result}; +} + /// @returns a * b + c, or an empty optional if the value overflowed the AInt inline std::optional CheckedMadd(AInt a, AInt b, AInt c) { // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635 diff --git a/src/tint/number_test.cc b/src/tint/number_test.cc index 3182ad353b..15d96e700d 100644 --- a/src/tint/number_test.cc +++ b/src/tint/number_test.cc @@ -537,6 +537,60 @@ INSTANTIATE_TEST_SUITE_P( //////////////////////////////////////////////////////////////////////// })); +using CheckedDivTest_AInt = testing::TestWithParam; +TEST_P(CheckedDivTest_AInt, Test) { + auto expect = std::get<0>(GetParam()); + auto a = std::get<1>(GetParam()); + auto b = std::get<2>(GetParam()); + EXPECT_EQ(CheckedDiv(a, b), expect) << std::hex << "0x" << a << " - 0x" << b; +} +INSTANTIATE_TEST_SUITE_P( + CheckedDivTest_AInt, + CheckedDivTest_AInt, + testing::ValuesIn(std::vector{ + {AInt(0), AInt(0), AInt(1)}, + {AInt(1), AInt(1), AInt(1)}, + {AInt(1), AInt(1), AInt(1)}, + {AInt(2), AInt(2), AInt(1)}, + {AInt(2), AInt(4), AInt(2)}, + {AInt::Highest(), AInt::Highest(), AInt(1)}, + {AInt::Lowest(), AInt::Lowest(), AInt(1)}, + {AInt(1), AInt::Highest(), AInt::Highest()}, + {AInt(0), AInt(0), AInt::Highest()}, + {AInt(0), AInt(0), AInt::Lowest()}, + {OVERFLOW, AInt(123), AInt(0)}, + {OVERFLOW, AInt(-123), AInt(0)}, + //////////////////////////////////////////////////////////////////////// + })); + +using CheckedDivTest_AFloat = testing::TestWithParam; +TEST_P(CheckedDivTest_AFloat, Test) { + auto expect = std::get<0>(GetParam()); + auto a = std::get<1>(GetParam()); + auto b = std::get<2>(GetParam()); + EXPECT_EQ(CheckedDiv(a, b), expect) << std::hex << "0x" << a << " - 0x" << b; +} +INSTANTIATE_TEST_SUITE_P( + CheckedDivTest_AFloat, + CheckedDivTest_AFloat, + testing::ValuesIn(std::vector{ + {AFloat(0), AFloat(0), AFloat(1)}, + {AFloat(1), AFloat(1), AFloat(1)}, + {AFloat(1), AFloat(1), AFloat(1)}, + {AFloat(2), AFloat(2), AFloat(1)}, + {AFloat(2), AFloat(4), AFloat(2)}, + {AFloat::Highest(), AFloat::Highest(), AFloat(1)}, + {AFloat::Lowest(), AFloat::Lowest(), AFloat(1)}, + {AFloat(1), AFloat::Highest(), AFloat::Highest()}, + {AFloat(0), AFloat(0), AFloat::Highest()}, + {-AFloat(0), AFloat(0), AFloat::Lowest()}, + {OVERFLOW, AFloat(123), AFloat(0)}, + {OVERFLOW, AFloat(123), AFloat(-0)}, + {OVERFLOW, AFloat(-123), AFloat(0)}, + {OVERFLOW, AFloat(-123), AFloat(-0)}, + //////////////////////////////////////////////////////////////////////// + })); + using TernaryCheckedCase = std::tuple, AInt, AInt, AInt>; using CheckedMaddTest_AInt = testing::TestWithParam;