Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/IR/ConstantFPRange.cpp
213766 views
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
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"
13
#include <cassert>
14
15
using namespace llvm;
16
17
void 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
25
void 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
33
bool ConstantFPRange::isNaNOnly() const {
34
return Lower.isPosInfinity() && Upper.isNegInfinity();
35
}
36
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;
43
}
44
45
ConstantFPRange::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.
60
static APFloat::cmpResult strictCompare(const APFloat &LHS,
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
71
static bool isNonCanonicalEmptySet(const APFloat &Lower, const APFloat &Upper) {
72
return strictCompare(Lower, Upper) == APFloat::cmpGreaterThan &&
73
!(Lower.isInfinity() && Upper.isInfinity());
74
}
75
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);
80
}
81
}
82
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");
90
}
91
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);
96
}
97
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,
102
MayBeSNaN);
103
}
104
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);
109
}
110
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
163
ConstantFPRange
164
ConstantFPRange::makeAllowedFCmpRegion(FCmpInst::Predicate Pred,
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) {
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
}
219
}
220
221
ConstantFPRange
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());
230
231
switch (Pred) {
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,
240
/*MayBeSNaN=*/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()),
247
Pred);
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:
255
return setNaNField(
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:
261
return setNaNField(
262
extendZeroIfEqual(makeGreaterThan(Other.getUpper(), Pred), Pred), Pred);
263
default:
264
llvm_unreachable("Unexpected predicate");
265
}
266
}
267
268
std::optional<ConstantFPRange>
269
ConstantFPRange::makeExactFCmpRegion(FCmpInst::Predicate Pred,
270
const APFloat &Other) {
271
if ((Pred == FCmpInst::FCMP_UNE || Pred == FCmpInst::FCMP_ONE) &&
272
!Other.isNaN())
273
return std::nullopt;
274
return makeSatisfyingFCmpRegion(Pred, ConstantFPRange(Other));
275
}
276
277
bool ConstantFPRange::fcmp(FCmpInst::Predicate Pred,
278
const ConstantFPRange &Other) const {
279
return makeSatisfyingFCmpRegion(Pred, Other).contains(*this);
280
}
281
282
bool ConstantFPRange::isFullSet() const {
283
return Lower.isNegInfinity() && Upper.isPosInfinity() && MayBeQNaN &&
284
MayBeSNaN;
285
}
286
287
bool ConstantFPRange::isEmptySet() const {
288
return Lower.isPosInfinity() && Upper.isNegInfinity() && !MayBeQNaN &&
289
!MayBeSNaN;
290
}
291
292
bool 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 &&
299
strictCompare(Val, Upper) != APFloat::cmpGreaterThan;
300
}
301
302
bool ConstantFPRange::contains(const ConstantFPRange &CR) const {
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
316
const APFloat *ConstantFPRange::getSingleElement(bool ExcludesNaN) const {
317
if (!ExcludesNaN && (MayBeSNaN || MayBeQNaN))
318
return nullptr;
319
return Lower.bitwiseIsEqual(Upper) ? &Lower : nullptr;
320
}
321
322
std::optional<bool> ConstantFPRange::getSignBit() const {
323
if (!MayBeSNaN && !MayBeQNaN && Lower.isNegative() == Upper.isNegative())
324
return Lower.isNegative();
325
return std::nullopt;
326
}
327
328
bool ConstantFPRange::operator==(const ConstantFPRange &CR) const {
329
if (MayBeSNaN != CR.MayBeSNaN || MayBeQNaN != CR.MayBeQNaN)
330
return false;
331
return Lower.bitwiseIsEqual(CR.Lower) && Upper.bitwiseIsEqual(CR.Upper);
332
}
333
334
FPClassTest ConstantFPRange::classify() const {
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
350
void ConstantFPRange::print(raw_ostream &OS) const {
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)
374
LLVM_DUMP_METHOD void ConstantFPRange::dump() const { print(dbgs()); }
375
#endif
376
377
ConstantFPRange
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);
386
}
387
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);
393
}
394
395