brintos

brintos / llvm-project-archived public Read only

0
0
Text · 25.3 KiB · 5b87686 Raw
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