From f0cbdd3e352a1d45965be686f48eee51159bb218 Mon Sep 17 00:00:00 2001 From: Jay Foad Date: Mon, 22 Apr 2024 12:54:48 +0100 Subject: [PATCH] [KnownBitsTest] Print name of function when exhaustive tests fail (#89588) When exhaustive unary/binary tests fail, print the name of the function being tested as well as the values of the inputs and outputs. Example of a simulated failure in testing "udiv exact": unittests/Support/KnownBitsTest.cpp:99: Failure Value of: checkResult(Name, Exact, Computed, {Known1, Known2}, CheckOptimality) Actual: false (udiv exact: Inputs = ???1, ????, Computed = ???1, Exact = 0???) Expected: true --- llvm/unittests/Support/KnownBitsTest.cpp | 106 +++++++++++++++-------- 1 file changed, 68 insertions(+), 38 deletions(-) diff --git a/llvm/unittests/Support/KnownBitsTest.cpp b/llvm/unittests/Support/KnownBitsTest.cpp index 2fa650c2c3bf0e..b970137e63b715 100644 --- a/llvm/unittests/Support/KnownBitsTest.cpp +++ b/llvm/unittests/Support/KnownBitsTest.cpp @@ -10,9 +10,11 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/KnownBits.h" #include "KnownBitsTest.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" #include "gtest/gtest.h" using namespace llvm; @@ -25,7 +27,7 @@ using BinaryBitsFn = using BinaryIntFn = llvm::function_ref(const APInt &, const APInt &)>; -static testing::AssertionResult checkResult(const KnownBits &Exact, +static testing::AssertionResult checkResult(Twine Name, const KnownBits &Exact, const KnownBits &Computed, ArrayRef Inputs, bool CheckOptimality) { @@ -41,6 +43,7 @@ static testing::AssertionResult checkResult(const KnownBits &Exact, } testing::AssertionResult Result = testing::AssertionFailure(); + Result << Name << ": "; Result << "Inputs = "; for (const KnownBits &Input : Inputs) Result << Input << ", "; @@ -48,7 +51,8 @@ static testing::AssertionResult checkResult(const KnownBits &Exact, return Result; } -static void testUnaryOpExhaustive(UnaryBitsFn BitsFn, UnaryIntFn IntFn, +static void testUnaryOpExhaustive(StringRef Name, UnaryBitsFn BitsFn, + UnaryIntFn IntFn, bool CheckOptimality = true) { for (unsigned Bits : {1, 4}) { ForeachKnownBits(Bits, [&](const KnownBits &Known) { @@ -65,12 +69,13 @@ static void testUnaryOpExhaustive(UnaryBitsFn BitsFn, UnaryIntFn IntFn, }); EXPECT_TRUE(!Computed.hasConflict()); - EXPECT_TRUE(checkResult(Exact, Computed, Known, CheckOptimality)); + EXPECT_TRUE(checkResult(Name, Exact, Computed, Known, CheckOptimality)); }); } } -static void testBinaryOpExhaustive(BinaryBitsFn BitsFn, BinaryIntFn IntFn, +static void testBinaryOpExhaustive(StringRef Name, BinaryBitsFn BitsFn, + BinaryIntFn IntFn, bool CheckOptimality = true, bool RefinePoisonToZero = false) { for (unsigned Bits : {1, 4}) { @@ -91,8 +96,8 @@ static void testBinaryOpExhaustive(BinaryBitsFn BitsFn, BinaryIntFn IntFn, }); EXPECT_TRUE(!Computed.hasConflict()); - EXPECT_TRUE( - checkResult(Exact, Computed, {Known1, Known2}, CheckOptimality)); + EXPECT_TRUE(checkResult(Name, Exact, Computed, {Known1, Known2}, + CheckOptimality)); // In some cases we choose to return zero if the result is always // poison. if (RefinePoisonToZero && Exact.hasConflict()) { @@ -137,6 +142,7 @@ TEST(KnownBitsTest, AddCarryExhaustive) { } static void TestAddSubExhaustive(bool IsAdd) { + Twine Name = IsAdd ? "add" : "sub"; unsigned Bits = 4; ForeachKnownBits(Bits, [&](const KnownBits &Known1) { ForeachKnownBits(Bits, [&](const KnownBits &Known2) { @@ -186,23 +192,26 @@ static void TestAddSubExhaustive(bool IsAdd) { KnownBits KnownComputed = KnownBits::computeForAddSub( IsAdd, /*NSW=*/false, /*NUW=*/false, Known1, Known2); - EXPECT_TRUE(checkResult(Known, KnownComputed, {Known1, Known2}, + EXPECT_TRUE(checkResult(Name, Known, KnownComputed, {Known1, Known2}, /*CheckOptimality=*/true)); KnownBits KnownNSWComputed = KnownBits::computeForAddSub( IsAdd, /*NSW=*/true, /*NUW=*/false, Known1, Known2); - EXPECT_TRUE(checkResult(KnownNSW, KnownNSWComputed, {Known1, Known2}, + EXPECT_TRUE(checkResult(Name + " nsw", KnownNSW, KnownNSWComputed, + {Known1, Known2}, /*CheckOptimality=*/true)); KnownBits KnownNUWComputed = KnownBits::computeForAddSub( IsAdd, /*NSW=*/false, /*NUW=*/true, Known1, Known2); - EXPECT_TRUE(checkResult(KnownNUW, KnownNUWComputed, {Known1, Known2}, + EXPECT_TRUE(checkResult(Name + " nuw", KnownNUW, KnownNUWComputed, + {Known1, Known2}, /*CheckOptimality=*/true)); KnownBits KnownNSWAndNUWComputed = KnownBits::computeForAddSub( IsAdd, /*NSW=*/true, /*NUW=*/true, Known1, Known2); - EXPECT_TRUE(checkResult(KnownNSWAndNUW, KnownNSWAndNUWComputed, - {Known1, Known2}, /*CheckOptimality=*/true)); + EXPECT_TRUE(checkResult(Name + " nsw nuw", KnownNSWAndNUW, + KnownNSWAndNUWComputed, {Known1, Known2}, + /*CheckOptimality=*/true)); }); }); } @@ -267,27 +276,31 @@ TEST(KnownBitsTest, SignBitUnknown) { TEST(KnownBitsTest, BinaryExhaustive) { testBinaryOpExhaustive( + "and", [](const KnownBits &Known1, const KnownBits &Known2) { return Known1 & Known2; }, [](const APInt &N1, const APInt &N2) { return N1 & N2; }); testBinaryOpExhaustive( + "or", [](const KnownBits &Known1, const KnownBits &Known2) { return Known1 | Known2; }, [](const APInt &N1, const APInt &N2) { return N1 | N2; }); testBinaryOpExhaustive( + "xor", [](const KnownBits &Known1, const KnownBits &Known2) { return Known1 ^ Known2; }, [](const APInt &N1, const APInt &N2) { return N1 ^ N2; }); - testBinaryOpExhaustive(KnownBits::umax, APIntOps::umax); - testBinaryOpExhaustive(KnownBits::umin, APIntOps::umin); - testBinaryOpExhaustive(KnownBits::smax, APIntOps::smax); - testBinaryOpExhaustive(KnownBits::smin, APIntOps::smin); - testBinaryOpExhaustive(KnownBits::abdu, APIntOps::abdu); - testBinaryOpExhaustive(KnownBits::abds, APIntOps::abds); + testBinaryOpExhaustive("umax", KnownBits::umax, APIntOps::umax); + testBinaryOpExhaustive("umin", KnownBits::umin, APIntOps::umin); + testBinaryOpExhaustive("smax", KnownBits::smax, APIntOps::smax); + testBinaryOpExhaustive("smin", KnownBits::smin, APIntOps::smin); + testBinaryOpExhaustive("abdu", KnownBits::abdu, APIntOps::abdu); + testBinaryOpExhaustive("abds", KnownBits::abds, APIntOps::abds); testBinaryOpExhaustive( + "udiv", [](const KnownBits &Known1, const KnownBits &Known2) { return KnownBits::udiv(Known1, Known2); }, @@ -298,6 +311,7 @@ TEST(KnownBitsTest, BinaryExhaustive) { }, /*CheckOptimality=*/false); testBinaryOpExhaustive( + "udiv exact", [](const KnownBits &Known1, const KnownBits &Known2) { return KnownBits::udiv(Known1, Known2, /*Exact*/ true); }, @@ -308,6 +322,7 @@ TEST(KnownBitsTest, BinaryExhaustive) { }, /*CheckOptimality=*/false); testBinaryOpExhaustive( + "sdiv", [](const KnownBits &Known1, const KnownBits &Known2) { return KnownBits::sdiv(Known1, Known2); }, @@ -318,6 +333,7 @@ TEST(KnownBitsTest, BinaryExhaustive) { }, /*CheckOptimality=*/false); testBinaryOpExhaustive( + "sdiv exact", [](const KnownBits &Known1, const KnownBits &Known2) { return KnownBits::sdiv(Known1, Known2, /*Exact*/ true); }, @@ -329,7 +345,7 @@ TEST(KnownBitsTest, BinaryExhaustive) { }, /*CheckOptimality=*/false); testBinaryOpExhaustive( - KnownBits::urem, + "urem", KnownBits::urem, [](const APInt &N1, const APInt &N2) -> std::optional { if (N2.isZero()) return std::nullopt; @@ -337,7 +353,7 @@ TEST(KnownBitsTest, BinaryExhaustive) { }, /*CheckOptimality=*/false); testBinaryOpExhaustive( - KnownBits::srem, + "srem", KnownBits::srem, [](const APInt &N1, const APInt &N2) -> std::optional { if (N2.isZero()) return std::nullopt; @@ -345,30 +361,31 @@ TEST(KnownBitsTest, BinaryExhaustive) { }, /*CheckOptimality=*/false); testBinaryOpExhaustive( - KnownBits::sadd_sat, + "sadd_sat", KnownBits::sadd_sat, [](const APInt &N1, const APInt &N2) -> std::optional { return N1.sadd_sat(N2); }, /*CheckOptimality=*/false); testBinaryOpExhaustive( - KnownBits::uadd_sat, + "uadd_sat", KnownBits::uadd_sat, [](const APInt &N1, const APInt &N2) -> std::optional { return N1.uadd_sat(N2); }, /*CheckOptimality=*/false); testBinaryOpExhaustive( - KnownBits::ssub_sat, + "ssub_sat", KnownBits::ssub_sat, [](const APInt &N1, const APInt &N2) -> std::optional { return N1.ssub_sat(N2); }, /*CheckOptimality=*/false); testBinaryOpExhaustive( - KnownBits::usub_sat, + "usub_sat", KnownBits::usub_sat, [](const APInt &N1, const APInt &N2) -> std::optional { return N1.usub_sat(N2); }, /*CheckOptimality=*/false); testBinaryOpExhaustive( + "shl", [](const KnownBits &Known1, const KnownBits &Known2) { return KnownBits::shl(Known1, Known2); }, @@ -379,6 +396,7 @@ TEST(KnownBitsTest, BinaryExhaustive) { }, /*CheckOptimality=*/true, /* RefinePoisonToZero */ true); testBinaryOpExhaustive( + "ushl_ov", [](const KnownBits &Known1, const KnownBits &Known2) { return KnownBits::shl(Known1, Known2, /* NUW */ true); }, @@ -391,6 +409,7 @@ TEST(KnownBitsTest, BinaryExhaustive) { }, /*CheckOptimality=*/true, /* RefinePoisonToZero */ true); testBinaryOpExhaustive( + "shl nsw", [](const KnownBits &Known1, const KnownBits &Known2) { return KnownBits::shl(Known1, Known2, /* NUW */ false, /* NSW */ true); }, @@ -403,6 +422,7 @@ TEST(KnownBitsTest, BinaryExhaustive) { }, /*CheckOptimality=*/true, /* RefinePoisonToZero */ true); testBinaryOpExhaustive( + "shl nuw", [](const KnownBits &Known1, const KnownBits &Known2) { return KnownBits::shl(Known1, Known2, /* NUW */ true, /* NSW */ true); }, @@ -417,6 +437,7 @@ TEST(KnownBitsTest, BinaryExhaustive) { /*CheckOptimality=*/true, /* RefinePoisonToZero */ true); testBinaryOpExhaustive( + "lshr", [](const KnownBits &Known1, const KnownBits &Known2) { return KnownBits::lshr(Known1, Known2); }, @@ -427,6 +448,7 @@ TEST(KnownBitsTest, BinaryExhaustive) { }, /*CheckOptimality=*/true, /* RefinePoisonToZero */ true); testBinaryOpExhaustive( + "lshr exact", [](const KnownBits &Known1, const KnownBits &Known2) { return KnownBits::lshr(Known1, Known2, /*ShAmtNonZero=*/false, /*Exact=*/true); @@ -440,6 +462,7 @@ TEST(KnownBitsTest, BinaryExhaustive) { }, /*CheckOptimality=*/true, /* RefinePoisonToZero */ true); testBinaryOpExhaustive( + "ashr", [](const KnownBits &Known1, const KnownBits &Known2) { return KnownBits::ashr(Known1, Known2); }, @@ -450,6 +473,7 @@ TEST(KnownBitsTest, BinaryExhaustive) { }, /*CheckOptimality=*/true, /* RefinePoisonToZero */ true); testBinaryOpExhaustive( + "ashr exact", [](const KnownBits &Known1, const KnownBits &Known2) { return KnownBits::ashr(Known1, Known2, /*ShAmtNonZero=*/false, /*Exact=*/true); @@ -463,38 +487,44 @@ TEST(KnownBitsTest, BinaryExhaustive) { }, /*CheckOptimality=*/true, /* RefinePoisonToZero */ true); testBinaryOpExhaustive( + "mul", [](const KnownBits &Known1, const KnownBits &Known2) { return KnownBits::mul(Known1, Known2); }, [](const APInt &N1, const APInt &N2) { return N1 * N2; }, /*CheckOptimality=*/false); testBinaryOpExhaustive( - KnownBits::mulhs, + "mulhs", KnownBits::mulhs, [](const APInt &N1, const APInt &N2) { return APIntOps::mulhs(N1, N2); }, /*CheckOptimality=*/false); testBinaryOpExhaustive( - KnownBits::mulhu, + "mulhu", KnownBits::mulhu, [](const APInt &N1, const APInt &N2) { return APIntOps::mulhu(N1, N2); }, /*CheckOptimality=*/false); } TEST(KnownBitsTest, UnaryExhaustive) { - testUnaryOpExhaustive([](const KnownBits &Known) { return Known.abs(); }, - [](const APInt &N) { return N.abs(); }); + testUnaryOpExhaustive( + "abs", [](const KnownBits &Known) { return Known.abs(); }, + [](const APInt &N) { return N.abs(); }); - testUnaryOpExhaustive([](const KnownBits &Known) { return Known.abs(true); }, - [](const APInt &N) -> std::optional { - if (N.isMinSignedValue()) - return std::nullopt; - return N.abs(); - }); + testUnaryOpExhaustive( + "abs(true)", [](const KnownBits &Known) { return Known.abs(true); }, + [](const APInt &N) -> std::optional { + if (N.isMinSignedValue()) + return std::nullopt; + return N.abs(); + }); - testUnaryOpExhaustive([](const KnownBits &Known) { return Known.blsi(); }, - [](const APInt &N) { return N & -N; }); - testUnaryOpExhaustive([](const KnownBits &Known) { return Known.blsmsk(); }, - [](const APInt &N) { return N ^ (N - 1); }); + testUnaryOpExhaustive( + "blsi", [](const KnownBits &Known) { return Known.blsi(); }, + [](const APInt &N) { return N & -N; }); + testUnaryOpExhaustive( + "blsmsk", [](const KnownBits &Known) { return Known.blsmsk(); }, + [](const APInt &N) { return N ^ (N - 1); }); testUnaryOpExhaustive( + "mul self", [](const KnownBits &Known) { return KnownBits::mul(Known, Known, /*SelfMultiply*/ true); },