Skip to content

Commit 856774d

Browse files
authored
[ConstantFPRange][UnitTest] Ignore NaN payloads when enumerating values 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.
1 parent 67d247a commit 856774d

File tree

1 file changed

+85
-24
lines changed

1 file changed

+85
-24
lines changed

llvm/unittests/IR/ConstantFPRangeTest.cpp

Lines changed: 85 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -150,26 +150,80 @@ static void EnumerateTwoInterestingConstantFPRanges(Fn TestFn,
150150

151151
template <typename Fn>
152152
static void EnumerateValuesInConstantFPRange(const ConstantFPRange &CR,
153-
Fn TestFn) {
153+
Fn TestFn, bool IgnoreNaNPayload) {
154154
const fltSemantics &Sem = CR.getSemantics();
155-
unsigned Bits = APFloat::semanticsSizeInBits(Sem);
156-
assert(Bits < 32 && "Too many bits");
157-
for (unsigned I = 0, E = (1U << Bits) - 1; I != E; ++I) {
158-
APFloat V(Sem, APInt(Bits, I));
159-
if (CR.contains(V))
160-
TestFn(V);
155+
if (IgnoreNaNPayload) {
156+
if (CR.containsSNaN()) {
157+
TestFn(APFloat::getSNaN(Sem, false));
158+
TestFn(APFloat::getSNaN(Sem, true));
159+
}
160+
if (CR.containsQNaN()) {
161+
TestFn(APFloat::getQNaN(Sem, false));
162+
TestFn(APFloat::getQNaN(Sem, true));
163+
}
164+
if (CR.isNaNOnly())
165+
return;
166+
APFloat Lower = CR.getLower();
167+
const APFloat &Upper = CR.getUpper();
168+
auto Next = [&](APFloat &V) {
169+
if (V.bitwiseIsEqual(Upper))
170+
return false;
171+
strictNext(V);
172+
return true;
173+
};
174+
do
175+
TestFn(Lower);
176+
while (Next(Lower));
177+
} else {
178+
unsigned Bits = APFloat::semanticsSizeInBits(Sem);
179+
assert(Bits < 32 && "Too many bits");
180+
for (unsigned I = 0, E = (1U << Bits) - 1; I != E; ++I) {
181+
APFloat V(Sem, APInt(Bits, I));
182+
if (CR.contains(V))
183+
TestFn(V);
184+
}
161185
}
162186
}
163187

164188
template <typename Fn>
165-
static bool AnyOfValueInConstantFPRange(const ConstantFPRange &CR, Fn TestFn) {
189+
static bool AnyOfValueInConstantFPRange(const ConstantFPRange &CR, Fn TestFn,
190+
bool IgnoreNaNPayload) {
166191
const fltSemantics &Sem = CR.getSemantics();
167-
unsigned Bits = APFloat::semanticsSizeInBits(Sem);
168-
assert(Bits < 32 && "Too many bits");
169-
for (unsigned I = 0, E = (1U << Bits) - 1; I != E; ++I) {
170-
APFloat V(Sem, APInt(Bits, I));
171-
if (CR.contains(V) && TestFn(V))
192+
if (IgnoreNaNPayload) {
193+
if (CR.containsSNaN()) {
194+
if (TestFn(APFloat::getSNaN(Sem, false)))
195+
return true;
196+
if (TestFn(APFloat::getSNaN(Sem, true)))
197+
return true;
198+
}
199+
if (CR.containsQNaN()) {
200+
if (TestFn(APFloat::getQNaN(Sem, false)))
201+
return true;
202+
if (TestFn(APFloat::getQNaN(Sem, true)))
203+
return true;
204+
}
205+
if (CR.isNaNOnly())
206+
return false;
207+
APFloat Lower = CR.getLower();
208+
const APFloat &Upper = CR.getUpper();
209+
auto Next = [&](APFloat &V) {
210+
if (V.bitwiseIsEqual(Upper))
211+
return false;
212+
strictNext(V);
172213
return true;
214+
};
215+
do {
216+
if (TestFn(Lower))
217+
return true;
218+
} while (Next(Lower));
219+
} else {
220+
unsigned Bits = APFloat::semanticsSizeInBits(Sem);
221+
assert(Bits < 32 && "Too many bits");
222+
for (unsigned I = 0, E = (1U << Bits) - 1; I != E; ++I) {
223+
APFloat V(Sem, APInt(Bits, I));
224+
if (CR.contains(V) && TestFn(V))
225+
return true;
226+
}
173227
}
174228
return false;
175229
}
@@ -385,13 +439,16 @@ TEST_F(ConstantFPRangeTest, FPClassify) {
385439
[](const ConstantFPRange &CR) {
386440
unsigned Mask = fcNone;
387441
bool HasPos = false, HasNeg = false;
388-
EnumerateValuesInConstantFPRange(CR, [&](const APFloat &V) {
389-
Mask |= V.classify();
390-
if (V.isNegative())
391-
HasNeg = true;
392-
else
393-
HasPos = true;
394-
});
442+
EnumerateValuesInConstantFPRange(
443+
CR,
444+
[&](const APFloat &V) {
445+
Mask |= V.classify();
446+
if (V.isNegative())
447+
HasNeg = true;
448+
else
449+
HasPos = true;
450+
},
451+
/*IgnoreNaNPayload=*/true);
395452

396453
std::optional<bool> SignBit = std::nullopt;
397454
if (HasPos != HasNeg)
@@ -453,11 +510,15 @@ TEST_F(ConstantFPRangeTest, makeAllowedFCmpRegion) {
453510
EnumerateValuesInConstantFPRange(
454511
ConstantFPRange::getFull(CR.getSemantics()),
455512
[&](const APFloat &V) {
456-
if (AnyOfValueInConstantFPRange(CR, [&](const APFloat &U) {
457-
return FCmpInst::compare(V, U, Pred);
458-
}))
513+
if (AnyOfValueInConstantFPRange(
514+
CR,
515+
[&](const APFloat &U) {
516+
return FCmpInst::compare(V, U, Pred);
517+
},
518+
/*IgnoreNaNPayload=*/true))
459519
Optimal = Optimal.unionWith(ConstantFPRange(V));
460-
});
520+
},
521+
/*IgnoreNaNPayload=*/true);
461522

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

0 commit comments

Comments
 (0)