LLVM 20.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}
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:622
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)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
Value * RHS
Value * LHS
bool bitwiseIsEqual(const APFloat &RHS) const
Definition: APFloat.h:1405
bool isNegative() const
Definition: APFloat.h:1440
bool isPosInfinity() const
Definition: APFloat.h:1453
const fltSemantics & getSemantics() const
Definition: APFloat.h:1448
bool isNaN() const
Definition: APFloat.h:1438
bool isSignaling() const
Definition: APFloat.h:1442
static APFloat getLargest(const fltSemantics &Sem, bool Negative=false)
Returns the largest finite number in the given semantics.
Definition: APFloat.h:1135
static APFloat getInf(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Infinity.
Definition: APFloat.h:1095
FPClassTest classify() const
Return the FPClassTest which will return true for the value.
Definition: APFloat.cpp:5452
bool isNegInfinity() const
Definition: APFloat.h:1454
static APFloat getZero(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Zero.
Definition: APFloat.h:1076
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition: InstrTypes.h:673
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
Definition: InstrTypes.h:676
@ FCMP_TRUE
1 1 1 1 Always true (always folded)
Definition: InstrTypes.h:690
@ FCMP_OLT
0 1 0 0 True if ordered and less than
Definition: InstrTypes.h:679
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
Definition: InstrTypes.h:688
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
Definition: InstrTypes.h:677
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
Definition: InstrTypes.h:678
@ FCMP_ULT
1 1 0 0 True if unordered or less than
Definition: InstrTypes.h:687
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
Definition: InstrTypes.h:681
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
Definition: InstrTypes.h:684
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
Definition: InstrTypes.h:685
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
Definition: InstrTypes.h:680
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
Definition: InstrTypes.h:682
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
Definition: InstrTypes.h:689
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
Definition: InstrTypes.h:686
@ FCMP_FALSE
0 0 0 0 Always false (always folded)
Definition: InstrTypes.h:675
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition: InstrTypes.h:683
static bool isUnordered(Predicate predicate)
Determine if the predicate is an unordered operation.
static bool isOrdered(Predicate predicate)
Determine if the predicate is an ordered operation.
This class represents a range of floating-point values.
bool isFullSet() const
Return true if this set contains all of the elements possible for this data-type.
static ConstantFPRange getNonNaN(const fltSemantics &Sem)
Helper for [-inf, inf] to represent all non-NaN values.
const APFloat * getSingleElement(bool ExcludesNaN=false) const
If this set contains a single element, return it, otherwise return null.
static 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...
bool operator==(const ConstantFPRange &CR) const
Return true if this range is equal to another range.
static ConstantFPRange getNaNOnly(const fltSemantics &Sem, bool MayBeQNaN, bool MayBeSNaN)
Create a range which only contains NaNs.
ConstantFPRange unionWith(const ConstantFPRange &CR) const
Return the smallest range that results from the union of this range with another range.
std::optional< bool > getSignBit() const
Return true if the sign bit of all values in this range is 1.
static 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...
bool isEmptySet() const
Return true if this set contains no members.
static ConstantFPRange getFinite(const fltSemantics &Sem)
Helper for (-inf, inf) to represent all finite values.
void print(raw_ostream &OS) const
Print out the bounds to a stream.
ConstantFPRange intersectWith(const ConstantFPRange &CR) const
Return the range that results from the intersection of this range with another range.
void dump() const
Allow printing from a debugger easily.
FPClassTest classify() const
Return the FPClassTest which will return true for the value.
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...
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 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:74
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
#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 2019 maximumNumber semantics.
Definition: APFloat.h:1558
FPClassTest
Floating-point class tests, supported by 'is_fpclass' intrinsic.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
@ Other
Any other memory.
LLVM_READONLY APFloat minnum(const APFloat &A, const APFloat &B)
Implements IEEE-754 2019 minimumNumber semantics.
Definition: APFloat.h:1544
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:1873
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
cmpResult
IEEE-754R 5.11: Floating Point Comparison Relations.
Definition: APFloat.h:287