Skip to content

Commit 2633b93

Browse files
committed
[ConstantFPRange] Implement ConstantFPRange::makeSatisfyingFCmpRegion
1 parent 9bf02a8 commit 2633b93

File tree

2 files changed

+111
-2
lines changed

2 files changed

+111
-2
lines changed

llvm/lib/IR/ConstantFPRange.cpp

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,48 @@ ConstantFPRange::makeAllowedFCmpRegion(FCmpInst::Predicate Pred,
221221
ConstantFPRange
222222
ConstantFPRange::makeSatisfyingFCmpRegion(FCmpInst::Predicate Pred,
223223
const ConstantFPRange &Other) {
224-
// TODO
225-
return getEmpty(Other.getSemantics());
224+
if (Other.isEmptySet())
225+
return getFull(Other.getSemantics());
226+
if (Other.containsNaN() && FCmpInst::isOrdered(Pred))
227+
return getEmpty(Other.getSemantics());
228+
if (Other.isNaNOnly() && FCmpInst::isUnordered(Pred))
229+
return getFull(Other.getSemantics());
230+
231+
switch (Pred) {
232+
case FCmpInst::FCMP_TRUE:
233+
return getFull(Other.getSemantics());
234+
case FCmpInst::FCMP_FALSE:
235+
return getEmpty(Other.getSemantics());
236+
case FCmpInst::FCMP_ORD:
237+
return getNonNaN(Other.getSemantics());
238+
case FCmpInst::FCMP_UNO:
239+
return getNaNOnly(Other.getSemantics(), /*MayBeQNaN=*/true,
240+
/*MayBeSNaN=*/true);
241+
case FCmpInst::FCMP_OEQ:
242+
case FCmpInst::FCMP_UEQ:
243+
return setNaNField(Other.isSingleElement(/*ExcludesNaN=*/true) ||
244+
((Other.classify() & ~fcNan) == fcZero)
245+
? extendZeroIfEqual(Other, Pred)
246+
: getEmpty(Other.getSemantics()),
247+
Pred);
248+
case FCmpInst::FCMP_ONE:
249+
case FCmpInst::FCMP_UNE:
250+
return getEmpty(Other.getSemantics());
251+
case FCmpInst::FCMP_OLT:
252+
case FCmpInst::FCMP_OLE:
253+
case FCmpInst::FCMP_ULT:
254+
case FCmpInst::FCMP_ULE:
255+
return setNaNField(
256+
extendZeroIfEqual(makeLessThan(Other.getLower(), Pred), Pred), Pred);
257+
case FCmpInst::FCMP_OGT:
258+
case FCmpInst::FCMP_OGE:
259+
case FCmpInst::FCMP_UGT:
260+
case FCmpInst::FCMP_UGE:
261+
return setNaNField(
262+
extendZeroIfEqual(makeGreaterThan(Other.getUpper(), Pred), Pred), Pred);
263+
default:
264+
llvm_unreachable("Unexpected predicate");
265+
}
226266
}
227267

228268
std::optional<ConstantFPRange>

llvm/unittests/IR/ConstantFPRangeTest.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,4 +470,73 @@ TEST_F(ConstantFPRangeTest, makeAllowedFCmpRegion) {
470470
}
471471
}
472472

473+
TEST_F(ConstantFPRangeTest, makeSatisfyingFCmpRegion) {
474+
for (auto Pred : FCmpInst::predicates()) {
475+
EnumerateConstantFPRanges(
476+
[Pred](const ConstantFPRange &CR) {
477+
ConstantFPRange Res =
478+
ConstantFPRange::makeSatisfyingFCmpRegion(Pred, CR);
479+
// Super set of the optimal set excluding NaNs
480+
ConstantFPRange SuperSet(CR.getSemantics());
481+
bool ContainsSNaN = false;
482+
bool ContainsQNaN = false;
483+
unsigned NonNaNValsInOptimalSet = 0;
484+
EnumerateValuesInConstantFPRange(
485+
ConstantFPRange::getFull(CR.getSemantics()),
486+
[&](const APFloat &V) {
487+
if (AnyOfValueInConstantFPRange(CR, [&](const APFloat &U) {
488+
return !FCmpInst::compare(V, U, Pred);
489+
})) {
490+
EXPECT_FALSE(Res.contains(V))
491+
<< "Wrong result for makeSatisfyingFCmpRegion(" << Pred
492+
<< ", " << CR << "). The result " << Res
493+
<< " should not contain " << V;
494+
} else {
495+
if (V.isNaN()) {
496+
if (V.isSignaling())
497+
ContainsSNaN = true;
498+
else
499+
ContainsQNaN = true;
500+
} else {
501+
SuperSet = SuperSet.unionWith(ConstantFPRange(V));
502+
++NonNaNValsInOptimalSet;
503+
}
504+
}
505+
});
506+
507+
// Check optimality
508+
509+
// The usefullness of making the result optimal for one/une is
510+
// questionable.
511+
if (Pred == FCmpInst::FCMP_ONE || Pred == FCmpInst::FCMP_UNE)
512+
return;
513+
514+
EXPECT_FALSE(ContainsSNaN && !Res.containsSNaN())
515+
<< "Suboptimal result for makeSatisfyingFCmpRegion(" << Pred
516+
<< ", " << CR << "), should contain SNaN, but got " << Res;
517+
EXPECT_FALSE(ContainsQNaN && !Res.containsQNaN())
518+
<< "Suboptimal result for makeSatisfyingFCmpRegion(" << Pred
519+
<< ", " << CR << "), should contain QNaN, but got " << Res;
520+
521+
// We only care about the cases where the result is representable by
522+
// ConstantFPRange.
523+
unsigned NonNaNValsInSuperSet = 0;
524+
EnumerateValuesInConstantFPRange(SuperSet, [&](const APFloat &V) {
525+
if (!V.isNaN())
526+
++NonNaNValsInSuperSet;
527+
});
528+
529+
if (NonNaNValsInSuperSet == NonNaNValsInOptimalSet) {
530+
ConstantFPRange Optimal =
531+
ConstantFPRange(SuperSet.getLower(), SuperSet.getUpper(),
532+
ContainsQNaN, ContainsSNaN);
533+
EXPECT_EQ(Res, Optimal)
534+
<< "Suboptimal result for makeSatisfyingFCmpRegion(" << Pred
535+
<< ", " << CR << ")";
536+
}
537+
},
538+
/*Exhaustive=*/false);
539+
}
540+
}
541+
473542
} // anonymous namespace

0 commit comments

Comments
 (0)