brintos

brintos / llvm-project-archived public Read only

0
0
Text · 50.3 KiB · 67fee96 Raw
1245 lines · cpp
1//===- ConstantRangeTest.cpp - ConstantRange tests ------------------------===//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/IR/Instructions.h"13#include "llvm/IR/Operator.h"14#include "gtest/gtest.h"15 16using namespace llvm;17 18namespace {19 20class ConstantFPRangeTest : public ::testing::Test {21protected:22  static const fltSemantics &Sem;23  static ConstantFPRange Full;24  static ConstantFPRange Empty;25  static ConstantFPRange Finite;26  static ConstantFPRange NonNaN;27  static ConstantFPRange One;28  static ConstantFPRange PosZero;29  static ConstantFPRange NegZero;30  static ConstantFPRange Zero;31  static ConstantFPRange PosInf;32  static ConstantFPRange NegInf;33  static ConstantFPRange Denormal;34  static ConstantFPRange NaN;35  static ConstantFPRange SNaN;36  static ConstantFPRange QNaN;37  static ConstantFPRange Some;38  static ConstantFPRange SomePos;39  static ConstantFPRange SomeNeg;40};41 42const fltSemantics &ConstantFPRangeTest::Sem = APFloat::IEEEdouble();43ConstantFPRange ConstantFPRangeTest::Full =44    ConstantFPRange::getFull(APFloat::IEEEdouble());45ConstantFPRange ConstantFPRangeTest::Empty =46    ConstantFPRange::getEmpty(APFloat::IEEEdouble());47ConstantFPRange ConstantFPRangeTest::Finite =48    ConstantFPRange::getFinite(APFloat::IEEEdouble());49ConstantFPRange ConstantFPRangeTest::NonNaN =50    ConstantFPRange::getNonNaN(APFloat::IEEEdouble());51ConstantFPRange ConstantFPRangeTest::One = ConstantFPRange(APFloat(1.0));52ConstantFPRange ConstantFPRangeTest::PosZero = ConstantFPRange(53    APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/false));54ConstantFPRange ConstantFPRangeTest::NegZero =55    ConstantFPRange(APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/true));56ConstantFPRange ConstantFPRangeTest::Zero = ConstantFPRange::getNonNaN(57    APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/true),58    APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/false));59ConstantFPRange ConstantFPRangeTest::Denormal =60    ConstantFPRange(APFloat::getSmallest(APFloat::IEEEdouble()));61ConstantFPRange ConstantFPRangeTest::PosInf =62    ConstantFPRange(APFloat::getInf(APFloat::IEEEdouble(), /*Negative=*/false));63ConstantFPRange ConstantFPRangeTest::NegInf =64    ConstantFPRange(APFloat::getInf(APFloat::IEEEdouble(), /*Negative=*/true));65ConstantFPRange ConstantFPRangeTest::NaN = ConstantFPRange::getNaNOnly(66    APFloat::IEEEdouble(), /*MayBeQNaN=*/true, /*MayBeSNaN=*/true);67ConstantFPRange ConstantFPRangeTest::SNaN =68    ConstantFPRange(APFloat::getSNaN(APFloat::IEEEdouble()));69ConstantFPRange ConstantFPRangeTest::QNaN =70    ConstantFPRange(APFloat::getQNaN(APFloat::IEEEdouble()));71ConstantFPRange ConstantFPRangeTest::Some =72    ConstantFPRange::getNonNaN(APFloat(-3.0), APFloat(3.0));73ConstantFPRange ConstantFPRangeTest::SomePos = ConstantFPRange::getNonNaN(74    APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/false), APFloat(3.0));75ConstantFPRange ConstantFPRangeTest::SomeNeg = ConstantFPRange::getNonNaN(76    APFloat(-3.0), APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/true));77 78static void strictNext(APFloat &V) {79  // Note: nextUp(+/-0) is smallest.80  if (V.isNegZero())81    V = APFloat::getZero(V.getSemantics(), /*Negative=*/false);82  else83    V.next(/*nextDown=*/false);84}85 86enum class SparseLevel {87  Dense,88  SpecialValuesWithAllPowerOfTwos,89  SpecialValuesOnly,90};91 92template <typename Fn>93static void EnumerateConstantFPRangesImpl(Fn TestFn, SparseLevel Level,94                                          bool MayBeQNaN, bool MayBeSNaN) {95  const fltSemantics &Sem = APFloat::Float8E4M3();96  APFloat PosInf = APFloat::getInf(Sem, /*Negative=*/false);97  APFloat NegInf = APFloat::getInf(Sem, /*Negative=*/true);98  TestFn(ConstantFPRange(PosInf, NegInf, MayBeQNaN, MayBeSNaN));99 100  if (Level != SparseLevel::Dense) {101    SmallVector<APFloat, 36> Values;102    Values.push_back(APFloat::getInf(Sem, /*Negative=*/true));103    Values.push_back(APFloat::getLargest(Sem, /*Negative=*/true));104    unsigned BitWidth = APFloat::semanticsSizeInBits(Sem);105    unsigned Exponents = APFloat::semanticsMaxExponent(Sem) -106                         APFloat::semanticsMinExponent(Sem) + 3;107    unsigned MantissaBits = APFloat::semanticsPrecision(Sem) - 1;108    if (Level == SparseLevel::SpecialValuesWithAllPowerOfTwos) {109      // Add -2^(max exponent), -2^(max exponent-1), ..., -2^(min exponent)110      for (unsigned M = Exponents - 2; M != 0; --M)111        Values.push_back(112            APFloat(Sem, APInt(BitWidth, (M + Exponents) << MantissaBits)));113    }114    Values.push_back(APFloat::getSmallestNormalized(Sem, /*Negative=*/true));115    Values.push_back(APFloat::getSmallest(Sem, /*Negative=*/true));116    Values.push_back(APFloat::getZero(Sem, /*Negative=*/true));117    size_t E = Values.size();118    for (size_t I = 1; I <= E; ++I)119      Values.push_back(-Values[E - I]);120    for (size_t I = 0; I != Values.size(); ++I)121      for (size_t J = I; J != Values.size(); ++J)122        TestFn(ConstantFPRange(Values[I], Values[J], MayBeQNaN, MayBeSNaN));123    return;124  }125 126  auto Next = [&](APFloat &V) {127    if (V.isPosInfinity())128      return false;129    strictNext(V);130    return true;131  };132 133  APFloat Lower = NegInf;134  do {135    APFloat Upper = Lower;136    do {137      TestFn(ConstantFPRange(Lower, Upper, MayBeQNaN, MayBeSNaN));138    } while (Next(Upper));139  } while (Next(Lower));140}141 142template <typename Fn>143static void EnumerateConstantFPRanges(Fn TestFn, SparseLevel Level,144                                      bool IgnoreSNaNs = false) {145  EnumerateConstantFPRangesImpl(TestFn, Level, /*MayBeQNaN=*/false,146                                /*MayBeSNaN=*/false);147  EnumerateConstantFPRangesImpl(TestFn, Level, /*MayBeQNaN=*/true,148                                /*MayBeSNaN=*/false);149  if (IgnoreSNaNs)150    return;151  EnumerateConstantFPRangesImpl(TestFn, Level, /*MayBeQNaN=*/false,152                                /*MayBeSNaN=*/true);153  EnumerateConstantFPRangesImpl(TestFn, Level, /*MayBeQNaN=*/true,154                                /*MayBeSNaN=*/true);155}156 157template <typename Fn>158static void EnumerateTwoInterestingConstantFPRanges(Fn TestFn,159                                                    SparseLevel Level) {160  EnumerateConstantFPRanges(161      [&](const ConstantFPRange &CR1) {162        EnumerateConstantFPRanges(163            [&](const ConstantFPRange &CR2) { TestFn(CR1, CR2); }, Level,164            /*IgnoreSNaNs=*/true);165      },166      Level, /*IgnoreSNaNs=*/true);167}168 169template <typename Fn>170static void EnumerateValuesInConstantFPRange(const ConstantFPRange &CR,171                                             Fn TestFn, bool IgnoreNaNPayload) {172  const fltSemantics &Sem = CR.getSemantics();173  if (IgnoreNaNPayload) {174    if (CR.containsSNaN()) {175      TestFn(APFloat::getSNaN(Sem, false));176      TestFn(APFloat::getSNaN(Sem, true));177    }178    if (CR.containsQNaN()) {179      TestFn(APFloat::getQNaN(Sem, false));180      TestFn(APFloat::getQNaN(Sem, true));181    }182    if (CR.isNaNOnly())183      return;184    APFloat Lower = CR.getLower();185    const APFloat &Upper = CR.getUpper();186    auto Next = [&](APFloat &V) {187      if (V.bitwiseIsEqual(Upper))188        return false;189      strictNext(V);190      return true;191    };192    do193      TestFn(Lower);194    while (Next(Lower));195  } else {196    unsigned Bits = APFloat::semanticsSizeInBits(Sem);197    assert(Bits < 32 && "Too many bits");198    for (unsigned I = 0, E = (1U << Bits) - 1; I != E; ++I) {199      APFloat V(Sem, APInt(Bits, I));200      if (CR.contains(V))201        TestFn(V);202    }203  }204}205 206template <typename Fn>207static bool AnyOfValueInConstantFPRange(const ConstantFPRange &CR, Fn TestFn,208                                        bool IgnoreNaNPayload) {209  const fltSemantics &Sem = CR.getSemantics();210  if (IgnoreNaNPayload) {211    if (CR.containsSNaN()) {212      if (TestFn(APFloat::getSNaN(Sem, false)))213        return true;214      if (TestFn(APFloat::getSNaN(Sem, true)))215        return true;216    }217    if (CR.containsQNaN()) {218      if (TestFn(APFloat::getQNaN(Sem, false)))219        return true;220      if (TestFn(APFloat::getQNaN(Sem, true)))221        return true;222    }223    if (CR.isNaNOnly())224      return false;225    APFloat Lower = CR.getLower();226    const APFloat &Upper = CR.getUpper();227    auto Next = [&](APFloat &V) {228      if (V.bitwiseIsEqual(Upper))229        return false;230      strictNext(V);231      return true;232    };233    do {234      if (TestFn(Lower))235        return true;236    } while (Next(Lower));237  } else {238    unsigned Bits = APFloat::semanticsSizeInBits(Sem);239    assert(Bits < 32 && "Too many bits");240    for (unsigned I = 0, E = (1U << Bits) - 1; I != E; ++I) {241      APFloat V(Sem, APInt(Bits, I));242      if (CR.contains(V) && TestFn(V))243        return true;244    }245  }246  return false;247}248 249TEST_F(ConstantFPRangeTest, Basics) {250  EXPECT_TRUE(Full.isFullSet());251  EXPECT_FALSE(Full.isEmptySet());252  EXPECT_TRUE(Full.contains(APFloat::getNaN(Sem)));253  EXPECT_TRUE(Full.contains(APFloat::getInf(Sem, /*Negative=*/false)));254  EXPECT_TRUE(Full.contains(APFloat::getInf(Sem, /*Negative=*/true)));255  EXPECT_TRUE(Full.contains(APFloat::getZero(Sem, /*Negative=*/false)));256  EXPECT_TRUE(Full.contains(APFloat::getZero(Sem, /*Negative=*/true)));257  EXPECT_TRUE(Full.contains(APFloat::getSmallest(Sem)));258  EXPECT_TRUE(Full.contains(APFloat(2.0)));259  EXPECT_TRUE(Full.contains(Full));260  EXPECT_TRUE(Full.contains(Empty));261  EXPECT_TRUE(Full.contains(Finite));262  EXPECT_TRUE(Full.contains(Zero));263  EXPECT_TRUE(Full.contains(Some));264 265  EXPECT_FALSE(Empty.isFullSet());266  EXPECT_TRUE(Empty.isEmptySet());267  EXPECT_FALSE(Empty.contains(APFloat::getNaN(Sem)));268  EXPECT_FALSE(Empty.contains(APFloat::getInf(Sem, /*Negative=*/false)));269  EXPECT_FALSE(Empty.contains(APFloat::getZero(Sem, /*Negative=*/true)));270  EXPECT_FALSE(Empty.contains(APFloat(2.0)));271  EXPECT_TRUE(Empty.contains(Empty));272 273  EXPECT_FALSE(Finite.isFullSet());274  EXPECT_FALSE(Finite.isEmptySet());275  EXPECT_FALSE(Finite.contains(APFloat::getNaN(Sem)));276  EXPECT_FALSE(Finite.contains(APFloat::getInf(Sem, /*Negative=*/false)));277  EXPECT_FALSE(Finite.contains(APFloat::getInf(Sem, /*Negative=*/true)));278  EXPECT_TRUE(Finite.contains(APFloat::getLargest(Sem, /*Negative=*/false)));279  EXPECT_TRUE(Finite.contains(APFloat::getLargest(Sem, /*Negative=*/true)));280  EXPECT_TRUE(Finite.contains(Finite));281  EXPECT_TRUE(Finite.contains(Some));282  EXPECT_TRUE(Finite.contains(Denormal));283  EXPECT_TRUE(Finite.contains(Zero));284  EXPECT_FALSE(Finite.contains(PosInf));285  EXPECT_FALSE(Finite.contains(NaN));286 287  EXPECT_TRUE(One.contains(APFloat(1.0)));288  EXPECT_FALSE(One.contains(APFloat(1.1)));289 290  EXPECT_TRUE(PosZero.contains(APFloat::getZero(Sem, /*Negative=*/false)));291  EXPECT_FALSE(PosZero.contains(APFloat::getZero(Sem, /*Negative=*/true)));292  EXPECT_TRUE(NegZero.contains(APFloat::getZero(Sem, /*Negative=*/true)));293  EXPECT_FALSE(NegZero.contains(APFloat::getZero(Sem, /*Negative=*/false)));294  EXPECT_TRUE(Zero.contains(PosZero));295  EXPECT_TRUE(Zero.contains(NegZero));296  EXPECT_TRUE(Denormal.contains(APFloat::getSmallest(Sem)));297  EXPECT_FALSE(Denormal.contains(APFloat::getSmallestNormalized(Sem)));298  EXPECT_TRUE(PosInf.contains(APFloat::getInf(Sem, /*Negative=*/false)));299  EXPECT_TRUE(NegInf.contains(APFloat::getInf(Sem, /*Negative=*/true)));300  EXPECT_TRUE(NaN.contains(APFloat::getQNaN(Sem)));301  EXPECT_TRUE(NaN.contains(APFloat::getSNaN(Sem)));302  EXPECT_TRUE(NaN.contains(SNaN));303  EXPECT_TRUE(NaN.contains(QNaN));304 305  EXPECT_TRUE(Some.contains(APFloat(3.0)));306  EXPECT_TRUE(Some.contains(APFloat(-3.0)));307  EXPECT_FALSE(Some.contains(APFloat(4.0)));308  APFloat Next1(3.0);309  Next1.next(/*nextDown=*/true);310  EXPECT_TRUE(Some.contains(Next1));311  APFloat Next2(3.0);312  Next2.next(/*nextDown=*/false);313  EXPECT_FALSE(Some.contains(Next2));314  EXPECT_TRUE(Some.contains(Zero));315  EXPECT_TRUE(Some.contains(Some));316  EXPECT_TRUE(Some.contains(One));317  EXPECT_FALSE(Some.contains(NaN));318  EXPECT_FALSE(Some.contains(PosInf));319  EXPECT_TRUE(SomePos.contains(APFloat(3.0)));320  EXPECT_FALSE(SomeNeg.contains(APFloat(3.0)));321  EXPECT_TRUE(SomeNeg.contains(APFloat(-3.0)));322  EXPECT_FALSE(SomePos.contains(APFloat(-3.0)));323  EXPECT_TRUE(Some.contains(SomePos));324  EXPECT_TRUE(Some.contains(SomeNeg));325}326 327TEST_F(ConstantFPRangeTest, Equality) {328  EXPECT_EQ(Full, Full);329  EXPECT_EQ(Empty, Empty);330  EXPECT_EQ(One, One);331  EXPECT_EQ(Some, Some);332  EXPECT_NE(Full, Empty);333  EXPECT_NE(Zero, PosZero);334  EXPECT_NE(One, NaN);335  EXPECT_NE(Some, One);336  EXPECT_NE(SNaN, QNaN);337}338 339TEST_F(ConstantFPRangeTest, SingleElement) {340  EXPECT_EQ(Full.getSingleElement(), static_cast<APFloat *>(nullptr));341  EXPECT_EQ(Empty.getSingleElement(), static_cast<APFloat *>(nullptr));342  EXPECT_EQ(Finite.getSingleElement(), static_cast<APFloat *>(nullptr));343  EXPECT_EQ(Zero.getSingleElement(), static_cast<APFloat *>(nullptr));344  EXPECT_EQ(NaN.getSingleElement(), static_cast<APFloat *>(nullptr));345  EXPECT_EQ(SNaN.getSingleElement(), static_cast<APFloat *>(nullptr));346  EXPECT_EQ(QNaN.getSingleElement(), static_cast<APFloat *>(nullptr));347 348  EXPECT_EQ(*One.getSingleElement(), APFloat(1.0));349  EXPECT_EQ(*PosZero.getSingleElement(), APFloat::getZero(Sem));350  EXPECT_EQ(*PosInf.getSingleElement(), APFloat::getInf(Sem));351  ConstantFPRange PosZeroOrNaN = PosZero.unionWith(NaN);352  EXPECT_EQ(*PosZeroOrNaN.getSingleElement(/*ExcludesNaN=*/true),353            APFloat::getZero(Sem));354 355  EXPECT_FALSE(Full.isSingleElement());356  EXPECT_FALSE(Empty.isSingleElement());357  EXPECT_TRUE(One.isSingleElement());358  EXPECT_FALSE(Some.isSingleElement());359  EXPECT_FALSE(Zero.isSingleElement());360  EXPECT_TRUE(PosZeroOrNaN.isSingleElement(/*ExcludesNaN=*/true));361}362 363TEST_F(ConstantFPRangeTest, ExhaustivelyEnumerate) {364  constexpr unsigned NNaNValues = (1 << 8) - 2 * ((1 << 3) - 1);365  constexpr unsigned Expected = 4 * ((NNaNValues + 1) * NNaNValues / 2 + 1);366  unsigned Count = 0;367  EnumerateConstantFPRanges([&](const ConstantFPRange &) { ++Count; },368                            SparseLevel::Dense);369  EXPECT_EQ(Expected, Count);370}371 372TEST_F(ConstantFPRangeTest, Enumerate) {373  constexpr unsigned NNaNValues = 2 * ((1 << 4) - 2 + 5);374  constexpr unsigned Expected = 4 * ((NNaNValues + 1) * NNaNValues / 2 + 1);375  unsigned Count = 0;376  EnumerateConstantFPRanges([&](const ConstantFPRange &) { ++Count; },377                            SparseLevel::SpecialValuesWithAllPowerOfTwos);378  EXPECT_EQ(Expected, Count);379}380 381TEST_F(ConstantFPRangeTest, EnumerateWithSpecialValuesOnly) {382  constexpr unsigned NNaNValues = 2 * 5;383  constexpr unsigned Expected = 4 * ((NNaNValues + 1) * NNaNValues / 2 + 1);384  unsigned Count = 0;385  EnumerateConstantFPRanges([&](const ConstantFPRange &) { ++Count; },386                            SparseLevel::SpecialValuesOnly);387  EXPECT_EQ(Expected, Count);388}389 390TEST_F(ConstantFPRangeTest, IntersectWith) {391  EXPECT_EQ(Empty.intersectWith(Full), Empty);392  EXPECT_EQ(Empty.intersectWith(Empty), Empty);393  EXPECT_EQ(Empty.intersectWith(One), Empty);394  EXPECT_EQ(Empty.intersectWith(Some), Empty);395  EXPECT_EQ(Full.intersectWith(Full), Full);396  EXPECT_EQ(Some.intersectWith(Some), Some);397  EXPECT_EQ(Some.intersectWith(One), One);398  EXPECT_EQ(Full.intersectWith(One), One);399  EXPECT_EQ(Full.intersectWith(Some), Some);400  EXPECT_EQ(Some.intersectWith(SomePos), SomePos);401  EXPECT_EQ(Some.intersectWith(SomeNeg), SomeNeg);402  EXPECT_EQ(NaN.intersectWith(Finite), Empty);403  EXPECT_EQ(NaN.intersectWith(SNaN), SNaN);404  EXPECT_EQ(NaN.intersectWith(QNaN), QNaN);405  EXPECT_EQ(Finite.intersectWith(One), One);406  EXPECT_EQ(Some.intersectWith(Zero), Zero);407  EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(4.0))408                .intersectWith(409                    ConstantFPRange::getNonNaN(APFloat(3.0), APFloat(6.0))),410            ConstantFPRange::getNonNaN(APFloat(3.0), APFloat(4.0)));411  EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))412                .intersectWith(413                    ConstantFPRange::getNonNaN(APFloat(5.0), APFloat(6.0))),414            Empty);415}416 417TEST_F(ConstantFPRangeTest, UnionWith) {418  EXPECT_EQ(Empty.unionWith(Full), Full);419  EXPECT_EQ(Empty.unionWith(Empty), Empty);420  EXPECT_EQ(Empty.unionWith(One), One);421  EXPECT_EQ(Empty.unionWith(Some), Some);422  EXPECT_EQ(Full.unionWith(Full), Full);423  EXPECT_EQ(Some.unionWith(Some), Some);424  EXPECT_EQ(Some.unionWith(One), Some);425  EXPECT_EQ(Full.unionWith(Some), Full);426  EXPECT_EQ(Some.unionWith(SomePos), Some);427  EXPECT_EQ(Some.unionWith(SomeNeg), Some);428  EXPECT_EQ(Finite.unionWith(One), Finite);429  EXPECT_EQ(Some.unionWith(Zero), Some);430  EXPECT_EQ(Finite.unionWith(PosInf).unionWith(NegInf).unionWith(NaN), Full);431  EXPECT_EQ(PosZero.unionWith(NegZero), Zero);432  EXPECT_EQ(NaN.unionWith(SNaN), NaN);433  EXPECT_EQ(NaN.unionWith(QNaN), NaN);434  EXPECT_EQ(SNaN.unionWith(QNaN), NaN);435  EXPECT_EQ(436      ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(4.0))437          .unionWith(ConstantFPRange::getNonNaN(APFloat(3.0), APFloat(6.0))),438      ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(6.0)));439  EXPECT_EQ(440      ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))441          .unionWith(ConstantFPRange::getNonNaN(APFloat(5.0), APFloat(6.0))),442      ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(6.0)));443}444 445TEST_F(ConstantFPRangeTest, FPClassify) {446  EXPECT_EQ(Empty.classify(), fcNone);447  EXPECT_EQ(Full.classify(), fcAllFlags);448  EXPECT_EQ(Finite.classify(), fcFinite);449  EXPECT_EQ(Zero.classify(), fcZero);450  EXPECT_EQ(NaN.classify(), fcNan);451  EXPECT_EQ(SNaN.classify(), fcSNan);452  EXPECT_EQ(QNaN.classify(), fcQNan);453  EXPECT_EQ(One.classify(), fcPosNormal);454  EXPECT_EQ(Some.classify(), fcFinite);455  EXPECT_EQ(SomePos.classify(), fcPosFinite);456  EXPECT_EQ(SomeNeg.classify(), fcNegFinite);457  EXPECT_EQ(PosInf.classify(), fcPosInf);458  EXPECT_EQ(NegInf.classify(), fcNegInf);459  EXPECT_EQ(Finite.getSignBit(), std::nullopt);460  EXPECT_EQ(PosZero.getSignBit(), false);461  EXPECT_EQ(NegZero.getSignBit(), true);462  EXPECT_EQ(SomePos.getSignBit(), false);463  EXPECT_EQ(SomeNeg.getSignBit(), true);464 465#if defined(EXPENSIVE_CHECKS)466  EnumerateConstantFPRanges(467      [](const ConstantFPRange &CR) {468        unsigned Mask = fcNone;469        bool HasPos = false, HasNeg = false;470        EnumerateValuesInConstantFPRange(471            CR,472            [&](const APFloat &V) {473              Mask |= V.classify();474              if (V.isNegative())475                HasNeg = true;476              else477                HasPos = true;478            },479            /*IgnoreNaNPayload=*/true);480 481        std::optional<bool> SignBit = std::nullopt;482        if (HasPos != HasNeg)483          SignBit = HasNeg;484 485        EXPECT_EQ(SignBit, CR.getSignBit()) << CR;486        EXPECT_EQ(Mask, CR.classify()) << CR;487      },488      SparseLevel::Dense);489#endif490}491 492TEST_F(ConstantFPRangeTest, Print) {493  auto ToString = [](const ConstantFPRange &CR) {494    std::string Str;495    raw_string_ostream OS(Str);496    CR.print(OS);497    return Str;498  };499 500  EXPECT_EQ(ToString(Full), "full-set");501  EXPECT_EQ(ToString(Empty), "empty-set");502  EXPECT_EQ(ToString(NaN), "NaN");503  EXPECT_EQ(ToString(SNaN), "SNaN");504  EXPECT_EQ(ToString(QNaN), "QNaN");505  EXPECT_EQ(ToString(One), "[1, 1]");506  EXPECT_EQ(ToString(Some.unionWith(SNaN)), "[-3, 3] with SNaN");507}508 509#ifdef GTEST_HAS_DEATH_TEST510#ifndef NDEBUG511TEST_F(ConstantFPRangeTest, NonCanonicalEmptySet) {512  EXPECT_DEATH((void)(ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(0.0))),513               "Non-canonical form");514}515TEST_F(ConstantFPRangeTest, MismatchedSemantics) {516  EXPECT_DEATH((void)(ConstantFPRange::getNonNaN(APFloat(0.0), APFloat(1.0f))),517               "Should only use the same semantics");518  EXPECT_DEATH((void)(One.contains(APFloat(1.0f))),519               "Should only use the same semantics");520  ConstantFPRange OneF32 = ConstantFPRange(APFloat(1.0f));521  EXPECT_DEATH((void)(One.contains(OneF32)),522               "Should only use the same semantics");523  EXPECT_DEATH((void)(One.intersectWith(OneF32)),524               "Should only use the same semantics");525  EXPECT_DEATH((void)(One.unionWith(OneF32)),526               "Should only use the same semantics");527}528#endif529#endif530 531TEST_F(ConstantFPRangeTest, makeAllowedFCmpRegion) {532  EXPECT_EQ(ConstantFPRange::makeAllowedFCmpRegion(533                FCmpInst::FCMP_OLE,534                ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))),535            ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),536                                       APFloat(2.0)));537  EXPECT_EQ(538      ConstantFPRange::makeAllowedFCmpRegion(539          FCmpInst::FCMP_OLT,540          ConstantFPRange::getNonNaN(APFloat(1.0),541                                     APFloat::getInf(Sem, /*Negative=*/false))),542      ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),543                                 APFloat::getLargest(Sem, /*Negative=*/false)));544  EXPECT_EQ(545      ConstantFPRange::makeAllowedFCmpRegion(546          FCmpInst::FCMP_OGT,547          ConstantFPRange::getNonNaN(APFloat::getZero(Sem, /*Negative=*/true),548                                     APFloat(2.0))),549      ConstantFPRange::getNonNaN(APFloat::getSmallest(Sem, /*Negative=*/false),550                                 APFloat::getInf(Sem, /*Negative=*/false)));551  EXPECT_EQ(ConstantFPRange::makeAllowedFCmpRegion(552                FCmpInst::FCMP_OGE,553                ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))),554            ConstantFPRange::getNonNaN(555                APFloat(1.0), APFloat::getInf(Sem, /*Negative=*/false)));556  EXPECT_EQ(ConstantFPRange::makeAllowedFCmpRegion(557                FCmpInst::FCMP_OEQ,558                ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))),559            ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0)));560 561#if defined(EXPENSIVE_CHECKS)562  for (auto Pred : FCmpInst::predicates()) {563    EnumerateConstantFPRanges(564        [Pred](const ConstantFPRange &CR) {565          ConstantFPRange Res =566              ConstantFPRange::makeAllowedFCmpRegion(Pred, CR);567          ConstantFPRange Optimal =568              ConstantFPRange::getEmpty(CR.getSemantics());569          EnumerateValuesInConstantFPRange(570              ConstantFPRange::getFull(CR.getSemantics()),571              [&](const APFloat &V) {572                if (AnyOfValueInConstantFPRange(573                        CR,574                        [&](const APFloat &U) {575                          return FCmpInst::compare(V, U, Pred);576                        },577                        /*IgnoreNaNPayload=*/true))578                  Optimal = Optimal.unionWith(ConstantFPRange(V));579              },580              /*IgnoreNaNPayload=*/true);581 582          EXPECT_TRUE(Res.contains(Optimal))583              << "Wrong result for makeAllowedFCmpRegion(" << Pred << ", " << CR584              << "). Expected " << Optimal << ", but got " << Res;585          EXPECT_EQ(Res, Optimal)586              << "Suboptimal result for makeAllowedFCmpRegion(" << Pred << ", "587              << CR << ")";588        },589        SparseLevel::SpecialValuesWithAllPowerOfTwos);590  }591#endif592}593 594TEST_F(ConstantFPRangeTest, makeSatisfyingFCmpRegion) {595  EXPECT_EQ(ConstantFPRange::makeSatisfyingFCmpRegion(596                FCmpInst::FCMP_OLE,597                ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))),598            ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),599                                       APFloat(1.0)));600  EXPECT_EQ(601      ConstantFPRange::makeSatisfyingFCmpRegion(602          FCmpInst::FCMP_OLT, ConstantFPRange::getNonNaN(603                                  APFloat::getSmallest(Sem, /*Negative=*/false),604                                  APFloat::getInf(Sem, /*Negative=*/false))),605      ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),606                                 APFloat::getZero(Sem, /*Negative=*/false)));607  EXPECT_EQ(608      ConstantFPRange::makeSatisfyingFCmpRegion(609          FCmpInst::FCMP_OGT, ConstantFPRange::getNonNaN(610                                  APFloat::getZero(Sem, /*Negative=*/true),611                                  APFloat::getZero(Sem, /*Negative=*/false))),612      ConstantFPRange::getNonNaN(APFloat::getSmallest(Sem, /*Negative=*/false),613                                 APFloat::getInf(Sem, /*Negative=*/false)));614  EXPECT_EQ(ConstantFPRange::makeSatisfyingFCmpRegion(615                FCmpInst::FCMP_OGE,616                ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))),617            ConstantFPRange::getNonNaN(618                APFloat(2.0), APFloat::getInf(Sem, /*Negative=*/false)));619  EXPECT_EQ(ConstantFPRange::makeSatisfyingFCmpRegion(620                FCmpInst::FCMP_OEQ,621                ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))),622            ConstantFPRange::getEmpty(Sem));623  EXPECT_EQ(ConstantFPRange::makeSatisfyingFCmpRegion(624                FCmpInst::FCMP_OEQ,625                ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(1.0))),626            ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(1.0)));627 628#if defined(EXPENSIVE_CHECKS)629  for (auto Pred : FCmpInst::predicates()) {630    EnumerateConstantFPRanges(631        [Pred](const ConstantFPRange &CR) {632          ConstantFPRange Res =633              ConstantFPRange::makeSatisfyingFCmpRegion(Pred, CR);634          // Super set of the optimal set excluding NaNs635          ConstantFPRange SuperSet(CR.getSemantics());636          bool ContainsSNaN = false;637          bool ContainsQNaN = false;638          unsigned NonNaNValsInOptimalSet = 0;639          EnumerateValuesInConstantFPRange(640              ConstantFPRange::getFull(CR.getSemantics()),641              [&](const APFloat &V) {642                if (AnyOfValueInConstantFPRange(643                        CR,644                        [&](const APFloat &U) {645                          return !FCmpInst::compare(V, U, Pred);646                        },647                        /*IgnoreNaNPayload=*/true)) {648                  EXPECT_FALSE(Res.contains(V))649                      << "Wrong result for makeSatisfyingFCmpRegion(" << Pred650                      << ", " << CR << "). The result " << Res651                      << " should not contain " << V;652                } else {653                  if (V.isNaN()) {654                    if (V.isSignaling())655                      ContainsSNaN = true;656                    else657                      ContainsQNaN = true;658                  } else {659                    SuperSet = SuperSet.unionWith(ConstantFPRange(V));660                    ++NonNaNValsInOptimalSet;661                  }662                }663              },664              /*IgnoreNaNPayload=*/true);665 666          // Check optimality667 668          // The usefullness of making the result optimal for one/une is669          // questionable.670          if (Pred == FCmpInst::FCMP_ONE || Pred == FCmpInst::FCMP_UNE)671            return;672 673          EXPECT_FALSE(ContainsSNaN && !Res.containsSNaN())674              << "Suboptimal result for makeSatisfyingFCmpRegion(" << Pred675              << ", " << CR << "), should contain SNaN, but got " << Res;676          EXPECT_FALSE(ContainsQNaN && !Res.containsQNaN())677              << "Suboptimal result for makeSatisfyingFCmpRegion(" << Pred678              << ", " << CR << "), should contain QNaN, but got " << Res;679 680          // We only care about the cases where the result is representable by681          // ConstantFPRange.682          unsigned NonNaNValsInSuperSet = 0;683          EnumerateValuesInConstantFPRange(684              SuperSet,685              [&](const APFloat &V) {686                if (!V.isNaN())687                  ++NonNaNValsInSuperSet;688              },689              /*IgnoreNaNPayload=*/true);690 691          if (NonNaNValsInSuperSet == NonNaNValsInOptimalSet) {692            ConstantFPRange Optimal =693                ConstantFPRange(SuperSet.getLower(), SuperSet.getUpper(),694                                ContainsQNaN, ContainsSNaN);695            EXPECT_EQ(Res, Optimal)696                << "Suboptimal result for makeSatisfyingFCmpRegion(" << Pred697                << ", " << CR << ")";698          }699        },700        SparseLevel::SpecialValuesWithAllPowerOfTwos);701  }702#endif703}704 705TEST_F(ConstantFPRangeTest, fcmp) {706  std::vector<ConstantFPRange> InterestingRanges;707  const fltSemantics &Sem = APFloat::Float8E4M3();708  auto FpImm = [&](double V) {709    bool ignored;710    APFloat APF(V);711    APF.convert(Sem, APFloat::rmNearestTiesToEven, &ignored);712    return APF;713  };714 715  InterestingRanges.push_back(ConstantFPRange::getEmpty(Sem));716  InterestingRanges.push_back(ConstantFPRange::getFull(Sem));717  InterestingRanges.push_back(ConstantFPRange::getFinite(Sem));718  InterestingRanges.push_back(ConstantFPRange(FpImm(1.0)));719  InterestingRanges.push_back(720      ConstantFPRange(APFloat::getZero(Sem, /*Negative=*/false)));721  InterestingRanges.push_back(722      ConstantFPRange(APFloat::getZero(Sem, /*Negative=*/true)));723  InterestingRanges.push_back(724      ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/false)));725  InterestingRanges.push_back(726      ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/true)));727  InterestingRanges.push_back(728      ConstantFPRange(APFloat::getSmallest(Sem, /*Negative=*/false)));729  InterestingRanges.push_back(730      ConstantFPRange(APFloat::getSmallest(Sem, /*Negative=*/true)));731  InterestingRanges.push_back(732      ConstantFPRange(APFloat::getLargest(Sem, /*Negative=*/false)));733  InterestingRanges.push_back(734      ConstantFPRange(APFloat::getLargest(Sem, /*Negative=*/true)));735  InterestingRanges.push_back(736      ConstantFPRange::getNaNOnly(Sem, /*MayBeQNaN=*/true, /*MayBeSNaN=*/true));737  InterestingRanges.push_back(738      ConstantFPRange::getNonNaN(FpImm(0.0), FpImm(1.0)));739  InterestingRanges.push_back(740      ConstantFPRange::getNonNaN(FpImm(2.0), FpImm(3.0)));741  InterestingRanges.push_back(742      ConstantFPRange::getNonNaN(FpImm(-1.0), FpImm(1.0)));743  InterestingRanges.push_back(744      ConstantFPRange::getNonNaN(FpImm(-1.0), FpImm(-0.0)));745  InterestingRanges.push_back(ConstantFPRange::getNonNaN(746      APFloat::getInf(Sem, /*Negative=*/true), FpImm(-1.0)));747  InterestingRanges.push_back(ConstantFPRange::getNonNaN(748      FpImm(1.0), APFloat::getInf(Sem, /*Negative=*/false)));749 750  for (auto &LHS : InterestingRanges) {751    for (auto &RHS : InterestingRanges) {752      for (auto Pred : FCmpInst::predicates()) {753        if (LHS.fcmp(Pred, RHS)) {754          EnumerateValuesInConstantFPRange(755              LHS,756              [&](const APFloat &LHSC) {757                EnumerateValuesInConstantFPRange(758                    RHS,759                    [&](const APFloat &RHSC) {760                      EXPECT_TRUE(FCmpInst::compare(LHSC, RHSC, Pred))761                          << LHS << " " << Pred << " " << RHS762                          << " doesn't hold";763                    },764                    /*IgnoreNaNPayload=*/true);765              },766              /*IgnoreNaNPayload=*/true);767        }768      }769    }770  }771}772 773TEST_F(ConstantFPRangeTest, makeExactFCmpRegion) {774  for (auto Pred : FCmpInst::predicates()) {775    EnumerateValuesInConstantFPRange(776        ConstantFPRange::getFull(APFloat::Float8E4M3()),777        [Pred](const APFloat &V) {778          std::optional<ConstantFPRange> Res =779              ConstantFPRange::makeExactFCmpRegion(Pred, V);780          ConstantFPRange Allowed =781              ConstantFPRange::makeAllowedFCmpRegion(Pred, ConstantFPRange(V));782          ConstantFPRange Satisfying =783              ConstantFPRange::makeSatisfyingFCmpRegion(Pred,784                                                        ConstantFPRange(V));785          if (Allowed == Satisfying)786            EXPECT_EQ(Res, Allowed) << "Wrong result for makeExactFCmpRegion("787                                    << Pred << ", " << V << ").";788          else789            EXPECT_FALSE(Res.has_value())790                << "Wrong result for makeExactFCmpRegion(" << Pred << ", " << V791                << ").";792        },793        /*IgnoreNaNPayload=*/true);794  }795}796 797TEST_F(ConstantFPRangeTest, abs) {798  EXPECT_EQ(Full.abs(),799            ConstantFPRange(APFloat::getZero(Sem, /*Negative=*/false),800                            APFloat::getInf(Sem, /*Negative=*/false),801                            /*MayBeQNaN=*/true,802                            /*MayBeSNaN=*/true));803  EXPECT_EQ(Empty.abs(), Empty);804  EXPECT_EQ(Zero.abs(), PosZero);805  EXPECT_EQ(PosInf.abs(), PosInf);806  EXPECT_EQ(NegInf.abs(), PosInf);807  EXPECT_EQ(Some.abs(), SomePos);808  EXPECT_EQ(SomeNeg.abs(), SomePos);809  EXPECT_EQ(NaN.abs(), NaN);810  EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(-2.0), APFloat(3.0)).abs(),811            ConstantFPRange::getNonNaN(APFloat(0.0), APFloat(3.0)));812  EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(-3.0), APFloat(2.0)).abs(),813            ConstantFPRange::getNonNaN(APFloat(0.0), APFloat(3.0)));814}815 816TEST_F(ConstantFPRangeTest, negate) {817  EXPECT_EQ(Full.negate(), Full);818  EXPECT_EQ(Empty.negate(), Empty);819  EXPECT_EQ(Zero.negate(), Zero);820  EXPECT_EQ(PosInf.negate(), NegInf);821  EXPECT_EQ(NegInf.negate(), PosInf);822  EXPECT_EQ(Some.negate(), Some);823  EXPECT_EQ(SomePos.negate(), SomeNeg);824  EXPECT_EQ(SomeNeg.negate(), SomePos);825  EXPECT_EQ(NaN.negate(), NaN);826  EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(-2.0), APFloat(3.0)).negate(),827            ConstantFPRange::getNonNaN(APFloat(-3.0), APFloat(2.0)));828  EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(-3.0), APFloat(2.0)).negate(),829            ConstantFPRange::getNonNaN(APFloat(-2.0), APFloat(3.0)));830}831 832TEST_F(ConstantFPRangeTest, getWithout) {833  EXPECT_EQ(Full.getWithoutNaN(), NonNaN);834  EXPECT_EQ(NaN.getWithoutNaN(), Empty);835 836  EXPECT_EQ(NaN.getWithoutInf(), NaN);837  EXPECT_EQ(PosInf.getWithoutInf(), Empty);838  EXPECT_EQ(NegInf.getWithoutInf(), Empty);839  EXPECT_EQ(NonNaN.getWithoutInf(), Finite);840  EXPECT_EQ(Zero.getWithoutInf(), Zero);841  EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),842                                       APFloat(3.0))843                .getWithoutInf(),844            ConstantFPRange::getNonNaN(845                APFloat::getLargest(Sem, /*Negative=*/true), APFloat(3.0)));846}847 848TEST_F(ConstantFPRangeTest, cast) {849  const fltSemantics &F16Sem = APFloat::IEEEhalf();850  const fltSemantics &BF16Sem = APFloat::BFloat();851  const fltSemantics &F32Sem = APFloat::IEEEsingle();852  const fltSemantics &F8NanOnlySem = APFloat::Float8E4M3FN();853  // normal -> normal (exact)854  EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0)).cast(F32Sem),855            ConstantFPRange::getNonNaN(APFloat(1.0f), APFloat(2.0f)));856  EXPECT_EQ(857      ConstantFPRange::getNonNaN(APFloat(-2.0f), APFloat(-1.0f)).cast(Sem),858      ConstantFPRange::getNonNaN(APFloat(-2.0), APFloat(-1.0)));859  // normal -> normal (inexact)860  EXPECT_EQ(861      ConstantFPRange::getNonNaN(APFloat(3.141592653589793),862                                 APFloat(6.283185307179586))863          .cast(F32Sem),864      ConstantFPRange::getNonNaN(APFloat(3.14159274f), APFloat(6.28318548f)));865  // normal -> subnormal866  EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(-5e-8), APFloat(5e-8))867                .cast(F16Sem)868                .classify(),869            fcSubnormal | fcZero);870  // normal -> zero871  EXPECT_EQ(ConstantFPRange::getNonNaN(872                APFloat::getSmallestNormalized(Sem, /*Negative=*/true),873                APFloat::getSmallestNormalized(Sem, /*Negative=*/false))874                .cast(F32Sem)875                .classify(),876            fcZero);877  // normal -> inf878  EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(-65536.0), APFloat(65536.0))879                .cast(F16Sem),880            ConstantFPRange::getNonNaN(F16Sem));881  // nan -> qnan882  EXPECT_EQ(883      ConstantFPRange::getNaNOnly(Sem, /*MayBeQNaN=*/true, /*MayBeSNaN=*/false)884          .cast(F32Sem),885      ConstantFPRange::getNaNOnly(F32Sem, /*MayBeQNaN=*/true,886                                  /*MayBeSNaN=*/false));887  EXPECT_EQ(888      ConstantFPRange::getNaNOnly(Sem, /*MayBeQNaN=*/false, /*MayBeSNaN=*/true)889          .cast(F32Sem),890      ConstantFPRange::getNaNOnly(F32Sem, /*MayBeQNaN=*/true,891                                  /*MayBeSNaN=*/false));892  EXPECT_EQ(893      ConstantFPRange::getNaNOnly(Sem, /*MayBeQNaN=*/true, /*MayBeSNaN=*/true)894          .cast(F32Sem),895      ConstantFPRange::getNaNOnly(F32Sem, /*MayBeQNaN=*/true,896                                  /*MayBeSNaN=*/false));897  // For BF16 -> F32, signaling bit is still lost.898  EXPECT_EQ(ConstantFPRange::getNaNOnly(BF16Sem, /*MayBeQNaN=*/true,899                                        /*MayBeSNaN=*/true)900                .cast(F32Sem),901            ConstantFPRange::getNaNOnly(F32Sem, /*MayBeQNaN=*/true,902                                        /*MayBeSNaN=*/false));903  // inf -> nan only (return full set for now)904  EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),905                                       APFloat::getInf(Sem, /*Negative=*/false))906                .cast(F8NanOnlySem),907            ConstantFPRange::getFull(F8NanOnlySem));908  // other rounding modes909  EXPECT_EQ(910      ConstantFPRange::getNonNaN(APFloat::getSmallest(Sem, /*Negative=*/true),911                                 APFloat::getSmallest(Sem, /*Negative=*/false))912          .cast(F32Sem, APFloat::rmTowardNegative),913      ConstantFPRange::getNonNaN(914          APFloat::getSmallest(F32Sem, /*Negative=*/true),915          APFloat::getZero(F32Sem, /*Negative=*/false)));916  EXPECT_EQ(917      ConstantFPRange::getNonNaN(APFloat::getSmallest(Sem, /*Negative=*/true),918                                 APFloat::getSmallest(Sem, /*Negative=*/false))919          .cast(F32Sem, APFloat::rmTowardPositive),920      ConstantFPRange::getNonNaN(921          APFloat::getZero(F32Sem, /*Negative=*/true),922          APFloat::getSmallest(F32Sem, /*Negative=*/false)));923  EXPECT_EQ(924      ConstantFPRange::getNonNaN(925          APFloat::getSmallestNormalized(Sem, /*Negative=*/true),926          APFloat::getSmallestNormalized(Sem, /*Negative=*/false))927          .cast(F32Sem, APFloat::rmTowardZero),928      ConstantFPRange::getNonNaN(APFloat::getZero(F32Sem, /*Negative=*/true),929                                 APFloat::getZero(F32Sem, /*Negative=*/false)));930 931  EnumerateValuesInConstantFPRange(932      ConstantFPRange::getFull(APFloat::Float8E4M3()),933      [&](const APFloat &V) {934        bool LosesInfo = false;935 936        APFloat DoubleV = V;937        DoubleV.convert(Sem, APFloat::rmNearestTiesToEven, &LosesInfo);938        ConstantFPRange DoubleCR = ConstantFPRange(V).cast(Sem);939        EXPECT_TRUE(DoubleCR.contains(DoubleV))940            << "Casting " << V << " to double failed. " << DoubleCR941            << " doesn't contain " << DoubleV;942 943        auto &FP4Sem = APFloat::Float4E2M1FN();944        APFloat FP4V = V;945        FP4V.convert(FP4Sem, APFloat::rmNearestTiesToEven, &LosesInfo);946        ConstantFPRange FP4CR = ConstantFPRange(V).cast(FP4Sem);947        EXPECT_TRUE(FP4CR.contains(FP4V))948            << "Casting " << V << " to FP4E2M1FN failed. " << FP4CR949            << " doesn't contain " << FP4V;950      },951      /*IgnoreNaNPayload=*/true);952}953 954TEST_F(ConstantFPRangeTest, add) {955  EXPECT_EQ(Full.add(Full), NonNaN.unionWith(QNaN));956  EXPECT_EQ(Full.add(Empty), Empty);957  EXPECT_EQ(Empty.add(Full), Empty);958  EXPECT_EQ(Empty.add(Empty), Empty);959  EXPECT_EQ(One.add(One), ConstantFPRange(APFloat(2.0)));960  EXPECT_EQ(Some.add(Some),961            ConstantFPRange::getNonNaN(APFloat(-6.0), APFloat(6.0)));962  EXPECT_EQ(SomePos.add(SomeNeg),963            ConstantFPRange::getNonNaN(APFloat(-3.0), APFloat(3.0)));964  EXPECT_EQ(PosInf.add(PosInf), PosInf);965  EXPECT_EQ(NegInf.add(NegInf), NegInf);966  EXPECT_EQ(PosInf.add(Finite.unionWith(PosInf)), PosInf);967  EXPECT_EQ(NegInf.add(Finite.unionWith(NegInf)), NegInf);968  EXPECT_EQ(PosInf.add(Finite.unionWith(NegInf)), PosInf.unionWith(QNaN));969  EXPECT_EQ(NegInf.add(Finite.unionWith(PosInf)), NegInf.unionWith(QNaN));970  EXPECT_EQ(PosInf.add(NegInf), QNaN);971  EXPECT_EQ(NegInf.add(PosInf), QNaN);972  EXPECT_EQ(PosZero.add(NegZero), PosZero);973  EXPECT_EQ(PosZero.add(Zero), PosZero);974  EXPECT_EQ(NegZero.add(NegZero), NegZero);975  EXPECT_EQ(NegZero.add(Zero), Zero);976  EXPECT_EQ(NaN.add(NaN), QNaN);977  EXPECT_EQ(NaN.add(Finite), QNaN);978  EXPECT_EQ(NonNaN.unionWith(NaN).add(NonNaN), NonNaN.unionWith(QNaN));979  EXPECT_EQ(PosInf.unionWith(QNaN).add(PosInf), PosInf.unionWith(QNaN));980  EXPECT_EQ(PosInf.unionWith(NaN).add(ConstantFPRange(APFloat(24.0))),981            PosInf.unionWith(QNaN));982 983#if defined(EXPENSIVE_CHECKS)984  EnumerateTwoInterestingConstantFPRanges(985      [](const ConstantFPRange &LHS, const ConstantFPRange &RHS) {986        ConstantFPRange Res = LHS.add(RHS);987        ConstantFPRange Expected =988            ConstantFPRange::getEmpty(LHS.getSemantics());989        EnumerateValuesInConstantFPRange(990            LHS,991            [&](const APFloat &LHSC) {992              EnumerateValuesInConstantFPRange(993                  RHS,994                  [&](const APFloat &RHSC) {995                    APFloat Sum = LHSC + RHSC;996                    EXPECT_TRUE(Res.contains(Sum))997                        << "Wrong result for " << LHS << " + " << RHS998                        << ". The result " << Res << " should contain " << Sum;999                    if (!Expected.contains(Sum))1000                      Expected = Expected.unionWith(ConstantFPRange(Sum));1001                  },1002                  /*IgnoreNaNPayload=*/true);1003            },1004            /*IgnoreNaNPayload=*/true);1005        EXPECT_EQ(Res, Expected)1006            << "Suboptimal result for " << LHS << " + " << RHS << ". Expected "1007            << Expected << ", but got " << Res;1008      },1009      SparseLevel::SpecialValuesOnly);1010#endif1011}1012 1013TEST_F(ConstantFPRangeTest, sub) {1014  EXPECT_EQ(Full.sub(Full), NonNaN.unionWith(QNaN));1015  EXPECT_EQ(Full.sub(Empty), Empty);1016  EXPECT_EQ(Empty.sub(Full), Empty);1017  EXPECT_EQ(Empty.sub(Empty), Empty);1018  EXPECT_EQ(One.sub(One), ConstantFPRange(APFloat(0.0)));1019  EXPECT_EQ(Some.sub(Some),1020            ConstantFPRange::getNonNaN(APFloat(-6.0), APFloat(6.0)));1021  EXPECT_EQ(SomePos.sub(SomeNeg),1022            ConstantFPRange::getNonNaN(APFloat(0.0), APFloat(6.0)));1023  EXPECT_EQ(PosInf.sub(NegInf), PosInf);1024  EXPECT_EQ(NegInf.sub(PosInf), NegInf);1025  EXPECT_EQ(PosInf.sub(Finite.unionWith(NegInf)), PosInf);1026  EXPECT_EQ(NegInf.sub(Finite.unionWith(PosInf)), NegInf);1027  EXPECT_EQ(PosInf.sub(Finite.unionWith(PosInf)), PosInf.unionWith(QNaN));1028  EXPECT_EQ(NegInf.sub(Finite.unionWith(NegInf)), NegInf.unionWith(QNaN));1029  EXPECT_EQ(PosInf.sub(PosInf), QNaN);1030  EXPECT_EQ(NegInf.sub(NegInf), QNaN);1031  EXPECT_EQ(PosZero.sub(NegZero), PosZero);1032  EXPECT_EQ(PosZero.sub(Zero), PosZero);1033  EXPECT_EQ(NegZero.sub(NegZero), PosZero);1034  EXPECT_EQ(NegZero.sub(PosZero), NegZero);1035  EXPECT_EQ(NegZero.sub(Zero), Zero);1036  EXPECT_EQ(NaN.sub(NaN), QNaN);1037  EXPECT_EQ(NaN.add(Finite), QNaN);1038 1039#if defined(EXPENSIVE_CHECKS)1040  EnumerateTwoInterestingConstantFPRanges(1041      [](const ConstantFPRange &LHS, const ConstantFPRange &RHS) {1042        ConstantFPRange Res = LHS.sub(RHS);1043        ConstantFPRange Expected =1044            ConstantFPRange::getEmpty(LHS.getSemantics());1045        EnumerateValuesInConstantFPRange(1046            LHS,1047            [&](const APFloat &LHSC) {1048              EnumerateValuesInConstantFPRange(1049                  RHS,1050                  [&](const APFloat &RHSC) {1051                    APFloat Diff = LHSC - RHSC;1052                    EXPECT_TRUE(Res.contains(Diff))1053                        << "Wrong result for " << LHS << " - " << RHS1054                        << ". The result " << Res << " should contain " << Diff;1055                    if (!Expected.contains(Diff))1056                      Expected = Expected.unionWith(ConstantFPRange(Diff));1057                  },1058                  /*IgnoreNaNPayload=*/true);1059            },1060            /*IgnoreNaNPayload=*/true);1061        EXPECT_EQ(Res, Expected)1062            << "Suboptimal result for " << LHS << " - " << RHS << ". Expected "1063            << Expected << ", but got " << Res;1064      },1065      SparseLevel::SpecialValuesOnly);1066#endif1067}1068 1069TEST_F(ConstantFPRangeTest, mul) {1070  EXPECT_EQ(Full.mul(Full), NonNaN.unionWith(QNaN));1071  EXPECT_EQ(Full.mul(Empty), Empty);1072  EXPECT_EQ(Empty.mul(Full), Empty);1073  EXPECT_EQ(Empty.mul(Empty), Empty);1074  EXPECT_EQ(One.mul(One), ConstantFPRange(APFloat(1.0)));1075  EXPECT_EQ(Some.mul(Some),1076            ConstantFPRange::getNonNaN(APFloat(-9.0), APFloat(9.0)));1077  EXPECT_EQ(SomePos.mul(SomeNeg),1078            ConstantFPRange::getNonNaN(APFloat(-9.0), APFloat(-0.0)));1079  EXPECT_EQ(PosInf.mul(PosInf), PosInf);1080  EXPECT_EQ(NegInf.mul(NegInf), PosInf);1081  EXPECT_EQ(PosInf.mul(Finite), NonNaN.unionWith(QNaN));1082  EXPECT_EQ(NegInf.mul(Finite), NonNaN.unionWith(QNaN));1083  EXPECT_EQ(PosInf.mul(NegInf), NegInf);1084  EXPECT_EQ(NegInf.mul(PosInf), NegInf);1085  EXPECT_EQ(PosZero.mul(NegZero), NegZero);1086  EXPECT_EQ(PosZero.mul(Zero), Zero);1087  EXPECT_EQ(NegZero.mul(NegZero), PosZero);1088  EXPECT_EQ(NegZero.mul(Zero), Zero);1089  EXPECT_EQ(NaN.mul(NaN), QNaN);1090  EXPECT_EQ(NaN.mul(Finite), QNaN);1091 1092#if defined(EXPENSIVE_CHECKS)1093  EnumerateTwoInterestingConstantFPRanges(1094      [](const ConstantFPRange &LHS, const ConstantFPRange &RHS) {1095        ConstantFPRange Res = LHS.mul(RHS);1096        ConstantFPRange Expected =1097            ConstantFPRange::getEmpty(LHS.getSemantics());1098        EnumerateValuesInConstantFPRange(1099            LHS,1100            [&](const APFloat &LHSC) {1101              EnumerateValuesInConstantFPRange(1102                  RHS,1103                  [&](const APFloat &RHSC) {1104                    APFloat Prod = LHSC * RHSC;1105                    EXPECT_TRUE(Res.contains(Prod))1106                        << "Wrong result for " << LHS << " * " << RHS1107                        << ". The result " << Res << " should contain " << Prod;1108                    if (!Expected.contains(Prod))1109                      Expected = Expected.unionWith(ConstantFPRange(Prod));1110                  },1111                  /*IgnoreNaNPayload=*/true);1112            },1113            /*IgnoreNaNPayload=*/true);1114        EXPECT_EQ(Res, Expected)1115            << "Suboptimal result for " << LHS << " * " << RHS << ". Expected "1116            << Expected << ", but got " << Res;1117      },1118      SparseLevel::SpecialValuesOnly);1119#endif1120}1121 1122TEST_F(ConstantFPRangeTest, div) {1123  EXPECT_EQ(Full.div(Full), NonNaN.unionWith(QNaN));1124  EXPECT_EQ(Full.div(Empty), Empty);1125  EXPECT_EQ(Empty.div(Full), Empty);1126  EXPECT_EQ(Empty.div(Empty), Empty);1127  EXPECT_EQ(One.div(One), ConstantFPRange(APFloat(1.0)));1128  EXPECT_EQ(Some.div(Some), NonNaN.unionWith(QNaN));1129  EXPECT_EQ(SomePos.div(SomeNeg),1130            ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/true),1131                            APFloat::getZero(Sem, /*Negative=*/true),1132                            /*MayBeQNaN=*/true, /*MayBeSNaN=*/false));1133  EXPECT_EQ(PosInf.div(PosInf), QNaN);1134  EXPECT_EQ(NegInf.div(NegInf), QNaN);1135  EXPECT_EQ(PosInf.div(Finite), NonNaN);1136  EXPECT_EQ(NegInf.div(Finite), NonNaN);1137  EXPECT_EQ(PosInf.div(NegInf), QNaN);1138  EXPECT_EQ(NegInf.div(PosInf), QNaN);1139  EXPECT_EQ(Zero.div(Zero), QNaN);1140  EXPECT_EQ(SomePos.div(PosInf), PosZero);1141  EXPECT_EQ(SomeNeg.div(PosInf), NegZero);1142  EXPECT_EQ(PosInf.div(SomePos), PosInf);1143  EXPECT_EQ(NegInf.div(SomeNeg), PosInf);1144  EXPECT_EQ(NegInf.div(Some), NonNaN);1145  EXPECT_EQ(NaN.div(NaN), QNaN);1146  EXPECT_EQ(NaN.div(Finite), QNaN);1147 1148#if defined(EXPENSIVE_CHECKS)1149  EnumerateTwoInterestingConstantFPRanges(1150      [](const ConstantFPRange &LHS, const ConstantFPRange &RHS) {1151        ConstantFPRange Res = LHS.div(RHS);1152        ConstantFPRange Expected =1153            ConstantFPRange::getEmpty(LHS.getSemantics());1154        EnumerateValuesInConstantFPRange(1155            LHS,1156            [&](const APFloat &LHSC) {1157              EnumerateValuesInConstantFPRange(1158                  RHS,1159                  [&](const APFloat &RHSC) {1160                    APFloat Val = LHSC / RHSC;1161                    EXPECT_TRUE(Res.contains(Val))1162                        << "Wrong result for " << LHS << " / " << RHS1163                        << ". The result " << Res << " should contain " << Val;1164                    if (!Expected.contains(Val))1165                      Expected = Expected.unionWith(ConstantFPRange(Val));1166                  },1167                  /*IgnoreNaNPayload=*/true);1168            },1169            /*IgnoreNaNPayload=*/true);1170        EXPECT_EQ(Res, Expected)1171            << "Suboptimal result for " << LHS << " / " << RHS << ". Expected "1172            << Expected << ", but got " << Res;1173      },1174      SparseLevel::SpecialValuesOnly);1175#endif1176}1177 1178TEST_F(ConstantFPRangeTest, flushDenormals) {1179  const fltSemantics &FP8Sem = APFloat::Float8E4M3();1180  APFloat NormalVal = APFloat::getSmallestNormalized(FP8Sem);1181  APFloat Subnormal1 = NormalVal;1182  Subnormal1.next(/*nextDown=*/true);1183  APFloat Subnormal2 = APFloat::getSmallest(FP8Sem);1184  APFloat ZeroVal = APFloat::getZero(FP8Sem);1185  APFloat EdgeValues[8] = {-NormalVal, -Subnormal1, -Subnormal2, -ZeroVal,1186                           ZeroVal,    Subnormal2,  Subnormal1,  NormalVal};1187  constexpr DenormalMode::DenormalModeKind Modes[4] = {1188      DenormalMode::IEEE, DenormalMode::PreserveSign,1189      DenormalMode::PositiveZero, DenormalMode::Dynamic};1190  for (uint32_t I = 0; I != 8; ++I) {1191    for (uint32_t J = I; J != 8; ++J) {1192      ConstantFPRange OriginCR =1193          ConstantFPRange::getNonNaN(EdgeValues[I], EdgeValues[J]);1194      for (auto Mode : Modes) {1195        StringRef ModeName = denormalModeKindName(Mode);1196        ConstantFPRange FlushedCR = OriginCR;1197        FlushedCR.flushDenormals(Mode);1198 1199        ConstantFPRange Expected = ConstantFPRange::getEmpty(FP8Sem);1200        auto CheckFlushedV = [&](const APFloat &V, const APFloat &FlushedV) {1201          EXPECT_TRUE(FlushedCR.contains(FlushedV))1202              << "Wrong result for flushDenormal(" << V << ", " << ModeName1203              << "). The result " << FlushedCR << " should contain "1204              << FlushedV;1205          if (!Expected.contains(FlushedV))1206            Expected = Expected.unionWith(ConstantFPRange(FlushedV));1207        };1208        EnumerateValuesInConstantFPRange(1209            OriginCR,1210            [&](const APFloat &V) {1211              if (V.isDenormal()) {1212                switch (Mode) {1213                case DenormalMode::IEEE:1214                  break;1215                case DenormalMode::PreserveSign:1216                  CheckFlushedV(V, APFloat::getZero(FP8Sem, V.isNegative()));1217                  break;1218                case DenormalMode::PositiveZero:1219                  CheckFlushedV(V, APFloat::getZero(FP8Sem));1220                  break;1221                case DenormalMode::Dynamic:1222                  // PreserveSign1223                  CheckFlushedV(V, APFloat::getZero(FP8Sem, V.isNegative()));1224                  // PositiveZero1225                  CheckFlushedV(V, APFloat::getZero(FP8Sem));1226                  break;1227                default:1228                  llvm_unreachable("unknown denormal mode");1229                }1230              }1231              // It is not mandated that flushing to zero occurs.1232              CheckFlushedV(V, V);1233            },1234            /*IgnoreNaNPayload=*/true);1235        EXPECT_EQ(FlushedCR, Expected)1236            << "Suboptimal result for flushDenormal(" << OriginCR << ", "1237            << ModeName << "). Expected " << Expected << ", but got "1238            << FlushedCR;1239      }1240    }1241  }1242}1243 1244} // anonymous namespace1245