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;