675 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/IR/ConstantFPRange.h"10#include "llvm/ADT/APFloat.h"11#include "llvm/ADT/FloatingPointMode.h"12#include "llvm/Support/Debug.h"13#include "llvm/Support/raw_ostream.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 34bool ConstantFPRange::isNaNOnly() const {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.61static APFloat::cmpResult strictCompare(const APFloat &LHS,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) {73 return strictCompare(Lower, Upper) == APFloat::cmpGreaterThan &&74 !(Lower.isInfinity() && Upper.isInfinity());75}76 77static void canonicalizeRange(APFloat &Lower, APFloat &Upper) {78 if (isNonCanonicalEmptySet(Lower, Upper)) {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/OGT113static bool fcmpPredExcludesEqual(FCmpInst::Predicate Pred) {114 return !(Pred & FCmpInst::FCMP_OEQ);115}116 117/// Return [-inf, V) or [-inf, V]118static ConstantFPRange makeLessThan(APFloat V, FCmpInst::Predicate Pred) {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]130static ConstantFPRange makeGreaterThan(APFloat V, FCmpInst::Predicate Pred) {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.142static ConstantFPRange extendZeroIfEqual(const ConstantFPRange &CR,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 157static ConstantFPRange setNaNField(const ConstantFPRange &CR,158 FCmpInst::Predicate Pred) {159 bool ContainsNaN = FCmpInst::isUnordered(Pred);160 return ConstantFPRange(CR.getLower(), CR.getUpper(),161 /*MayBeQNaN=*/ContainsNaN, /*MayBeSNaN=*/ContainsNaN);162}163 164ConstantFPRange165ConstantFPRange::makeAllowedFCmpRegion(FCmpInst::Predicate Pred,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) {175 case FCmpInst::FCMP_TRUE:176 return getFull(Other.getSemantics());177 case FCmpInst::FCMP_FALSE:178 return getEmpty(Other.getSemantics());179 case FCmpInst::FCMP_ORD:180 return getNonNaN(Other.getSemantics());181 case FCmpInst::FCMP_UNO:182 return getNaNOnly(Other.getSemantics(), /*MayBeQNaN=*/true,183 /*MayBeSNaN=*/true);184 case FCmpInst::FCMP_OEQ:185 case FCmpInst::FCMP_UEQ:186 return setNaNField(extendZeroIfEqual(Other, Pred), Pred);187 case FCmpInst::FCMP_ONE:188 case FCmpInst::FCMP_UNE: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());205 case FCmpInst::FCMP_OLT:206 case FCmpInst::FCMP_OLE:207 case FCmpInst::FCMP_ULT:208 case FCmpInst::FCMP_ULE:209 return setNaNField(210 extendZeroIfEqual(makeLessThan(Other.getUpper(), Pred), Pred), Pred);211 case FCmpInst::FCMP_OGT:212 case FCmpInst::FCMP_OGE:213 case FCmpInst::FCMP_UGT:214 case FCmpInst::FCMP_UGE:215 return setNaNField(216 extendZeroIfEqual(makeGreaterThan(Other.getLower(), Pred), Pred), Pred);217 default:218 llvm_unreachable("Unexpected predicate");219 }220}221 222ConstantFPRange223ConstantFPRange::makeSatisfyingFCmpRegion(FCmpInst::Predicate Pred,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) {233 case FCmpInst::FCMP_TRUE:234 return getFull(Other.getSemantics());235 case FCmpInst::FCMP_FALSE:236 return getEmpty(Other.getSemantics());237 case FCmpInst::FCMP_ORD:238 return getNonNaN(Other.getSemantics());239 case FCmpInst::FCMP_UNO:240 return getNaNOnly(Other.getSemantics(), /*MayBeQNaN=*/true,241 /*MayBeSNaN=*/true);242 case FCmpInst::FCMP_OEQ:243 case FCmpInst::FCMP_UEQ:244 return setNaNField(Other.isSingleElement(/*ExcludesNaN=*/true) ||245 ((Other.classify() & ~fcNan) == fcZero)246 ? extendZeroIfEqual(Other, Pred)247 : getEmpty(Other.getSemantics()),248 Pred);249 case FCmpInst::FCMP_ONE:250 case FCmpInst::FCMP_UNE:251 return getEmpty(Other.getSemantics());252 case FCmpInst::FCMP_OLT:253 case FCmpInst::FCMP_OLE:254 case FCmpInst::FCMP_ULT:255 case FCmpInst::FCMP_ULE:256 return setNaNField(257 extendZeroIfEqual(makeLessThan(Other.getLower(), Pred), Pred), Pred);258 case FCmpInst::FCMP_OGT:259 case FCmpInst::FCMP_OGE:260 case FCmpInst::FCMP_UGT:261 case FCmpInst::FCMP_UGE:262 return setNaNField(263 extendZeroIfEqual(makeGreaterThan(Other.getUpper(), Pred), Pred), Pred);264 default:265 llvm_unreachable("Unexpected predicate");266 }267}268 269std::optional<ConstantFPRange>270ConstantFPRange::makeExactFCmpRegion(FCmpInst::Predicate Pred,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 278bool ConstantFPRange::fcmp(FCmpInst::Predicate Pred,279 const ConstantFPRange &Other) const {280 return makeSatisfyingFCmpRegion(Pred, Other).contains(*this);281}282 283bool ConstantFPRange::isFullSet() const {284 return Lower.isNegInfinity() && Upper.isPosInfinity() && MayBeQNaN &&285 MayBeSNaN;286}287 288bool ConstantFPRange::isEmptySet() const {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 &&300 strictCompare(Val, Upper) != 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 337FPClassTest ConstantFPRange::classify() const {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 353void ConstantFPRange::print(raw_ostream &OS) const {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)377LLVM_DUMP_METHOD void ConstantFPRange::dump() const { print(dbgs()); }378#endif379 380ConstantFPRange381ConstantFPRange::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.408 APFloat NewLower = APFloat::getZero(getSemantics());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) {421 assert(strictCompare(Lower, Upper) != APFloat::cmpGreaterThan &&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 }432 return strictCompare(Lower, Upper) != APFloat::cmpGreaterThan;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 = QNaN480 ResMayBeQNaN |=481 (LHSHasNegInf && RHSHasPosInf) || (LHSHasPosInf && RHSHasNegInf);482 // +inf + finite/+inf = +inf, -inf + finite/-inf = -inf483 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 511void ConstantFPRange::flushDenormals(DenormalMode::DenormalModeKind Mode) {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 -> NegZero520 // PositiveZero: PosSubnormal -> PosZero, NegSubnormal -> PosZero521 // Dynamic: PosSubnormal -> PosZero, NegSubnormal -> NegZero/PosZero522 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.533struct SameSignRange {534 bool HasZero;535 bool HasNonZero;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)542 : HasZero(Lower.isZero()), HasNonZero(!Upper.isZero()),543 HasInf(Upper.isInfinity()) {544 assert(!Lower.isNegative() && !Upper.isNegative() &&545 "The sign should be dropped.");546 assert(strictCompare(Lower, Upper) != APFloat::cmpGreaterThan &&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) {558 assert(strictCompare(Lower, Upper) != APFloat::cmpGreaterThan &&559 "Non-NaN part is empty.");560 if (Lower.isNegative() == Upper.isNegative()) {561 if (Lower.isNegative())562 NegPart = SameSignRange{abs(Upper), abs(Lower)};563 else564 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 = QNaN589 ResMayBeQNaN |= LHS->HasZero && RHS->HasInf;590 ResMayBeQNaN |= RHS->HasZero && LHS->HasInf;591 // NonZero * inf = inf592 if ((LHS->HasInf && RHS->HasNonZero) || (RHS->HasInf && LHS->HasNonZero))593 (Negative ? ResLower : ResUpper) = APFloat::getInf(Sem, Negative);594 // Finite * Finite595 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 = QNaN631 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 || HasZero636 // HasNonZero = HasNonZeroFinite || HasInf637 // 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 = inf642 if ((LHS->HasInf && RHS->FinitePart) ||643 (LHSHasNonZeroFinite && RHS->HasZero))644 (Negative ? ResLower : ResUpper) = APFloat::getInf(Sem, Negative);645 // Finite / inf = 0646 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 / FiniteNonZero652 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}675