1 //===- ConstantFPRange.cpp - ConstantFPRange implementation ---------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/IR/ConstantFPRange.h"
10 #include "llvm/ADT/APFloat.h"
11 #include "llvm/Support/Debug.h"
12 #include "llvm/Support/raw_ostream.h"
17 void ConstantFPRange::makeEmpty() {
18 auto &Sem
= Lower
.getSemantics();
19 Lower
= APFloat::getInf(Sem
, /*Negative=*/false);
20 Upper
= APFloat::getInf(Sem
, /*Negative=*/true);
25 void ConstantFPRange::makeFull() {
26 auto &Sem
= Lower
.getSemantics();
27 Lower
= APFloat::getInf(Sem
, /*Negative=*/true);
28 Upper
= APFloat::getInf(Sem
, /*Negative=*/false);
33 bool ConstantFPRange::isNaNOnly() const {
34 return Lower
.isPosInfinity() && Upper
.isNegInfinity();
37 ConstantFPRange::ConstantFPRange(const fltSemantics
&Sem
, bool IsFullSet
)
38 : Lower(Sem
, APFloat::uninitialized
), Upper(Sem
, APFloat::uninitialized
) {
39 Lower
= APFloat::getInf(Sem
, /*Negative=*/IsFullSet
);
40 Upper
= APFloat::getInf(Sem
, /*Negative=*/!IsFullSet
);
41 MayBeQNaN
= IsFullSet
;
42 MayBeSNaN
= IsFullSet
;
45 ConstantFPRange::ConstantFPRange(const APFloat
&Value
)
46 : Lower(Value
.getSemantics(), APFloat::uninitialized
),
47 Upper(Value
.getSemantics(), APFloat::uninitialized
) {
50 bool IsSNaN
= Value
.isSignaling();
54 Lower
= Upper
= Value
;
55 MayBeQNaN
= MayBeSNaN
= false;
59 // We treat that -0 is less than 0 here.
60 static APFloat::cmpResult
strictCompare(const APFloat
&LHS
,
62 assert(!LHS
.isNaN() && !RHS
.isNaN() && "Unordered compare");
63 if (LHS
.isZero() && RHS
.isZero()) {
64 if (LHS
.isNegative() == RHS
.isNegative())
65 return APFloat::cmpEqual
;
66 return LHS
.isNegative() ? APFloat::cmpLessThan
: APFloat::cmpGreaterThan
;
68 return LHS
.compare(RHS
);
71 static bool isNonCanonicalEmptySet(const APFloat
&Lower
, const APFloat
&Upper
) {
72 return strictCompare(Lower
, Upper
) == APFloat::cmpGreaterThan
&&
73 !(Lower
.isInfinity() && Upper
.isInfinity());
76 static void canonicalizeRange(APFloat
&Lower
, APFloat
&Upper
) {
77 if (isNonCanonicalEmptySet(Lower
, Upper
)) {
78 Lower
= APFloat::getInf(Lower
.getSemantics(), /*Negative=*/false);
79 Upper
= APFloat::getInf(Upper
.getSemantics(), /*Negative=*/true);
83 ConstantFPRange::ConstantFPRange(APFloat LowerVal
, APFloat UpperVal
,
84 bool MayBeQNaNVal
, bool MayBeSNaNVal
)
85 : Lower(std::move(LowerVal
)), Upper(std::move(UpperVal
)),
86 MayBeQNaN(MayBeQNaNVal
), MayBeSNaN(MayBeSNaNVal
) {
87 assert(&Lower
.getSemantics() == &Upper
.getSemantics() &&
88 "Should only use the same semantics");
89 assert(!isNonCanonicalEmptySet(Lower
, Upper
) && "Non-canonical form");
92 ConstantFPRange
ConstantFPRange::getFinite(const fltSemantics
&Sem
) {
93 return ConstantFPRange(APFloat::getLargest(Sem
, /*Negative=*/true),
94 APFloat::getLargest(Sem
, /*Negative=*/false),
95 /*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
98 ConstantFPRange
ConstantFPRange::getNaNOnly(const fltSemantics
&Sem
,
99 bool MayBeQNaN
, bool MayBeSNaN
) {
100 return ConstantFPRange(APFloat::getInf(Sem
, /*Negative=*/false),
101 APFloat::getInf(Sem
, /*Negative=*/true), MayBeQNaN
,
105 ConstantFPRange
ConstantFPRange::getNonNaN(const fltSemantics
&Sem
) {
106 return ConstantFPRange(APFloat::getInf(Sem
, /*Negative=*/true),
107 APFloat::getInf(Sem
, /*Negative=*/false),
108 /*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
111 /// Return true for ULT/UGT/OLT/OGT
112 static bool fcmpPredExcludesEqual(FCmpInst::Predicate Pred
) {
113 return !(Pred
& FCmpInst::FCMP_OEQ
);
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);
124 return ConstantFPRange::getNonNaN(APFloat::getInf(Sem
, /*Negative=*/true),
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);
136 return ConstantFPRange::getNonNaN(std::move(V
),
137 APFloat::getInf(Sem
, /*Negative=*/false));
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
))
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(),
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
);
164 ConstantFPRange::makeAllowedFCmpRegion(FCmpInst::Predicate Pred
,
165 const ConstantFPRange
&Other
) {
166 if (Other
.isEmptySet())
168 if (Other
.containsNaN() && FCmpInst::isUnordered(Pred
))
169 return getFull(Other
.getSemantics());
170 if (Other
.isNaNOnly() && FCmpInst::isOrdered(Pred
))
171 return getEmpty(Other
.getSemantics());
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,
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())
193 getNonNaN(APFloat::getInf(Sem
, /*Negative=*/true),
194 APFloat::getLargest(Sem
, /*Negative=*/false)),
196 if (SingleElement
->isNegInfinity())
198 getNonNaN(APFloat::getLargest(Sem
, /*Negative=*/true),
199 APFloat::getInf(Sem
, /*Negative=*/false)),
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
:
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
:
215 extendZeroIfEqual(makeGreaterThan(Other
.getLower(), Pred
), Pred
), Pred
);
217 llvm_unreachable("Unexpected predicate");
222 ConstantFPRange::makeSatisfyingFCmpRegion(FCmpInst::Predicate Pred
,
223 const ConstantFPRange
&Other
) {
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());
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,
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()),
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
:
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
:
262 extendZeroIfEqual(makeGreaterThan(Other
.getUpper(), Pred
), Pred
), Pred
);
264 llvm_unreachable("Unexpected predicate");
268 std::optional
<ConstantFPRange
>
269 ConstantFPRange::makeExactFCmpRegion(FCmpInst::Predicate Pred
,
270 const APFloat
&Other
) {
271 if ((Pred
== FCmpInst::FCMP_UNE
|| Pred
== FCmpInst::FCMP_ONE
) &&
274 return makeSatisfyingFCmpRegion(Pred
, ConstantFPRange(Other
));
277 bool ConstantFPRange::fcmp(FCmpInst::Predicate Pred
,
278 const ConstantFPRange
&Other
) const {
279 return makeSatisfyingFCmpRegion(Pred
, Other
).contains(*this);
282 bool ConstantFPRange::isFullSet() const {
283 return Lower
.isNegInfinity() && Upper
.isPosInfinity() && MayBeQNaN
&&
287 bool ConstantFPRange::isEmptySet() const {
288 return Lower
.isPosInfinity() && Upper
.isNegInfinity() && !MayBeQNaN
&&
292 bool ConstantFPRange::contains(const APFloat
&Val
) const {
293 assert(&getSemantics() == &Val
.getSemantics() &&
294 "Should only use the same semantics");
297 return Val
.isSignaling() ? MayBeSNaN
: MayBeQNaN
;
298 return strictCompare(Lower
, Val
) != APFloat::cmpGreaterThan
&&
299 strictCompare(Val
, Upper
) != APFloat::cmpGreaterThan
;
302 bool ConstantFPRange::contains(const ConstantFPRange
&CR
) const {
303 assert(&getSemantics() == &CR
.getSemantics() &&
304 "Should only use the same semantics");
306 if (CR
.MayBeQNaN
&& !MayBeQNaN
)
309 if (CR
.MayBeSNaN
&& !MayBeSNaN
)
312 return strictCompare(Lower
, CR
.Lower
) != APFloat::cmpGreaterThan
&&
313 strictCompare(CR
.Upper
, Upper
) != APFloat::cmpGreaterThan
;
316 const APFloat
*ConstantFPRange::getSingleElement(bool ExcludesNaN
) const {
317 if (!ExcludesNaN
&& (MayBeSNaN
|| MayBeQNaN
))
319 return Lower
.bitwiseIsEqual(Upper
) ? &Lower
: nullptr;
322 std::optional
<bool> ConstantFPRange::getSignBit() const {
323 if (!MayBeSNaN
&& !MayBeQNaN
&& Lower
.isNegative() == Upper
.isNegative())
324 return Lower
.isNegative();
328 bool ConstantFPRange::operator==(const ConstantFPRange
&CR
) const {
329 if (MayBeSNaN
!= CR
.MayBeSNaN
|| MayBeQNaN
!= CR
.MayBeQNaN
)
331 return Lower
.bitwiseIsEqual(CR
.Lower
) && Upper
.bitwiseIsEqual(CR
.Upper
);
334 FPClassTest
ConstantFPRange::classify() const {
335 uint32_t Mask
= fcNone
;
341 FPClassTest LowerMask
= Lower
.classify();
342 FPClassTest UpperMask
= Upper
.classify();
343 assert(LowerMask
<= UpperMask
&& "Range is nan-only.");
344 // Set all bits from log2(LowerMask) to log2(UpperMask).
345 Mask
|= (UpperMask
<< 1) - LowerMask
;
347 return static_cast<FPClassTest
>(Mask
);
350 void ConstantFPRange::print(raw_ostream
&OS
) const {
353 else if (isEmptySet())
356 bool NaNOnly
= isNaNOnly();
358 OS
<< '[' << Lower
<< ", " << Upper
<< ']';
360 if (MayBeSNaN
|| MayBeQNaN
) {
363 if (MayBeSNaN
&& MayBeQNaN
)
373 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
374 LLVM_DUMP_METHOD
void ConstantFPRange::dump() const { print(dbgs()); }
378 ConstantFPRange::intersectWith(const ConstantFPRange
&CR
) const {
379 assert(&getSemantics() == &CR
.getSemantics() &&
380 "Should only use the same semantics");
381 APFloat NewLower
= maxnum(Lower
, CR
.Lower
);
382 APFloat NewUpper
= minnum(Upper
, CR
.Upper
);
383 canonicalizeRange(NewLower
, NewUpper
);
384 return ConstantFPRange(std::move(NewLower
), std::move(NewUpper
),
385 MayBeQNaN
& CR
.MayBeQNaN
, MayBeSNaN
& CR
.MayBeSNaN
);
388 ConstantFPRange
ConstantFPRange::unionWith(const ConstantFPRange
&CR
) const {
389 assert(&getSemantics() == &CR
.getSemantics() &&
390 "Should only use the same semantics");
391 return ConstantFPRange(minnum(Lower
, CR
.Lower
), maxnum(Upper
, CR
.Upper
),
392 MayBeQNaN
| CR
.MayBeQNaN
, MayBeSNaN
| CR
.MayBeSNaN
);