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