Skip to content

Commit

Permalink
[ConstantFPRange][UnitTest] Ignore NaN payloads when enumerating valu…
Browse files Browse the repository at this point in the history
…es in a range (#111083)

NaN payloads can be ignored because they are unrelated with
ConstantFPRange (except the conversion from ConstantFPRange to
KnownBits). This patch just enumerates `+/-[S/Q]NaN` to avoid
enumerating 32 NaN values in all ranges which contain NaN values.
Addresses comment
#110082 (comment).
This patch reduces the execution time for unittests from 30.37s to
10.59s with an optimized build.
  • Loading branch information
dtcxzyw authored Oct 4, 2024
1 parent 67d247a commit 856774d
Showing 1 changed file with 85 additions and 24 deletions.
109 changes: 85 additions & 24 deletions llvm/unittests/IR/ConstantFPRangeTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,26 +150,80 @@ static void EnumerateTwoInterestingConstantFPRanges(Fn TestFn,

template <typename Fn>
static void EnumerateValuesInConstantFPRange(const ConstantFPRange &CR,
Fn TestFn) {
Fn TestFn, bool IgnoreNaNPayload) {
const fltSemantics &Sem = CR.getSemantics();
unsigned Bits = APFloat::semanticsSizeInBits(Sem);
assert(Bits < 32 && "Too many bits");
for (unsigned I = 0, E = (1U << Bits) - 1; I != E; ++I) {
APFloat V(Sem, APInt(Bits, I));
if (CR.contains(V))
TestFn(V);
if (IgnoreNaNPayload) {
if (CR.containsSNaN()) {
TestFn(APFloat::getSNaN(Sem, false));
TestFn(APFloat::getSNaN(Sem, true));
}
if (CR.containsQNaN()) {
TestFn(APFloat::getQNaN(Sem, false));
TestFn(APFloat::getQNaN(Sem, true));
}
if (CR.isNaNOnly())
return;
APFloat Lower = CR.getLower();
const APFloat &Upper = CR.getUpper();
auto Next = [&](APFloat &V) {
if (V.bitwiseIsEqual(Upper))
return false;
strictNext(V);
return true;
};
do
TestFn(Lower);
while (Next(Lower));
} else {
unsigned Bits = APFloat::semanticsSizeInBits(Sem);
assert(Bits < 32 && "Too many bits");
for (unsigned I = 0, E = (1U << Bits) - 1; I != E; ++I) {
APFloat V(Sem, APInt(Bits, I));
if (CR.contains(V))
TestFn(V);
}
}
}

template <typename Fn>
static bool AnyOfValueInConstantFPRange(const ConstantFPRange &CR, Fn TestFn) {
static bool AnyOfValueInConstantFPRange(const ConstantFPRange &CR, Fn TestFn,
bool IgnoreNaNPayload) {
const fltSemantics &Sem = CR.getSemantics();
unsigned Bits = APFloat::semanticsSizeInBits(Sem);
assert(Bits < 32 && "Too many bits");
for (unsigned I = 0, E = (1U << Bits) - 1; I != E; ++I) {
APFloat V(Sem, APInt(Bits, I));
if (CR.contains(V) && TestFn(V))
if (IgnoreNaNPayload) {
if (CR.containsSNaN()) {
if (TestFn(APFloat::getSNaN(Sem, false)))
return true;
if (TestFn(APFloat::getSNaN(Sem, true)))
return true;
}
if (CR.containsQNaN()) {
if (TestFn(APFloat::getQNaN(Sem, false)))
return true;
if (TestFn(APFloat::getQNaN(Sem, true)))
return true;
}
if (CR.isNaNOnly())
return false;
APFloat Lower = CR.getLower();
const APFloat &Upper = CR.getUpper();
auto Next = [&](APFloat &V) {
if (V.bitwiseIsEqual(Upper))
return false;
strictNext(V);
return true;
};
do {
if (TestFn(Lower))
return true;
} while (Next(Lower));
} else {
unsigned Bits = APFloat::semanticsSizeInBits(Sem);
assert(Bits < 32 && "Too many bits");
for (unsigned I = 0, E = (1U << Bits) - 1; I != E; ++I) {
APFloat V(Sem, APInt(Bits, I));
if (CR.contains(V) && TestFn(V))
return true;
}
}
return false;
}
Expand Down Expand Up @@ -385,13 +439,16 @@ TEST_F(ConstantFPRangeTest, FPClassify) {
[](const ConstantFPRange &CR) {
unsigned Mask = fcNone;
bool HasPos = false, HasNeg = false;
EnumerateValuesInConstantFPRange(CR, [&](const APFloat &V) {
Mask |= V.classify();
if (V.isNegative())
HasNeg = true;
else
HasPos = true;
});
EnumerateValuesInConstantFPRange(
CR,
[&](const APFloat &V) {
Mask |= V.classify();
if (V.isNegative())
HasNeg = true;
else
HasPos = true;
},
/*IgnoreNaNPayload=*/true);

std::optional<bool> SignBit = std::nullopt;
if (HasPos != HasNeg)
Expand Down Expand Up @@ -453,11 +510,15 @@ TEST_F(ConstantFPRangeTest, makeAllowedFCmpRegion) {
EnumerateValuesInConstantFPRange(
ConstantFPRange::getFull(CR.getSemantics()),
[&](const APFloat &V) {
if (AnyOfValueInConstantFPRange(CR, [&](const APFloat &U) {
return FCmpInst::compare(V, U, Pred);
}))
if (AnyOfValueInConstantFPRange(
CR,
[&](const APFloat &U) {
return FCmpInst::compare(V, U, Pred);
},
/*IgnoreNaNPayload=*/true))
Optimal = Optimal.unionWith(ConstantFPRange(V));
});
},
/*IgnoreNaNPayload=*/true);

EXPECT_TRUE(Res.contains(Optimal))
<< "Wrong result for makeAllowedFCmpRegion(" << Pred << ", " << CR
Expand Down

0 comments on commit 856774d

Please sign in to comment.