tint: Add CheckedSub functions

Bug: tint:1581
Change-Id: Iee836af4b5a1252335f680cba7ab4e04c2996728
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/99420
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
Antonio Maiorano 2022-08-17 12:46:39 +00:00 committed by Dawn LUCI CQ
parent 5ef011f2c3
commit f8a34d08dd
2 changed files with 95 additions and 1 deletions

View File

@ -350,7 +350,7 @@ inline std::optional<AInt> CheckedAdd(AInt a, AInt b) {
} }
#else // TINT_HAS_OVERFLOW_BUILTINS #else // TINT_HAS_OVERFLOW_BUILTINS
if (a.value >= 0) { if (a.value >= 0) {
if (AInt::kHighestValue - a.value < b.value) { if (b.value > AInt::kHighestValue - a.value) {
return {}; return {};
} }
} else { } else {
@ -372,6 +372,37 @@ inline std::optional<AFloat> CheckedAdd(AFloat a, AFloat b) {
return AFloat{result}; return AFloat{result};
} }
/// @returns a - b, or an empty optional if the resulting value overflowed the AInt
inline std::optional<AInt> CheckedSub(AInt a, AInt b) {
int64_t result;
#ifdef TINT_HAS_OVERFLOW_BUILTINS
if (__builtin_sub_overflow(a.value, b.value, &result)) {
return {};
}
#else // TINT_HAS_OVERFLOW_BUILTINS
if (b.value >= 0) {
if (a.value < AInt::kLowestValue + b.value) {
return {};
}
} else {
if (a.value > AInt::kHighestValue + b.value) {
return {};
}
}
result = a.value - b.value;
#endif // TINT_HAS_OVERFLOW_BUILTINS
return AInt(result);
}
/// @returns a + b, or an empty optional if the resulting value overflowed the AFloat
inline std::optional<AFloat> CheckedSub(AFloat a, AFloat b) {
auto result = a.value - b.value;
if (!std::isfinite(result)) {
return {};
}
return AFloat{result};
}
/// @returns a * b, or an empty optional if the resulting value overflowed the AInt /// @returns a * b, or an empty optional if the resulting value overflowed the AInt
inline std::optional<AInt> CheckedMul(AInt a, AInt b) { inline std::optional<AInt> CheckedMul(AInt a, AInt b) {
int64_t result; int64_t result;

View File

@ -356,7 +356,9 @@ INSTANTIATE_TEST_SUITE_P(
///////////////////////////////////// /////////////////////////////////////
})); }));
#ifdef OVERFLOW
#undef OVERFLOW // corecrt_math.h :( #undef OVERFLOW // corecrt_math.h :(
#endif
#define OVERFLOW \ #define OVERFLOW \
{} {}
@ -428,6 +430,67 @@ INSTANTIATE_TEST_SUITE_P(
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
})); }));
using CheckedSubTest_AInt = testing::TestWithParam<BinaryCheckedCase_AInt>;
TEST_P(CheckedSubTest_AInt, Test) {
auto expect = std::get<0>(GetParam());
auto a = std::get<1>(GetParam());
auto b = std::get<2>(GetParam());
EXPECT_EQ(CheckedSub(a, b), expect) << std::hex << "0x" << a << " - 0x" << b;
}
INSTANTIATE_TEST_SUITE_P(
CheckedSubTest_AInt,
CheckedSubTest_AInt,
testing::ValuesIn(std::vector<BinaryCheckedCase_AInt>{
{AInt(0), AInt(0), AInt(0)},
{AInt(1), AInt(1), AInt(0)},
{AInt(0), AInt(1), AInt(1)},
{AInt(-2), AInt(-1), AInt(1)},
{AInt(1), AInt(2), AInt(1)},
{AInt(-3), AInt(-2), AInt(1)},
{AInt(0x100), AInt(0x300), AInt(0x200)},
{AInt(-0x300), AInt(-0x100), AInt(0x200)},
{AInt::Highest(), AInt(AInt::kHighestValue - 1), AInt(-1)},
{AInt::Lowest(), AInt(AInt::kLowestValue + 1), AInt(1)},
{AInt(0x00000000ffffffffll), AInt::Highest(), AInt(0x7fffffff00000000ll)},
{AInt::Highest(), AInt::Highest(), AInt(0)},
{AInt::Lowest(), AInt::Lowest(), AInt(0)},
{OVERFLOW, AInt::Lowest(), AInt(1)},
{OVERFLOW, AInt::Highest(), AInt(-1)},
{OVERFLOW, AInt::Lowest(), AInt(2)},
{OVERFLOW, AInt::Highest(), AInt(-2)},
{OVERFLOW, AInt::Lowest(), AInt(10000)},
{OVERFLOW, AInt::Highest(), AInt(-10000)},
{OVERFLOW, AInt::Lowest(), AInt::Highest()},
////////////////////////////////////////////////////////////////////////
}));
using CheckedSubTest_AFloat = testing::TestWithParam<BinaryCheckedCase_AFloat>;
TEST_P(CheckedSubTest_AFloat, Test) {
auto expect = std::get<0>(GetParam());
auto a = std::get<1>(GetParam());
auto b = std::get<2>(GetParam());
EXPECT_EQ(CheckedSub(a, b), expect) << std::hex << "0x" << a << " - 0x" << b;
}
INSTANTIATE_TEST_SUITE_P(
CheckedSubTest_AFloat,
CheckedSubTest_AFloat,
testing::ValuesIn(std::vector<BinaryCheckedCase_AFloat>{
{AFloat(0), AFloat(0), AFloat(0)},
{AFloat(1), AFloat(1), AFloat(0)},
{AFloat(0), AFloat(1), AFloat(1)},
{AFloat(-2), AFloat(-1), AFloat(1)},
{AFloat(1), AFloat(2), AFloat(1)},
{AFloat(-3), AFloat(-2), AFloat(1)},
{AFloat(0x100), AFloat(0x300), AFloat(0x200)},
{AFloat(-0x300), AFloat(-0x100), AFloat(0x200)},
{AFloat::Highest(), AFloat(AFloat::kHighestValue - 1), AFloat(-1)},
{AFloat::Lowest(), AFloat(AFloat::kLowestValue + 1), AFloat(1)},
{AFloat::Highest(), AFloat::Highest(), AFloat(0)},
{AFloat::Lowest(), AFloat::Lowest(), AFloat(0)},
{OVERFLOW, AFloat::Lowest(), AFloat::Highest()},
////////////////////////////////////////////////////////////////////////
}));
using CheckedMulTest_AInt = testing::TestWithParam<BinaryCheckedCase_AInt>; using CheckedMulTest_AInt = testing::TestWithParam<BinaryCheckedCase_AInt>;
TEST_P(CheckedMulTest_AInt, Test) { TEST_P(CheckedMulTest_AInt, Test) {
auto expect = std::get<0>(GetParam()); auto expect = std::get<0>(GetParam());