Skip to content

Commit

Permalink
[KnownBitsTest] Print name of function when exhaustive tests fail (ll…
Browse files Browse the repository at this point in the history
…vm#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
  • Loading branch information
jayfoad authored Apr 22, 2024
1 parent c93f029 commit f0cbdd3
Showing 1 changed file with 68 additions and 38 deletions.
106 changes: 68 additions & 38 deletions llvm/unittests/Support/KnownBitsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -25,7 +27,7 @@ using BinaryBitsFn =
using BinaryIntFn =
llvm::function_ref<std::optional<APInt>(const APInt &, const APInt &)>;

static testing::AssertionResult checkResult(const KnownBits &Exact,
static testing::AssertionResult checkResult(Twine Name, const KnownBits &Exact,
const KnownBits &Computed,
ArrayRef<KnownBits> Inputs,
bool CheckOptimality) {
Expand All @@ -41,14 +43,16 @@ static testing::AssertionResult checkResult(const KnownBits &Exact,
}

testing::AssertionResult Result = testing::AssertionFailure();
Result << Name << ": ";
Result << "Inputs = ";
for (const KnownBits &Input : Inputs)
Result << Input << ", ";
Result << "Computed = " << Computed << ", Exact = " << 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) {
Expand All @@ -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}) {
Expand All @@ -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()) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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));
});
});
}
Expand Down Expand Up @@ -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);
},
Expand All @@ -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);
},
Expand All @@ -308,6 +322,7 @@ TEST(KnownBitsTest, BinaryExhaustive) {
},
/*CheckOptimality=*/false);
testBinaryOpExhaustive(
"sdiv",
[](const KnownBits &Known1, const KnownBits &Known2) {
return KnownBits::sdiv(Known1, Known2);
},
Expand All @@ -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);
},
Expand All @@ -329,46 +345,47 @@ TEST(KnownBitsTest, BinaryExhaustive) {
},
/*CheckOptimality=*/false);
testBinaryOpExhaustive(
KnownBits::urem,
"urem", KnownBits::urem,
[](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
if (N2.isZero())
return std::nullopt;
return N1.urem(N2);
},
/*CheckOptimality=*/false);
testBinaryOpExhaustive(
KnownBits::srem,
"srem", KnownBits::srem,
[](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
if (N2.isZero())
return std::nullopt;
return N1.srem(N2);
},
/*CheckOptimality=*/false);
testBinaryOpExhaustive(
KnownBits::sadd_sat,
"sadd_sat", KnownBits::sadd_sat,
[](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
return N1.sadd_sat(N2);
},
/*CheckOptimality=*/false);
testBinaryOpExhaustive(
KnownBits::uadd_sat,
"uadd_sat", KnownBits::uadd_sat,
[](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
return N1.uadd_sat(N2);
},
/*CheckOptimality=*/false);
testBinaryOpExhaustive(
KnownBits::ssub_sat,
"ssub_sat", KnownBits::ssub_sat,
[](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
return N1.ssub_sat(N2);
},
/*CheckOptimality=*/false);
testBinaryOpExhaustive(
KnownBits::usub_sat,
"usub_sat", KnownBits::usub_sat,
[](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
return N1.usub_sat(N2);
},
/*CheckOptimality=*/false);
testBinaryOpExhaustive(
"shl",
[](const KnownBits &Known1, const KnownBits &Known2) {
return KnownBits::shl(Known1, Known2);
},
Expand All @@ -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);
},
Expand All @@ -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);
},
Expand All @@ -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);
},
Expand All @@ -417,6 +437,7 @@ TEST(KnownBitsTest, BinaryExhaustive) {
/*CheckOptimality=*/true, /* RefinePoisonToZero */ true);

testBinaryOpExhaustive(
"lshr",
[](const KnownBits &Known1, const KnownBits &Known2) {
return KnownBits::lshr(Known1, Known2);
},
Expand All @@ -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);
Expand All @@ -440,6 +462,7 @@ TEST(KnownBitsTest, BinaryExhaustive) {
},
/*CheckOptimality=*/true, /* RefinePoisonToZero */ true);
testBinaryOpExhaustive(
"ashr",
[](const KnownBits &Known1, const KnownBits &Known2) {
return KnownBits::ashr(Known1, Known2);
},
Expand All @@ -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);
Expand All @@ -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<APInt> {
if (N.isMinSignedValue())
return std::nullopt;
return N.abs();
});
testUnaryOpExhaustive(
"abs(true)", [](const KnownBits &Known) { return Known.abs(true); },
[](const APInt &N) -> std::optional<APInt> {
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);
},
Expand Down

0 comments on commit f0cbdd3

Please sign in to comment.