LLVM 22.0.0git
ConstantFPRange.cpp
Go to the documentation of this file.
1//===- ConstantFPRange.cpp - ConstantFPRange implementation ---------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
10#include "llvm/ADT/APFloat.h"
11#include "llvm/Support/Debug.h"
13#include <cassert>
14
15using namespace llvm;
16
17void ConstantFPRange::makeEmpty() {
18 auto &Sem = Lower.getSemantics();
19 Lower = APFloat::getInf(Sem, /*Negative=*/false);
20 Upper = APFloat::getInf(Sem, /*Negative=*/true);
21 MayBeQNaN = false;
22 MayBeSNaN = false;
23}
24
25void ConstantFPRange::makeFull() {
26 auto &Sem = Lower.getSemantics();
27 Lower = APFloat::getInf(Sem, /*Negative=*/true);
28 Upper = APFloat::getInf(Sem, /*Negative=*/false);
29 MayBeQNaN = true;
30 MayBeSNaN = true;
31}
32
34 return Lower.isPosInfinity() && Upper.isNegInfinity();
35}
36
37ConstantFPRange::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;
43}
44
45ConstantFPRange::ConstantFPRange(const APFloat &Value)
46 : Lower(Value.getSemantics(), APFloat::uninitialized),
47 Upper(Value.getSemantics(), APFloat::uninitialized) {
48 if (Value.isNaN()) {
49 makeEmpty();
50 bool IsSNaN = Value.isSignaling();
51 MayBeQNaN = !IsSNaN;
52 MayBeSNaN = IsSNaN;
53 } else {
54 Lower = Upper = Value;
55 MayBeQNaN = MayBeSNaN = false;
56 }
57}
58
59// We treat that -0 is less than 0 here.
61 const APFloat &RHS) {
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;
67 }
68 return LHS.compare(RHS);
69}
70
71static bool isNonCanonicalEmptySet(const APFloat &Lower, const APFloat &Upper) {
73 !(Lower.isInfinity() && Upper.isInfinity());
74}
75
78 Lower = APFloat::getInf(Lower.getSemantics(), /*Negative=*/false);
79 Upper = APFloat::getInf(Upper.getSemantics(), /*Negative=*/true);
80 }
81}
82
83ConstantFPRange::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");
90}
91
93 return ConstantFPRange(APFloat::getLargest(Sem, /*Negative=*/true),
94 APFloat::getLargest(Sem, /*Negative=*/false),
95 /*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
96}
97
99 bool MayBeQNaN, bool MayBeSNaN) {
100 return ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/false),
101 APFloat::getInf(Sem, /*Negative=*/true), MayBeQNaN,
102 MayBeSNaN);
103}
104
106 return ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/true),
107 APFloat::getInf(Sem, /*Negative=*/false),
108 /*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
109}
110
111/// Return true for ULT/UGT/OLT/OGT
113 return !(Pred & FCmpInst::FCMP_OEQ);
114}
115
116/// Return [-inf, V) or [-inf, V]
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]
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.
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
157 FCmpInst::Predicate Pred) {
158 bool ContainsNaN = FCmpInst::isUnordered(Pred);
159 return ConstantFPRange(CR.getLower(), CR.getUpper(),
160 /*MayBeQNaN=*/ContainsNaN, /*MayBeSNaN=*/ContainsNaN);
161}
162
165 const ConstantFPRange &Other) {
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) {
175 return getFull(Other.getSemantics());
177 return getEmpty(Other.getSemantics());
179 return getNonNaN(Other.getSemantics());
181 return getNaNOnly(Other.getSemantics(), /*MayBeQNaN=*/true,
182 /*MayBeSNaN=*/true);
185 return setNaNField(extendZeroIfEqual(Other, Pred), Pred);
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());
208 return setNaNField(
209 extendZeroIfEqual(makeLessThan(Other.getUpper(), Pred), Pred), Pred);
214 return setNaNField(
215 extendZeroIfEqual(makeGreaterThan(Other.getLower(), Pred), Pred), Pred);
216 default:
217 llvm_unreachable("Unexpected predicate");
218 }
219}
220
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());
230
231 switch (Pred) {
233 return getFull(Other.getSemantics());
235 return getEmpty(Other.getSemantics());
237 return getNonNaN(Other.getSemantics());
239 return getNaNOnly(Other.getSemantics(), /*MayBeQNaN=*/true,
240 /*MayBeSNaN=*/true);
243 return setNaNField(Other.isSingleElement(/*ExcludesNaN=*/true) ||
244 ((Other.classify() & ~fcNan) == fcZero)
245 ? extendZeroIfEqual(Other, Pred)
246 : getEmpty(Other.getSemantics()),
247 Pred);
250 return getEmpty(Other.getSemantics());
255 return setNaNField(
256 extendZeroIfEqual(makeLessThan(Other.getLower(), Pred), Pred), Pred);
261 return setNaNField(
262 extendZeroIfEqual(makeGreaterThan(Other.getUpper(), Pred), Pred), Pred);
263 default:
264 llvm_unreachable("Unexpected predicate");
265 }
266}
267
268std::optional<ConstantFPRange>
270 const APFloat &Other) {
271 if ((Pred == FCmpInst::FCMP_UNE || Pred == FCmpInst::FCMP_ONE) &&
272 !Other.isNaN())
273 return std::nullopt;
275}
276
278 const ConstantFPRange &Other) const {
279 return makeSatisfyingFCmpRegion(Pred, Other).contains(*this);
280}
281
283 return Lower.isNegInfinity() && Upper.isPosInfinity() && MayBeQNaN &&
284 MayBeSNaN;
285}
286
288 return Lower.isPosInfinity() && Upper.isNegInfinity() && !MayBeQNaN &&
289 !MayBeSNaN;
290}
291
292bool ConstantFPRange::contains(const APFloat &Val) const {
293 assert(&getSemantics() == &Val.getSemantics() &&
294 "Should only use the same semantics");
295
296 if (Val.isNaN())
297 return Val.isSignaling() ? MayBeSNaN : MayBeQNaN;
298 return strictCompare(Lower, Val) != APFloat::cmpGreaterThan &&
300}
301
303 assert(&getSemantics() == &CR.getSemantics() &&
304 "Should only use the same semantics");
305
306 if (CR.MayBeQNaN && !MayBeQNaN)
307 return false;
308
309 if (CR.MayBeSNaN && !MayBeSNaN)
310 return false;
311
312 return strictCompare(Lower, CR.Lower) != APFloat::cmpGreaterThan &&
313 strictCompare(CR.Upper, Upper) != APFloat::cmpGreaterThan;
314}
315
316const APFloat *ConstantFPRange::getSingleElement(bool ExcludesNaN) const {
317 if (!ExcludesNaN && (MayBeSNaN || MayBeQNaN))
318 return nullptr;
319 return Lower.bitwiseIsEqual(Upper) ? &Lower : nullptr;
320}
321
322std::optional<bool> ConstantFPRange::getSignBit() const {
323 if (!MayBeSNaN && !MayBeQNaN && Lower.isNegative() == Upper.isNegative())
324 return Lower.isNegative();
325 return std::nullopt;
326}
327
329 if (MayBeSNaN != CR.MayBeSNaN || MayBeQNaN != CR.MayBeQNaN)
330 return false;
331 return Lower.bitwiseIsEqual(CR.Lower) && Upper.bitwiseIsEqual(CR.Upper);
332}
333
335 uint32_t Mask = fcNone;
336 if (MayBeSNaN)
337 Mask |= fcSNan;
338 if (MayBeQNaN)
339 Mask |= fcQNan;
340 if (!isNaNOnly()) {
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;
346 }
347 return static_cast<FPClassTest>(Mask);
348}
349
351 if (isFullSet())
352 OS << "full-set";
353 else if (isEmptySet())
354 OS << "empty-set";
355 else {
356 bool NaNOnly = isNaNOnly();
357 if (!NaNOnly)
358 OS << '[' << Lower << ", " << Upper << ']';
359
360 if (MayBeSNaN || MayBeQNaN) {
361 if (!NaNOnly)
362 OS << " with ";
363 if (MayBeSNaN && MayBeQNaN)
364 OS << "NaN";
365 else if (MayBeSNaN)
366 OS << "SNaN";
367 else if (MayBeQNaN)
368 OS << "QNaN";
369 }
370 }
371}
372
373#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
375#endif
376
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);
386}
387
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);
393}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file declares a class to represent arbitrary precision floating point values and provide a varie...
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition: Compiler.h:638
static APFloat::cmpResult strictCompare(const APFloat &LHS, const APFloat &RHS)
static ConstantFPRange extendZeroIfEqual(const ConstantFPRange &CR, FCmpInst::Predicate Pred)
Make sure that +0/-0 are both included in the range.
static bool fcmpPredExcludesEqual(FCmpInst::Predicate Pred)
Return true for ULT/UGT/OLT/OGT.
static ConstantFPRange makeLessThan(APFloat V, FCmpInst::Predicate Pred)
Return [-inf, V) or [-inf, V].
static void canonicalizeRange(APFloat &Lower, APFloat &Upper)
static ConstantFPRange makeGreaterThan(APFloat V, FCmpInst::Predicate Pred)
Return (V, +inf] or [V, +inf].
static bool isNonCanonicalEmptySet(const APFloat &Lower, const APFloat &Upper)
static ConstantFPRange setNaNField(const ConstantFPRange &CR, FCmpInst::Predicate Pred)
raw_pwrite_stream & OS
Value * RHS
Value * LHS
bool bitwiseIsEqual(const APFloat &RHS) const
Definition: APFloat.h:1414
bool isNegative() const
Definition: APFloat.h:1449
bool isPosInfinity() const
Definition: APFloat.h:1462
const fltSemantics & getSemantics() const
Definition: APFloat.h:1457
bool isNaN() const
Definition: APFloat.h:1447
bool isSignaling() const
Definition: APFloat.h:1451
static APFloat getLargest(const fltSemantics &Sem, bool Negative=false)
Returns the largest finite number in the given semantics.
Definition: APFloat.h:1138
static APFloat getInf(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Infinity.
Definition: APFloat.h:1098
LLVM_ABI FPClassTest classify() const
Return the FPClassTest which will return true for the value.
Definition: APFloat.cpp:5986
bool isNegInfinity() const
Definition: APFloat.h:1463
static APFloat getZero(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Zero.
Definition: APFloat.h:1079
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition: InstrTypes.h:678
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
Definition: InstrTypes.h:681
@ FCMP_TRUE
1 1 1 1 Always true (always folded)
Definition: InstrTypes.h:695
@ FCMP_OLT
0 1 0 0 True if ordered and less than
Definition: InstrTypes.h:684
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
Definition: InstrTypes.h:693
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
Definition: InstrTypes.h:682
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
Definition: InstrTypes.h:683
@ FCMP_ULT
1 1 0 0 True if unordered or less than
Definition: InstrTypes.h:692
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
Definition: InstrTypes.h:686
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
Definition: InstrTypes.h:689
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
Definition: InstrTypes.h:690
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
Definition: InstrTypes.h:685
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
Definition: InstrTypes.h:687
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
Definition: InstrTypes.h:694
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
Definition: InstrTypes.h:691
@ FCMP_FALSE
0 0 0 0 Always false (always folded)
Definition: InstrTypes.h:680
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition: InstrTypes.h:688
static LLVM_ABI bool isUnordered(Predicate predicate)
Determine if the predicate is an unordered operation.
static LLVM_ABI bool isOrdered(Predicate predicate)
Determine if the predicate is an ordered operation.
This class represents a range of floating-point values.
LLVM_ABI bool isFullSet() const
Return true if this set contains all of the elements possible for this data-type.
static LLVM_ABI ConstantFPRange getNonNaN(const fltSemantics &Sem)
Helper for [-inf, inf] to represent all non-NaN values.
LLVM_ABI const APFloat * getSingleElement(bool ExcludesNaN=false) const
If this set contains a single element, return it, otherwise return null.
static LLVM_ABI ConstantFPRange makeSatisfyingFCmpRegion(FCmpInst::Predicate Pred, const ConstantFPRange &Other)
Produce the largest range such that all values in the returned range satisfy the given predicate with...
LLVM_ABI bool operator==(const ConstantFPRange &CR) const
Return true if this range is equal to another range.
static LLVM_ABI ConstantFPRange getNaNOnly(const fltSemantics &Sem, bool MayBeQNaN, bool MayBeSNaN)
Create a range which only contains NaNs.
LLVM_ABI ConstantFPRange unionWith(const ConstantFPRange &CR) const
Return the smallest range that results from the union of this range with another range.
LLVM_ABI std::optional< bool > getSignBit() const
Return true if the sign bit of all values in this range is 1.
static LLVM_ABI ConstantFPRange makeAllowedFCmpRegion(FCmpInst::Predicate Pred, const ConstantFPRange &Other)
Produce the smallest range such that all values that may satisfy the given predicate with any value c...
LLVM_ABI bool isNaNOnly() const
LLVM_ABI bool isEmptySet() const
Return true if this set contains no members.
static LLVM_ABI ConstantFPRange getFinite(const fltSemantics &Sem)
Helper for (-inf, inf) to represent all finite values.
LLVM_ABI void print(raw_ostream &OS) const
Print out the bounds to a stream.
LLVM_ABI ConstantFPRange intersectWith(const ConstantFPRange &CR) const
Return the range that results from the intersection of this range with another range.
LLVM_ABI void dump() const
Allow printing from a debugger easily.
LLVM_ABI FPClassTest classify() const
Return the FPClassTest which will return true for the value.
LLVM_ABI bool fcmp(FCmpInst::Predicate Pred, const ConstantFPRange &Other) const
Does the predicate Pred hold between ranges this and Other? NOTE: false does not mean that inverse pr...
LLVM_ABI bool contains(const APFloat &Val) const
Return true if the specified value is in the set.
const APFloat & getUpper() const
Return the upper value for this range.
const APFloat & getLower() const
Return the lower value for this range.
static LLVM_ABI std::optional< ConstantFPRange > makeExactFCmpRegion(FCmpInst::Predicate Pred, const APFloat &Other)
Produce the exact range such that all values in the returned range satisfy the given predicate with a...
const fltSemantics & getSemantics() const
Get the semantics of this ConstantFPRange.
LLVM Value Representation.
Definition: Value.h:75
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
LLVM_READONLY APFloat maxnum(const APFloat &A, const APFloat &B)
Implements IEEE-754 2008 maxNum semantics.
Definition: APFloat.h:1598
FPClassTest
Floating-point class tests, supported by 'is_fpclass' intrinsic.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:207
@ Other
Any other memory.
LLVM_READONLY APFloat minnum(const APFloat &A, const APFloat &B)
Implements IEEE-754 2008 minNum semantics.
Definition: APFloat.h:1579
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1886
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:856
cmpResult
IEEE-754R 5.11: Floating Point Comparison Relations.
Definition: APFloat.h:294