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"
12#include "llvm/Support/Debug.h"
14#include <cassert>
15
16using namespace llvm;
17
18void ConstantFPRange::makeEmpty() {
19 auto &Sem = Lower.getSemantics();
20 Lower = APFloat::getInf(Sem, /*Negative=*/false);
21 Upper = APFloat::getInf(Sem, /*Negative=*/true);
22 MayBeQNaN = false;
23 MayBeSNaN = false;
24}
25
26void ConstantFPRange::makeFull() {
27 auto &Sem = Lower.getSemantics();
28 Lower = APFloat::getInf(Sem, /*Negative=*/true);
29 Upper = APFloat::getInf(Sem, /*Negative=*/false);
30 MayBeQNaN = true;
31 MayBeSNaN = true;
32}
33
35 return Lower.isPosInfinity() && Upper.isNegInfinity();
36}
37
38ConstantFPRange::ConstantFPRange(const fltSemantics &Sem, bool IsFullSet)
39 : Lower(Sem, APFloat::uninitialized), Upper(Sem, APFloat::uninitialized) {
40 Lower = APFloat::getInf(Sem, /*Negative=*/IsFullSet);
41 Upper = APFloat::getInf(Sem, /*Negative=*/!IsFullSet);
42 MayBeQNaN = IsFullSet;
43 MayBeSNaN = IsFullSet;
44}
45
46ConstantFPRange::ConstantFPRange(const APFloat &Value)
47 : Lower(Value.getSemantics(), APFloat::uninitialized),
48 Upper(Value.getSemantics(), APFloat::uninitialized) {
49 if (Value.isNaN()) {
50 makeEmpty();
51 bool IsSNaN = Value.isSignaling();
52 MayBeQNaN = !IsSNaN;
53 MayBeSNaN = IsSNaN;
54 } else {
55 Lower = Upper = Value;
56 MayBeQNaN = MayBeSNaN = false;
57 }
58}
59
60// We treat that -0 is less than 0 here.
62 const APFloat &RHS) {
63 assert(!LHS.isNaN() && !RHS.isNaN() && "Unordered compare");
64 if (LHS.isZero() && RHS.isZero()) {
65 if (LHS.isNegative() == RHS.isNegative())
66 return APFloat::cmpEqual;
67 return LHS.isNegative() ? APFloat::cmpLessThan : APFloat::cmpGreaterThan;
68 }
69 return LHS.compare(RHS);
70}
71
72static bool isNonCanonicalEmptySet(const APFloat &Lower, const APFloat &Upper) {
74 !(Lower.isInfinity() && Upper.isInfinity());
75}
76
79 Lower = APFloat::getInf(Lower.getSemantics(), /*Negative=*/false);
80 Upper = APFloat::getInf(Upper.getSemantics(), /*Negative=*/true);
81 }
82}
83
84ConstantFPRange::ConstantFPRange(APFloat LowerVal, APFloat UpperVal,
85 bool MayBeQNaNVal, bool MayBeSNaNVal)
86 : Lower(std::move(LowerVal)), Upper(std::move(UpperVal)),
87 MayBeQNaN(MayBeQNaNVal), MayBeSNaN(MayBeSNaNVal) {
88 assert(&Lower.getSemantics() == &Upper.getSemantics() &&
89 "Should only use the same semantics");
90 assert(!isNonCanonicalEmptySet(Lower, Upper) && "Non-canonical form");
91}
92
93ConstantFPRange ConstantFPRange::getFinite(const fltSemantics &Sem) {
94 return ConstantFPRange(APFloat::getLargest(Sem, /*Negative=*/true),
95 APFloat::getLargest(Sem, /*Negative=*/false),
96 /*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
97}
98
99ConstantFPRange ConstantFPRange::getNaNOnly(const fltSemantics &Sem,
100 bool MayBeQNaN, bool MayBeSNaN) {
101 return ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/false),
102 APFloat::getInf(Sem, /*Negative=*/true), MayBeQNaN,
103 MayBeSNaN);
104}
105
106ConstantFPRange ConstantFPRange::getNonNaN(const fltSemantics &Sem) {
107 return ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/true),
108 APFloat::getInf(Sem, /*Negative=*/false),
109 /*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
110}
111
112/// Return true for ULT/UGT/OLT/OGT
114 return !(Pred & FCmpInst::FCMP_OEQ);
115}
116
117/// Return [-inf, V) or [-inf, V]
119 const fltSemantics &Sem = V.getSemantics();
120 if (fcmpPredExcludesEqual(Pred)) {
121 if (V.isNegInfinity())
122 return ConstantFPRange::getEmpty(Sem);
123 V.next(/*nextDown=*/true);
124 }
125 return ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),
126 std::move(V));
127}
128
129/// Return (V, +inf] or [V, +inf]
131 const fltSemantics &Sem = V.getSemantics();
132 if (fcmpPredExcludesEqual(Pred)) {
133 if (V.isPosInfinity())
134 return ConstantFPRange::getEmpty(Sem);
135 V.next(/*nextDown=*/false);
136 }
137 return ConstantFPRange::getNonNaN(std::move(V),
138 APFloat::getInf(Sem, /*Negative=*/false));
139}
140
141/// Make sure that +0/-0 are both included in the range.
143 FCmpInst::Predicate Pred) {
144 if (fcmpPredExcludesEqual(Pred))
145 return CR;
146
147 APFloat Lower = CR.getLower();
148 APFloat Upper = CR.getUpper();
149 if (Lower.isPosZero())
150 Lower = APFloat::getZero(Lower.getSemantics(), /*Negative=*/true);
151 if (Upper.isNegZero())
152 Upper = APFloat::getZero(Upper.getSemantics(), /*Negative=*/false);
153 return ConstantFPRange(std::move(Lower), std::move(Upper), CR.containsQNaN(),
154 CR.containsSNaN());
155}
156
158 FCmpInst::Predicate Pred) {
159 bool ContainsNaN = FCmpInst::isUnordered(Pred);
160 return ConstantFPRange(CR.getLower(), CR.getUpper(),
161 /*MayBeQNaN=*/ContainsNaN, /*MayBeSNaN=*/ContainsNaN);
162}
163
166 const ConstantFPRange &Other) {
167 if (Other.isEmptySet())
168 return Other;
169 if (Other.containsNaN() && FCmpInst::isUnordered(Pred))
170 return getFull(Other.getSemantics());
171 if (Other.isNaNOnly() && FCmpInst::isOrdered(Pred))
172 return getEmpty(Other.getSemantics());
173
174 switch (Pred) {
176 return getFull(Other.getSemantics());
178 return getEmpty(Other.getSemantics());
180 return getNonNaN(Other.getSemantics());
182 return getNaNOnly(Other.getSemantics(), /*MayBeQNaN=*/true,
183 /*MayBeSNaN=*/true);
186 return setNaNField(extendZeroIfEqual(Other, Pred), Pred);
189 if (const APFloat *SingleElement =
190 Other.getSingleElement(/*ExcludesNaN=*/true)) {
191 const fltSemantics &Sem = SingleElement->getSemantics();
192 if (SingleElement->isPosInfinity())
193 return setNaNField(
194 getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),
195 APFloat::getLargest(Sem, /*Negative=*/false)),
196 Pred);
197 if (SingleElement->isNegInfinity())
198 return setNaNField(
199 getNonNaN(APFloat::getLargest(Sem, /*Negative=*/true),
200 APFloat::getInf(Sem, /*Negative=*/false)),
201 Pred);
202 }
203 return Pred == FCmpInst::FCMP_ONE ? getNonNaN(Other.getSemantics())
204 : getFull(Other.getSemantics());
209 return setNaNField(
210 extendZeroIfEqual(makeLessThan(Other.getUpper(), Pred), Pred), Pred);
215 return setNaNField(
216 extendZeroIfEqual(makeGreaterThan(Other.getLower(), Pred), Pred), Pred);
217 default:
218 llvm_unreachable("Unexpected predicate");
219 }
220}
221
224 const ConstantFPRange &Other) {
225 if (Other.isEmptySet())
226 return getFull(Other.getSemantics());
227 if (Other.containsNaN() && FCmpInst::isOrdered(Pred))
228 return getEmpty(Other.getSemantics());
229 if (Other.isNaNOnly() && FCmpInst::isUnordered(Pred))
230 return getFull(Other.getSemantics());
231
232 switch (Pred) {
234 return getFull(Other.getSemantics());
236 return getEmpty(Other.getSemantics());
238 return getNonNaN(Other.getSemantics());
240 return getNaNOnly(Other.getSemantics(), /*MayBeQNaN=*/true,
241 /*MayBeSNaN=*/true);
244 return setNaNField(Other.isSingleElement(/*ExcludesNaN=*/true) ||
245 ((Other.classify() & ~fcNan) == fcZero)
246 ? extendZeroIfEqual(Other, Pred)
247 : getEmpty(Other.getSemantics()),
248 Pred);
251 return getEmpty(Other.getSemantics());
256 return setNaNField(
257 extendZeroIfEqual(makeLessThan(Other.getLower(), Pred), Pred), Pred);
262 return setNaNField(
263 extendZeroIfEqual(makeGreaterThan(Other.getUpper(), Pred), Pred), Pred);
264 default:
265 llvm_unreachable("Unexpected predicate");
266 }
267}
268
269std::optional<ConstantFPRange>
271 const APFloat &Other) {
272 if ((Pred == FCmpInst::FCMP_UNE || Pred == FCmpInst::FCMP_ONE) &&
273 !Other.isNaN())
274 return std::nullopt;
275 return makeSatisfyingFCmpRegion(Pred, ConstantFPRange(Other));
276}
277
279 const ConstantFPRange &Other) const {
280 return makeSatisfyingFCmpRegion(Pred, Other).contains(*this);
281}
282
284 return Lower.isNegInfinity() && Upper.isPosInfinity() && MayBeQNaN &&
285 MayBeSNaN;
286}
287
289 return Lower.isPosInfinity() && Upper.isNegInfinity() && !MayBeQNaN &&
290 !MayBeSNaN;
291}
292
293bool ConstantFPRange::contains(const APFloat &Val) const {
294 assert(&getSemantics() == &Val.getSemantics() &&
295 "Should only use the same semantics");
296
297 if (Val.isNaN())
298 return Val.isSignaling() ? MayBeSNaN : MayBeQNaN;
299 return strictCompare(Lower, Val) != APFloat::cmpGreaterThan &&
301}
302
303bool ConstantFPRange::contains(const ConstantFPRange &CR) const {
304 assert(&getSemantics() == &CR.getSemantics() &&
305 "Should only use the same semantics");
306
307 if (CR.MayBeQNaN && !MayBeQNaN)
308 return false;
309
310 if (CR.MayBeSNaN && !MayBeSNaN)
311 return false;
312
313 return strictCompare(Lower, CR.Lower) != APFloat::cmpGreaterThan &&
314 strictCompare(CR.Upper, Upper) != APFloat::cmpGreaterThan;
315}
316
317const APFloat *ConstantFPRange::getSingleElement(bool ExcludesNaN) const {
318 if (!ExcludesNaN && (MayBeSNaN || MayBeQNaN))
319 return nullptr;
320 return Lower.bitwiseIsEqual(Upper) ? &Lower : nullptr;
321}
322
323std::optional<bool> ConstantFPRange::getSignBit() const {
324 if (!MayBeSNaN && !MayBeQNaN && Lower.isNegative() == Upper.isNegative())
325 return Lower.isNegative();
326 return std::nullopt;
327}
328
329bool ConstantFPRange::operator==(const ConstantFPRange &CR) const {
330 assert(&getSemantics() == &CR.getSemantics() &&
331 "Should only use the same semantics");
332 if (MayBeSNaN != CR.MayBeSNaN || MayBeQNaN != CR.MayBeQNaN)
333 return false;
334 return Lower.bitwiseIsEqual(CR.Lower) && Upper.bitwiseIsEqual(CR.Upper);
335}
336
338 uint32_t Mask = fcNone;
339 if (MayBeSNaN)
340 Mask |= fcSNan;
341 if (MayBeQNaN)
342 Mask |= fcQNan;
343 if (!isNaNOnly()) {
344 FPClassTest LowerMask = Lower.classify();
345 FPClassTest UpperMask = Upper.classify();
346 assert(LowerMask <= UpperMask && "Range is nan-only.");
347 // Set all bits from log2(LowerMask) to log2(UpperMask).
348 Mask |= (UpperMask << 1) - LowerMask;
349 }
350 return static_cast<FPClassTest>(Mask);
351}
352
354 if (isFullSet())
355 OS << "full-set";
356 else if (isEmptySet())
357 OS << "empty-set";
358 else {
359 bool NaNOnly = isNaNOnly();
360 if (!NaNOnly)
361 OS << '[' << Lower << ", " << Upper << ']';
362
363 if (MayBeSNaN || MayBeQNaN) {
364 if (!NaNOnly)
365 OS << " with ";
366 if (MayBeSNaN && MayBeQNaN)
367 OS << "NaN";
368 else if (MayBeSNaN)
369 OS << "SNaN";
370 else if (MayBeQNaN)
371 OS << "QNaN";
372 }
373 }
374}
375
376#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
378#endif
379
381ConstantFPRange::intersectWith(const ConstantFPRange &CR) const {
382 assert(&getSemantics() == &CR.getSemantics() &&
383 "Should only use the same semantics");
384 APFloat NewLower = maxnum(Lower, CR.Lower);
385 APFloat NewUpper = minnum(Upper, CR.Upper);
386 canonicalizeRange(NewLower, NewUpper);
387 return ConstantFPRange(std::move(NewLower), std::move(NewUpper),
388 MayBeQNaN & CR.MayBeQNaN, MayBeSNaN & CR.MayBeSNaN);
389}
390
391ConstantFPRange ConstantFPRange::unionWith(const ConstantFPRange &CR) const {
392 assert(&getSemantics() == &CR.getSemantics() &&
393 "Should only use the same semantics");
394 return ConstantFPRange(minnum(Lower, CR.Lower), maxnum(Upper, CR.Upper),
395 MayBeQNaN | CR.MayBeQNaN, MayBeSNaN | CR.MayBeSNaN);
396}
397
398ConstantFPRange ConstantFPRange::abs() const {
399 if (isNaNOnly())
400 return *this;
401 // Check if the range is all non-negative or all non-positive.
402 if (Lower.isNegative() == Upper.isNegative()) {
403 if (Lower.isNegative())
404 return negate();
405 return *this;
406 }
407 // The range contains both positive and negative values.
409 APFloat NewUpper = maxnum(-Lower, Upper);
410 return ConstantFPRange(std::move(NewLower), std::move(NewUpper), MayBeQNaN,
411 MayBeSNaN);
412}
413
414ConstantFPRange ConstantFPRange::negate() const {
415 return ConstantFPRange(-Upper, -Lower, MayBeQNaN, MayBeSNaN);
416}
417
418/// Return true if the finite part is not empty after removing infinities.
419static bool removeInf(APFloat &Lower, APFloat &Upper, bool &HasPosInf,
420 bool &HasNegInf) {
422 "Non-NaN part is empty.");
423 auto &Sem = Lower.getSemantics();
424 if (Lower.isNegInfinity()) {
425 Lower = APFloat::getLargest(Sem, /*Negative=*/true);
426 HasNegInf = true;
427 }
428 if (Upper.isPosInfinity()) {
429 Upper = APFloat::getLargest(Sem, /*Negative=*/false);
430 HasPosInf = true;
431 }
433}
434
435ConstantFPRange ConstantFPRange::getWithoutInf() const {
436 if (isNaNOnly())
437 return *this;
438 APFloat NewLower = Lower;
439 APFloat NewUpper = Upper;
440 bool UnusedFlag;
441 removeInf(NewLower, NewUpper, /*HasPosInf=*/UnusedFlag,
442 /*HasNegInf=*/UnusedFlag);
443 canonicalizeRange(NewLower, NewUpper);
444 return ConstantFPRange(std::move(NewLower), std::move(NewUpper), MayBeQNaN,
445 MayBeSNaN);
446}
447
448ConstantFPRange ConstantFPRange::cast(const fltSemantics &DstSem,
449 APFloat::roundingMode RM) const {
450 bool LosesInfo;
451 APFloat NewLower = Lower;
452 APFloat NewUpper = Upper;
453 // For conservative, return full range if conversion is invalid.
454 if (NewLower.convert(DstSem, RM, &LosesInfo) == APFloat::opInvalidOp ||
455 NewLower.isNaN())
456 return getFull(DstSem);
457 if (NewUpper.convert(DstSem, RM, &LosesInfo) == APFloat::opInvalidOp ||
458 NewUpper.isNaN())
459 return getFull(DstSem);
460 return ConstantFPRange(std::move(NewLower), std::move(NewUpper),
461 /*MayBeQNaNVal=*/MayBeQNaN || MayBeSNaN,
462 /*MayBeSNaNVal=*/false);
463}
464
465ConstantFPRange ConstantFPRange::add(const ConstantFPRange &Other) const {
466 bool ResMayBeQNaN = ((MayBeQNaN || MayBeSNaN) && !Other.isEmptySet()) ||
467 ((Other.MayBeQNaN || Other.MayBeSNaN) && !isEmptySet());
468 if (isNaNOnly() || Other.isNaNOnly())
469 return getNaNOnly(getSemantics(), /*MayBeQNaN=*/ResMayBeQNaN,
470 /*MayBeSNaN=*/false);
471 bool LHSHasNegInf = false, LHSHasPosInf = false;
472 APFloat LHSLower = Lower, LHSUpper = Upper;
473 bool LHSFiniteIsNonEmpty =
474 removeInf(LHSLower, LHSUpper, LHSHasPosInf, LHSHasNegInf);
475 bool RHSHasNegInf = false, RHSHasPosInf = false;
476 APFloat RHSLower = Other.Lower, RHSUpper = Other.Upper;
477 bool RHSFiniteIsNonEmpty =
478 removeInf(RHSLower, RHSUpper, RHSHasPosInf, RHSHasNegInf);
479 // -inf + +inf = QNaN
480 ResMayBeQNaN |=
481 (LHSHasNegInf && RHSHasPosInf) || (LHSHasPosInf && RHSHasNegInf);
482 // +inf + finite/+inf = +inf, -inf + finite/-inf = -inf
483 bool HasNegInf = (LHSHasNegInf && (RHSFiniteIsNonEmpty || RHSHasNegInf)) ||
484 (RHSHasNegInf && (LHSFiniteIsNonEmpty || LHSHasNegInf));
485 bool HasPosInf = (LHSHasPosInf && (RHSFiniteIsNonEmpty || RHSHasPosInf)) ||
486 (RHSHasPosInf && (LHSFiniteIsNonEmpty || LHSHasPosInf));
487 if (LHSFiniteIsNonEmpty && RHSFiniteIsNonEmpty) {
488 APFloat NewLower =
489 HasNegInf ? APFloat::getInf(LHSLower.getSemantics(), /*Negative=*/true)
490 : LHSLower + RHSLower;
491 APFloat NewUpper =
492 HasPosInf ? APFloat::getInf(LHSUpper.getSemantics(), /*Negative=*/false)
493 : LHSUpper + RHSUpper;
494 return ConstantFPRange(NewLower, NewUpper, ResMayBeQNaN,
495 /*MayBeSNaN=*/false);
496 }
497 // If both HasNegInf and HasPosInf are false, the non-NaN part is empty.
498 // We just return the canonical form [+inf, -inf] for the empty non-NaN set.
499 return ConstantFPRange(
500 APFloat::getInf(Lower.getSemantics(), /*Negative=*/HasNegInf),
501 APFloat::getInf(Upper.getSemantics(), /*Negative=*/!HasPosInf),
502 ResMayBeQNaN,
503 /*MayBeSNaN=*/false);
504}
505
506ConstantFPRange ConstantFPRange::sub(const ConstantFPRange &Other) const {
507 // fsub X, Y = fadd X, (fneg Y)
508 return add(Other.negate());
509}
510
512 if (Mode == DenormalMode::IEEE)
513 return;
514 FPClassTest Class = classify();
515 if (!(Class & fcSubnormal))
516 return;
517
518 auto &Sem = getSemantics();
519 // PreserveSign: PosSubnormal -> PosZero, NegSubnormal -> NegZero
520 // PositiveZero: PosSubnormal -> PosZero, NegSubnormal -> PosZero
521 // Dynamic: PosSubnormal -> PosZero, NegSubnormal -> NegZero/PosZero
522 bool ZeroLowerNegative =
523 Mode != DenormalMode::PositiveZero && (Class & fcNegSubnormal);
524 bool ZeroUpperNegative =
525 Mode == DenormalMode::PreserveSign && !(Class & fcPosSubnormal);
526 assert((ZeroLowerNegative || !ZeroUpperNegative) &&
527 "ZeroLower is greater than ZeroUpper.");
528 Lower = minnum(Lower, APFloat::getZero(Sem, ZeroLowerNegative));
529 Upper = maxnum(Upper, APFloat::getZero(Sem, ZeroUpperNegative));
530}
531
532/// Represent a contiguous range of values sharing the same sign.
536 bool HasInf;
537 // The lower and upper bounds of the range (inclusive).
538 // The sign is dropped and infinities are excluded.
539 std::optional<std::pair<APFloat, APFloat>> FinitePart;
540
541 explicit SameSignRange(const APFloat &Lower, const APFloat &Upper)
543 HasInf(Upper.isInfinity()) {
544 assert(!Lower.isNegative() && !Upper.isNegative() &&
545 "The sign should be dropped.");
547 "Empty set.");
548 if (!Lower.isInfinity())
549 FinitePart = {Lower,
550 HasInf ? APFloat::getLargest(Lower.getSemantics()) : Upper};
551 }
552};
553
554/// Split the range into positive and negative components.
555static void splitPosNeg(const APFloat &Lower, const APFloat &Upper,
556 std::optional<SameSignRange> &NegPart,
557 std::optional<SameSignRange> &PosPart) {
559 "Non-NaN part is empty.");
560 if (Lower.isNegative() == Upper.isNegative()) {
561 if (Lower.isNegative())
562 NegPart = SameSignRange{abs(Upper), abs(Lower)};
563 else
564 PosPart = SameSignRange{Lower, Upper};
565 return;
566 }
567 auto &Sem = Lower.getSemantics();
568 NegPart = SameSignRange{APFloat::getZero(Sem), abs(Lower)};
569 PosPart = SameSignRange{APFloat::getZero(Sem), Upper};
570}
571
572ConstantFPRange ConstantFPRange::mul(const ConstantFPRange &Other) const {
573 auto &Sem = getSemantics();
574 bool ResMayBeQNaN = ((MayBeQNaN || MayBeSNaN) && !Other.isEmptySet()) ||
575 ((Other.MayBeQNaN || Other.MayBeSNaN) && !isEmptySet());
576 if (isNaNOnly() || Other.isNaNOnly())
577 return getNaNOnly(Sem, /*MayBeQNaN=*/ResMayBeQNaN,
578 /*MayBeSNaN=*/false);
579 std::optional<SameSignRange> LHSNeg, LHSPos, RHSNeg, RHSPos;
580 splitPosNeg(Lower, Upper, LHSNeg, LHSPos);
581 splitPosNeg(Other.Lower, Other.Upper, RHSNeg, RHSPos);
582 APFloat ResLower = APFloat::getInf(Sem, /*Negative=*/false);
583 APFloat ResUpper = APFloat::getInf(Sem, /*Negative=*/true);
584 auto Update = [&](std::optional<SameSignRange> &LHS,
585 std::optional<SameSignRange> &RHS, bool Negative) {
586 if (!LHS || !RHS)
587 return;
588 // 0 * inf = QNaN
589 ResMayBeQNaN |= LHS->HasZero && RHS->HasInf;
590 ResMayBeQNaN |= RHS->HasZero && LHS->HasInf;
591 // NonZero * inf = inf
592 if ((LHS->HasInf && RHS->HasNonZero) || (RHS->HasInf && LHS->HasNonZero))
593 (Negative ? ResLower : ResUpper) = APFloat::getInf(Sem, Negative);
594 // Finite * Finite
595 if (LHS->FinitePart && RHS->FinitePart) {
596 APFloat NewLower = LHS->FinitePart->first * RHS->FinitePart->first;
597 APFloat NewUpper = LHS->FinitePart->second * RHS->FinitePart->second;
598 if (Negative) {
599 ResLower = minnum(ResLower, -NewUpper);
600 ResUpper = maxnum(ResUpper, -NewLower);
601 } else {
602 ResLower = minnum(ResLower, NewLower);
603 ResUpper = maxnum(ResUpper, NewUpper);
604 }
605 }
606 };
607 Update(LHSNeg, RHSNeg, /*Negative=*/false);
608 Update(LHSNeg, RHSPos, /*Negative=*/true);
609 Update(LHSPos, RHSNeg, /*Negative=*/true);
610 Update(LHSPos, RHSPos, /*Negative=*/false);
611 return ConstantFPRange(ResLower, ResUpper, ResMayBeQNaN, /*MayBeSNaN=*/false);
612}
613
614ConstantFPRange ConstantFPRange::div(const ConstantFPRange &Other) const {
615 auto &Sem = getSemantics();
616 bool ResMayBeQNaN = ((MayBeQNaN || MayBeSNaN) && !Other.isEmptySet()) ||
617 ((Other.MayBeQNaN || Other.MayBeSNaN) && !isEmptySet());
618 if (isNaNOnly() || Other.isNaNOnly())
619 return getNaNOnly(Sem, /*MayBeQNaN=*/ResMayBeQNaN,
620 /*MayBeSNaN=*/false);
621 std::optional<SameSignRange> LHSNeg, LHSPos, RHSNeg, RHSPos;
622 splitPosNeg(Lower, Upper, LHSNeg, LHSPos);
623 splitPosNeg(Other.Lower, Other.Upper, RHSNeg, RHSPos);
624 APFloat ResLower = APFloat::getInf(Sem, /*Negative=*/false);
625 APFloat ResUpper = APFloat::getInf(Sem, /*Negative=*/true);
626 auto Update = [&](std::optional<SameSignRange> &LHS,
627 std::optional<SameSignRange> &RHS, bool Negative) {
628 if (!LHS || !RHS)
629 return;
630 // inf / inf = QNaN 0 / 0 = QNaN
631 ResMayBeQNaN |= LHS->HasInf && RHS->HasInf;
632 ResMayBeQNaN |= LHS->HasZero && RHS->HasZero;
633 // It is not straightforward to infer HasNonZeroFinite = HasFinite &&
634 // HasNonZero. By definitions we have:
635 // HasFinite = HasNonZeroFinite || HasZero
636 // HasNonZero = HasNonZeroFinite || HasInf
637 // Since the range is contiguous, if both HasFinite and HasNonZero are true,
638 // HasNonZeroFinite must be true.
639 bool LHSHasNonZeroFinite = LHS->FinitePart && LHS->HasNonZero;
640 bool RHSHasNonZeroFinite = RHS->FinitePart && RHS->HasNonZero;
641 // inf / Finite = inf FiniteNonZero / 0 = inf
642 if ((LHS->HasInf && RHS->FinitePart) ||
643 (LHSHasNonZeroFinite && RHS->HasZero))
644 (Negative ? ResLower : ResUpper) = APFloat::getInf(Sem, Negative);
645 // Finite / inf = 0
646 if (LHS->FinitePart && RHS->HasInf) {
647 APFloat Zero = APFloat::getZero(Sem, /*Negative=*/Negative);
648 ResLower = minnum(ResLower, Zero);
649 ResUpper = maxnum(ResUpper, Zero);
650 }
651 // Finite / FiniteNonZero
652 if (LHS->FinitePart && RHSHasNonZeroFinite) {
653 assert(!RHS->FinitePart->second.isZero() &&
654 "Divisor should be non-zero.");
655 APFloat NewLower = LHS->FinitePart->first / RHS->FinitePart->second;
656 APFloat NewUpper = LHS->FinitePart->second /
657 (RHS->FinitePart->first.isZero()
658 ? APFloat::getSmallest(Sem, /*Negative=*/false)
659 : RHS->FinitePart->first);
660 if (Negative) {
661 ResLower = minnum(ResLower, -NewUpper);
662 ResUpper = maxnum(ResUpper, -NewLower);
663 } else {
664 ResLower = minnum(ResLower, NewLower);
665 ResUpper = maxnum(ResUpper, NewUpper);
666 }
667 }
668 };
669 Update(LHSNeg, RHSNeg, /*Negative=*/false);
670 Update(LHSNeg, RHSPos, /*Negative=*/true);
671 Update(LHSPos, RHSNeg, /*Negative=*/true);
672 Update(LHSPos, RHSPos, /*Negative=*/false);
673 return ConstantFPRange(ResLower, ResUpper, ResMayBeQNaN, /*MayBeSNaN=*/false);
674}
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 void splitPosNeg(const APFloat &Lower, const APFloat &Upper, std::optional< SameSignRange > &NegPart, std::optional< SameSignRange > &PosPart)
Split the range into positive and negative components.
static bool removeInf(APFloat &Lower, APFloat &Upper, bool &HasPosInf, bool &HasNegInf)
Return true if the finite part is not empty after removing infinities.
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)
Utilities for dealing with flags related to floating point properties and mode controls.
static bool isZero(Value *V, const DataLayout &DL, DominatorTree *DT, AssumptionCache *AC)
Definition Lint.cpp:539
Value * RHS
Value * LHS
cmpResult
IEEE-754R 5.11: Floating Point Comparison Relations.
Definition APFloat.h:334
llvm::RoundingMode roundingMode
IEEE-754R 4.3: Rounding-direction attributes.
Definition APFloat.h:342
LLVM_ABI opStatus convert(const fltSemantics &ToSemantics, roundingMode RM, bool *losesInfo)
Definition APFloat.cpp:6053
bool bitwiseIsEqual(const APFloat &RHS) const
Definition APFloat.h:1396
const fltSemantics & getSemantics() const
Definition APFloat.h:1439
bool isNaN() const
Definition APFloat.h:1429
bool isSignaling() const
Definition APFloat.h:1433
static APFloat getLargest(const fltSemantics &Sem, bool Negative=false)
Returns the largest finite number in the given semantics.
Definition APFloat.h:1120
static APFloat getInf(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Infinity.
Definition APFloat.h:1080
static APFloat getSmallest(const fltSemantics &Sem, bool Negative=false)
Returns the smallest (by magnitude) finite number in the given semantics.
Definition APFloat.h:1130
static APFloat getZero(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Zero.
Definition APFloat.h:1061
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:676
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
Definition InstrTypes.h:679
@ FCMP_TRUE
1 1 1 1 Always true (always folded)
Definition InstrTypes.h:693
@ FCMP_OLT
0 1 0 0 True if ordered and less than
Definition InstrTypes.h:682
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
Definition InstrTypes.h:691
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
Definition InstrTypes.h:680
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
Definition InstrTypes.h:681
@ FCMP_ULT
1 1 0 0 True if unordered or less than
Definition InstrTypes.h:690
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
Definition InstrTypes.h:684
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
Definition InstrTypes.h:687
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
Definition InstrTypes.h:688
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
Definition InstrTypes.h:683
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
Definition InstrTypes.h:685
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
Definition InstrTypes.h:692
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
Definition InstrTypes.h:689
@ FCMP_FALSE
0 0 0 0 Always false (always folded)
Definition InstrTypes.h:678
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:686
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 ConstantFPRange add(const ConstantFPRange &Other) const
Return a new range representing the possible values resulting from an addition of a value in this ran...
LLVM_ABI ConstantFPRange abs() const
Calculate absolute value range.
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 void flushDenormals(DenormalMode::DenormalModeKind Mode)
Flush denormal values to zero according to the specified mode.
LLVM_ABI ConstantFPRange sub(const ConstantFPRange &Other) const
Return a new range representing the possible values resulting from a subtraction of a value in this r...
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.
LLVM_ABI ConstantFPRange mul(const ConstantFPRange &Other) const
Return a new range representing the possible values resulting from a multiplication of a value in thi...
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 cast(const fltSemantics &DstSem, APFloat::roundingMode RM=APFloat::rmNearestTiesToEven) const
Return a new range in the specified format with the specified rounding mode.
LLVM_ABI ConstantFPRange intersectWith(const ConstantFPRange &CR) const
Return the range that results from the intersection of this range with another range.
LLVM_ABI ConstantFPRange div(const ConstantFPRange &Other) const
Return a new range representing the possible values resulting from a division of a value in this rang...
LLVM_ABI void dump() const
Allow printing from a debugger easily.
LLVM_ABI ConstantFPRange negate() const
Calculate range of negated values.
LLVM_ABI FPClassTest classify() const
Return the FPClassTest which will return true for the value.
LLVM_ABI ConstantFPRange getWithoutInf() const
Get the range without infinities.
LLVM_ABI bool fcmp(FCmpInst::Predicate Pred, const ConstantFPRange &Other) const
Does the predicate Pred hold between ranges this and Other?
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 Types.h:26
APFloat abs(APFloat X)
Returns the absolute value of the argument.
Definition APFloat.h:1545
LLVM_READONLY APFloat maxnum(const APFloat &A, const APFloat &B)
Implements IEEE-754 2008 maxNum semantics.
Definition APFloat.h:1580
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.
Definition ModRef.h:68
LLVM_READONLY APFloat minnum(const APFloat &A, const APFloat &B)
Implements IEEE-754 2008 minNum semantics.
Definition APFloat.h:1561
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:1915
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:870
Represent a contiguous range of values sharing the same sign.
SameSignRange(const APFloat &Lower, const APFloat &Upper)
std::optional< std::pair< APFloat, APFloat > > FinitePart
DenormalModeKind
Represent handled modes for denormal (aka subnormal) modes in the floating point environment.
@ PreserveSign
The sign of a flushed-to-zero number is preserved in the sign of 0.
@ PositiveZero
Denormals are flushed to positive zero.
@ IEEE
IEEE-754 denormal numbers preserved.