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
LLVM_ABI opStatus convert(const fltSemantics &ToSemantics, roundingMode RM, bool *losesInfo)
Definition APFloat.cpp:6057
bool bitwiseIsEqual(const APFloat &RHS) const
Definition APFloat.h:1414
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
static APFloat getSmallest(const fltSemantics &Sem, bool Negative=false)
Returns the smallest (by magnitude) finite number in the given semantics.
Definition APFloat.h:1148
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: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.
APFloat abs(APFloat X)
Returns the absolute value of the argument.
Definition APFloat.h:1563
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.
Definition ModRef.h:68
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:1867
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:867
Represent a contiguous range of values sharing the same sign.
SameSignRange(const APFloat &Lower, const APFloat &Upper)
std::optional< std::pair< APFloat, APFloat > > FinitePart
cmpResult
IEEE-754R 5.11: Floating Point Comparison Relations.
Definition APFloat.h:294
llvm::RoundingMode roundingMode
IEEE-754R 4.3: Rounding-direction attributes.
Definition APFloat.h:302
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.