Skip to content

Commit 5867362

Browse files
authored
[ConstantFPRange] Implement ConstantFPRange::makeAllowedFCmpRegion (#110082)
This patch adds `makeAllowedFCmpRegion` support for `ConstantFPRange`.
1 parent eb3361d commit 5867362

File tree

2 files changed

+146
-2
lines changed

2 files changed

+146
-2
lines changed

llvm/lib/IR/ConstantFPRange.cpp

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

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

118221
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+
EXPECT_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)