Skip to content

Commit 6e3ad10

Browse files
committed
[ConstantFPRange] Implement ConstantFPRange::makeAllowedFCmpRegion
1 parent 4db1056 commit 6e3ad10

File tree

2 files changed

+141
-2
lines changed

2 files changed

+141
-2
lines changed

llvm/lib/IR/ConstantFPRange.cpp

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,109 @@ ConstantFPRange ConstantFPRange::getNonNaN(const fltSemantics &Sem) {
108108
/*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
109109
}
110110

111+
/// Return [-inf, V) or [-inf, V]
112+
static ConstantFPRange makeLessThan(APFloat V, FCmpInst::Predicate Pred) {
113+
const fltSemantics &Sem = V.getSemantics();
114+
if (!(Pred & FCmpInst::FCMP_OEQ)) {
115+
if (V.isNegInfinity())
116+
return ConstantFPRange::getEmpty(Sem);
117+
V.next(/*nextDown=*/true);
118+
}
119+
return ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),
120+
std::move(V));
121+
}
122+
123+
/// Return (V, +inf] or [V, +inf]
124+
static ConstantFPRange makeGreaterThan(APFloat V, FCmpInst::Predicate Pred) {
125+
const fltSemantics &Sem = V.getSemantics();
126+
if (!(Pred & FCmpInst::FCMP_OEQ)) {
127+
if (V.isPosInfinity())
128+
return ConstantFPRange::getEmpty(Sem);
129+
V.next(/*nextDown=*/false);
130+
}
131+
return ConstantFPRange::getNonNaN(std::move(V),
132+
APFloat::getInf(Sem, /*Negative=*/false));
133+
}
134+
135+
/// Make sure that +0/-0 are both included in the range.
136+
static ConstantFPRange extendZeroIfEqual(const ConstantFPRange &CR,
137+
FCmpInst::Predicate Pred) {
138+
if (!(Pred & FCmpInst::FCMP_OEQ))
139+
return CR;
140+
141+
APFloat Lower = CR.getLower();
142+
APFloat Upper = CR.getUpper();
143+
if (Lower.isPosZero())
144+
Lower = APFloat::getZero(Lower.getSemantics(), /*Negative=*/true);
145+
if (Upper.isNegZero())
146+
Upper = APFloat::getZero(Upper.getSemantics(), /*Negative=*/false);
147+
return ConstantFPRange(std::move(Lower), std::move(Upper), CR.containsQNaN(),
148+
CR.containsSNaN());
149+
}
150+
151+
static ConstantFPRange setNaNField(const ConstantFPRange &CR,
152+
FCmpInst::Predicate Pred) {
153+
bool ContainsNaN = FCmpInst::isUnordered(Pred);
154+
return ConstantFPRange(CR.getLower(), CR.getUpper(),
155+
/*MayBeQNaN=*/ContainsNaN, /*MayBeSNaN=*/ContainsNaN);
156+
}
157+
111158
ConstantFPRange
112159
ConstantFPRange::makeAllowedFCmpRegion(FCmpInst::Predicate Pred,
113160
const ConstantFPRange &Other) {
114-
// TODO
115-
return getFull(Other.getSemantics());
161+
if (Other.isEmptySet())
162+
return Other;
163+
if (Other.containsNaN() && FCmpInst::isUnordered(Pred))
164+
return getFull(Other.getSemantics());
165+
if (Other.isNaNOnly() && FCmpInst::isOrdered(Pred))
166+
return getEmpty(Other.getSemantics());
167+
168+
switch (Pred) {
169+
case FCmpInst::FCMP_TRUE:
170+
return getFull(Other.getSemantics());
171+
case FCmpInst::FCMP_FALSE:
172+
return getEmpty(Other.getSemantics());
173+
case FCmpInst::FCMP_ORD:
174+
return getNonNaN(Other.getSemantics());
175+
case FCmpInst::FCMP_UNO:
176+
return getNaNOnly(Other.getSemantics(), /*MayBeQNaN=*/true,
177+
/*MayBeSNaN=*/true);
178+
case FCmpInst::FCMP_OEQ:
179+
case FCmpInst::FCMP_UEQ:
180+
return setNaNField(extendZeroIfEqual(Other, Pred), Pred);
181+
case FCmpInst::FCMP_ONE:
182+
case FCmpInst::FCMP_UNE:
183+
if (const APFloat *SingleElement =
184+
Other.getSingleElement(/*ExcludesNaN=*/true)) {
185+
const fltSemantics &Sem = SingleElement->getSemantics();
186+
if (SingleElement->isPosInfinity())
187+
return setNaNField(
188+
getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),
189+
APFloat::getLargest(Sem, /*Negative=*/false)),
190+
Pred);
191+
if (SingleElement->isNegInfinity())
192+
return setNaNField(
193+
getNonNaN(APFloat::getLargest(Sem, /*Negative=*/true),
194+
APFloat::getInf(Sem, /*Negative=*/false)),
195+
Pred);
196+
}
197+
return Pred == FCmpInst::FCMP_ONE ? getNonNaN(Other.getSemantics())
198+
: getFull(Other.getSemantics());
199+
case FCmpInst::FCMP_OLT:
200+
case FCmpInst::FCMP_OLE:
201+
case FCmpInst::FCMP_ULT:
202+
case FCmpInst::FCMP_ULE:
203+
return setNaNField(
204+
extendZeroIfEqual(makeLessThan(Other.getUpper(), Pred), Pred), Pred);
205+
case FCmpInst::FCMP_OGT:
206+
case FCmpInst::FCMP_OGE:
207+
case FCmpInst::FCMP_UGT:
208+
case FCmpInst::FCMP_UGE:
209+
return setNaNField(
210+
extendZeroIfEqual(makeGreaterThan(Other.getLower(), Pred), Pred), Pred);
211+
default:
212+
llvm_unreachable("Unexpected predicate");
213+
}
116214
}
117215

118216
ConstantFPRange

llvm/unittests/IR/ConstantFPRangeTest.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,19 @@ static void EnumerateValuesInConstantFPRange(const ConstantFPRange &CR,
161161
}
162162
}
163163

164+
template <typename Fn>
165+
static bool AnyOfValueInConstantFPRange(const ConstantFPRange &CR, Fn TestFn) {
166+
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))
172+
return true;
173+
}
174+
return false;
175+
}
176+
164177
TEST_F(ConstantFPRangeTest, Basics) {
165178
EXPECT_TRUE(Full.isFullSet());
166179
EXPECT_FALSE(Full.isEmptySet());
@@ -429,4 +442,32 @@ TEST_F(ConstantFPRangeTest, MismatchedSemantics) {
429442
#endif
430443
#endif
431444

445+
TEST_F(ConstantFPRangeTest, makeAllowedFCmpRegion) {
446+
for (auto Pred : FCmpInst::predicates()) {
447+
EnumerateConstantFPRanges(
448+
[Pred](const ConstantFPRange &CR) {
449+
ConstantFPRange Res =
450+
ConstantFPRange::makeAllowedFCmpRegion(Pred, CR);
451+
ConstantFPRange Optimal =
452+
ConstantFPRange::getEmpty(CR.getSemantics());
453+
EnumerateValuesInConstantFPRange(
454+
ConstantFPRange::getFull(CR.getSemantics()),
455+
[&](const APFloat &V) {
456+
if (AnyOfValueInConstantFPRange(CR, [&](const APFloat &U) {
457+
return FCmpInst::compare(V, U, Pred);
458+
}))
459+
Optimal = Optimal.unionWith(ConstantFPRange(V));
460+
});
461+
462+
ASSERT_TRUE(Res.contains(Optimal))
463+
<< "Wrong result for makeAllowedFCmpRegion(" << Pred << ", " << CR
464+
<< "). Expected " << Optimal << ", but got " << Res;
465+
EXPECT_EQ(Res, Optimal)
466+
<< "Suboptimal result for makeAllowedFCmpRegion(" << Pred << ", "
467+
<< CR << ")";
468+
},
469+
/*Exhaustive=*/false);
470+
}
471+
}
472+
432473
} // anonymous namespace

0 commit comments

Comments
 (0)