Skip to content

[KnownBitsTest] Print name of function when exhaustive tests fail #89588

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 22, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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