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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/IR/ConstantFPRange.h" 10 #include "llvm/IR/Instructions.h" 11 #include "llvm/IR/Operator.h" 12 #include "gtest/gtest.h" 13 14 using namespace llvm; 15 16 namespace { 17 18 class ConstantFPRangeTest : public ::testing::Test { 19 protected: 20 static const fltSemantics &Sem; 21 static ConstantFPRange Full; 22 static ConstantFPRange Empty; 23 static ConstantFPRange Finite; 24 static ConstantFPRange One; 25 static ConstantFPRange PosZero; 26 static ConstantFPRange NegZero; 27 static ConstantFPRange Zero; 28 static ConstantFPRange PosInf; 29 static ConstantFPRange NegInf; 30 static ConstantFPRange Denormal; 31 static ConstantFPRange NaN; 32 static ConstantFPRange SNaN; 33 static ConstantFPRange QNaN; 34 static ConstantFPRange Some; 35 static ConstantFPRange SomePos; 36 static ConstantFPRange SomeNeg; 37 }; 38 39 const fltSemantics &ConstantFPRangeTest::Sem = APFloat::IEEEdouble(); 40 ConstantFPRange ConstantFPRangeTest::Full = 41 ConstantFPRange::getFull(APFloat::IEEEdouble()); 42 ConstantFPRange ConstantFPRangeTest::Empty = 43 ConstantFPRange::getEmpty(APFloat::IEEEdouble()); 44 ConstantFPRange ConstantFPRangeTest::Finite = 45 ConstantFPRange::getFinite(APFloat::IEEEdouble()); 46 ConstantFPRange ConstantFPRangeTest::One = ConstantFPRange(APFloat(1.0)); 47 ConstantFPRange ConstantFPRangeTest::PosZero = ConstantFPRange( 48 APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/false)); 49 ConstantFPRange ConstantFPRangeTest::NegZero = 50 ConstantFPRange(APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/true)); 51 ConstantFPRange ConstantFPRangeTest::Zero = ConstantFPRange::getNonNaN( 52 APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/true), 53 APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/false)); 54 ConstantFPRange ConstantFPRangeTest::Denormal = 55 ConstantFPRange(APFloat::getSmallest(APFloat::IEEEdouble())); 56 ConstantFPRange ConstantFPRangeTest::PosInf = 57 ConstantFPRange(APFloat::getInf(APFloat::IEEEdouble(), /*Negative=*/false)); 58 ConstantFPRange ConstantFPRangeTest::NegInf = 59 ConstantFPRange(APFloat::getInf(APFloat::IEEEdouble(), /*Negative=*/true)); 60 ConstantFPRange ConstantFPRangeTest::NaN = ConstantFPRange::getNaNOnly( 61 APFloat::IEEEdouble(), /*MayBeQNaN=*/true, /*MayBeSNaN=*/true); 62 ConstantFPRange ConstantFPRangeTest::SNaN = 63 ConstantFPRange(APFloat::getSNaN(APFloat::IEEEdouble())); 64 ConstantFPRange ConstantFPRangeTest::QNaN = 65 ConstantFPRange(APFloat::getQNaN(APFloat::IEEEdouble())); 66 ConstantFPRange ConstantFPRangeTest::Some = 67 ConstantFPRange::getNonNaN(APFloat(-3.0), APFloat(3.0)); 68 ConstantFPRange ConstantFPRangeTest::SomePos = ConstantFPRange::getNonNaN( 69 APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/false), APFloat(3.0)); 70 ConstantFPRange ConstantFPRangeTest::SomeNeg = ConstantFPRange::getNonNaN( 71 APFloat(-3.0), APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/true)); 72 73 static void strictNext(APFloat &V) { 74 // Note: nextUp(+/-0) is smallest. 75 if (V.isNegZero()) 76 V = APFloat::getZero(V.getSemantics(), /*Negative=*/false); 77 else 78 V.next(/*nextDown=*/false); 79 } 80 81 template <typename Fn> 82 static void EnumerateConstantFPRangesImpl(Fn TestFn, bool Exhaustive, 83 bool MayBeQNaN, bool MayBeSNaN) { 84 const fltSemantics &Sem = APFloat::Float8E4M3(); 85 APFloat PosInf = APFloat::getInf(Sem, /*Negative=*/false); 86 APFloat NegInf = APFloat::getInf(Sem, /*Negative=*/true); 87 TestFn(ConstantFPRange(PosInf, NegInf, MayBeQNaN, MayBeSNaN)); 88 89 if (!Exhaustive) { 90 SmallVector<APFloat, 36> Values; 91 Values.push_back(APFloat::getInf(Sem, /*Negative=*/true)); 92 Values.push_back(APFloat::getLargest(Sem, /*Negative=*/true)); 93 unsigned BitWidth = APFloat::semanticsSizeInBits(Sem); 94 unsigned Exponents = APFloat::semanticsMaxExponent(Sem) - 95 APFloat::semanticsMinExponent(Sem) + 3; 96 unsigned MantissaBits = APFloat::semanticsPrecision(Sem) - 1; 97 // Add -2^(max exponent), -2^(max exponent-1), ..., -2^(min exponent) 98 for (unsigned M = Exponents - 2; M != 0; --M) 99 Values.push_back( 100 APFloat(Sem, APInt(BitWidth, (M + Exponents) << MantissaBits))); 101 Values.push_back(APFloat::getSmallest(Sem, /*Negative=*/true)); 102 Values.push_back(APFloat::getZero(Sem, /*Negative=*/true)); 103 size_t E = Values.size(); 104 for (size_t I = 1; I <= E; ++I) 105 Values.push_back(-Values[E - I]); 106 for (size_t I = 0; I != Values.size(); ++I) 107 for (size_t J = I; J != Values.size(); ++J) 108 TestFn(ConstantFPRange(Values[I], Values[J], MayBeQNaN, MayBeSNaN)); 109 return; 110 } 111 112 auto Next = [&](APFloat &V) { 113 if (V.isPosInfinity()) 114 return false; 115 strictNext(V); 116 return true; 117 }; 118 119 APFloat Lower = NegInf; 120 do { 121 APFloat Upper = Lower; 122 do { 123 TestFn(ConstantFPRange(Lower, Upper, MayBeQNaN, MayBeSNaN)); 124 } while (Next(Upper)); 125 } while (Next(Lower)); 126 } 127 128 template <typename Fn> 129 static void EnumerateConstantFPRanges(Fn TestFn, bool Exhaustive) { 130 EnumerateConstantFPRangesImpl(TestFn, Exhaustive, /*MayBeQNaN=*/false, 131 /*MayBeSNaN=*/false); 132 EnumerateConstantFPRangesImpl(TestFn, Exhaustive, /*MayBeQNaN=*/false, 133 /*MayBeSNaN=*/true); 134 EnumerateConstantFPRangesImpl(TestFn, Exhaustive, /*MayBeQNaN=*/true, 135 /*MayBeSNaN=*/false); 136 EnumerateConstantFPRangesImpl(TestFn, Exhaustive, /*MayBeQNaN=*/true, 137 /*MayBeSNaN=*/true); 138 } 139 140 template <typename Fn> 141 static void EnumerateTwoInterestingConstantFPRanges(Fn TestFn, 142 bool Exhaustive) { 143 EnumerateConstantFPRanges( 144 [&](const ConstantFPRange &CR1) { 145 EnumerateConstantFPRanges( 146 [&](const ConstantFPRange &CR2) { TestFn(CR1, CR2); }, Exhaustive); 147 }, 148 Exhaustive); 149 } 150 151 template <typename Fn> 152 static void EnumerateValuesInConstantFPRange(const ConstantFPRange &CR, 153 Fn TestFn, bool IgnoreNaNPayload) { 154 const fltSemantics &Sem = CR.getSemantics(); 155 if (IgnoreNaNPayload) { 156 if (CR.containsSNaN()) { 157 TestFn(APFloat::getSNaN(Sem, false)); 158 TestFn(APFloat::getSNaN(Sem, true)); 159 } 160 if (CR.containsQNaN()) { 161 TestFn(APFloat::getQNaN(Sem, false)); 162 TestFn(APFloat::getQNaN(Sem, true)); 163 } 164 if (CR.isNaNOnly()) 165 return; 166 APFloat Lower = CR.getLower(); 167 const APFloat &Upper = CR.getUpper(); 168 auto Next = [&](APFloat &V) { 169 if (V.bitwiseIsEqual(Upper)) 170 return false; 171 strictNext(V); 172 return true; 173 }; 174 do 175 TestFn(Lower); 176 while (Next(Lower)); 177 } else { 178 unsigned Bits = APFloat::semanticsSizeInBits(Sem); 179 assert(Bits < 32 && "Too many bits"); 180 for (unsigned I = 0, E = (1U << Bits) - 1; I != E; ++I) { 181 APFloat V(Sem, APInt(Bits, I)); 182 if (CR.contains(V)) 183 TestFn(V); 184 } 185 } 186 } 187 188 template <typename Fn> 189 static bool AnyOfValueInConstantFPRange(const ConstantFPRange &CR, Fn TestFn, 190 bool IgnoreNaNPayload) { 191 const fltSemantics &Sem = CR.getSemantics(); 192 if (IgnoreNaNPayload) { 193 if (CR.containsSNaN()) { 194 if (TestFn(APFloat::getSNaN(Sem, false))) 195 return true; 196 if (TestFn(APFloat::getSNaN(Sem, true))) 197 return true; 198 } 199 if (CR.containsQNaN()) { 200 if (TestFn(APFloat::getQNaN(Sem, false))) 201 return true; 202 if (TestFn(APFloat::getQNaN(Sem, true))) 203 return true; 204 } 205 if (CR.isNaNOnly()) 206 return false; 207 APFloat Lower = CR.getLower(); 208 const APFloat &Upper = CR.getUpper(); 209 auto Next = [&](APFloat &V) { 210 if (V.bitwiseIsEqual(Upper)) 211 return false; 212 strictNext(V); 213 return true; 214 }; 215 do { 216 if (TestFn(Lower)) 217 return true; 218 } while (Next(Lower)); 219 } else { 220 unsigned Bits = APFloat::semanticsSizeInBits(Sem); 221 assert(Bits < 32 && "Too many bits"); 222 for (unsigned I = 0, E = (1U << Bits) - 1; I != E; ++I) { 223 APFloat V(Sem, APInt(Bits, I)); 224 if (CR.contains(V) && TestFn(V)) 225 return true; 226 } 227 } 228 return false; 229 } 230 231 TEST_F(ConstantFPRangeTest, Basics) { 232 EXPECT_TRUE(Full.isFullSet()); 233 EXPECT_FALSE(Full.isEmptySet()); 234 EXPECT_TRUE(Full.contains(APFloat::getNaN(Sem))); 235 EXPECT_TRUE(Full.contains(APFloat::getInf(Sem, /*Negative=*/false))); 236 EXPECT_TRUE(Full.contains(APFloat::getInf(Sem, /*Negative=*/true))); 237 EXPECT_TRUE(Full.contains(APFloat::getZero(Sem, /*Negative=*/false))); 238 EXPECT_TRUE(Full.contains(APFloat::getZero(Sem, /*Negative=*/true))); 239 EXPECT_TRUE(Full.contains(APFloat::getSmallest(Sem))); 240 EXPECT_TRUE(Full.contains(APFloat(2.0))); 241 EXPECT_TRUE(Full.contains(Full)); 242 EXPECT_TRUE(Full.contains(Empty)); 243 EXPECT_TRUE(Full.contains(Finite)); 244 EXPECT_TRUE(Full.contains(Zero)); 245 EXPECT_TRUE(Full.contains(Some)); 246 247 EXPECT_FALSE(Empty.isFullSet()); 248 EXPECT_TRUE(Empty.isEmptySet()); 249 EXPECT_FALSE(Empty.contains(APFloat::getNaN(Sem))); 250 EXPECT_FALSE(Empty.contains(APFloat::getInf(Sem, /*Negative=*/false))); 251 EXPECT_FALSE(Empty.contains(APFloat::getZero(Sem, /*Negative=*/true))); 252 EXPECT_FALSE(Empty.contains(APFloat(2.0))); 253 EXPECT_TRUE(Empty.contains(Empty)); 254 255 EXPECT_FALSE(Finite.isFullSet()); 256 EXPECT_FALSE(Finite.isEmptySet()); 257 EXPECT_FALSE(Finite.contains(APFloat::getNaN(Sem))); 258 EXPECT_FALSE(Finite.contains(APFloat::getInf(Sem, /*Negative=*/false))); 259 EXPECT_FALSE(Finite.contains(APFloat::getInf(Sem, /*Negative=*/true))); 260 EXPECT_TRUE(Finite.contains(APFloat::getLargest(Sem, /*Negative=*/false))); 261 EXPECT_TRUE(Finite.contains(APFloat::getLargest(Sem, /*Negative=*/true))); 262 EXPECT_TRUE(Finite.contains(Finite)); 263 EXPECT_TRUE(Finite.contains(Some)); 264 EXPECT_TRUE(Finite.contains(Denormal)); 265 EXPECT_TRUE(Finite.contains(Zero)); 266 EXPECT_FALSE(Finite.contains(PosInf)); 267 EXPECT_FALSE(Finite.contains(NaN)); 268 269 EXPECT_TRUE(One.contains(APFloat(1.0))); 270 EXPECT_FALSE(One.contains(APFloat(1.1))); 271 272 EXPECT_TRUE(PosZero.contains(APFloat::getZero(Sem, /*Negative=*/false))); 273 EXPECT_FALSE(PosZero.contains(APFloat::getZero(Sem, /*Negative=*/true))); 274 EXPECT_TRUE(NegZero.contains(APFloat::getZero(Sem, /*Negative=*/true))); 275 EXPECT_FALSE(NegZero.contains(APFloat::getZero(Sem, /*Negative=*/false))); 276 EXPECT_TRUE(Zero.contains(PosZero)); 277 EXPECT_TRUE(Zero.contains(NegZero)); 278 EXPECT_TRUE(Denormal.contains(APFloat::getSmallest(Sem))); 279 EXPECT_FALSE(Denormal.contains(APFloat::getSmallestNormalized(Sem))); 280 EXPECT_TRUE(PosInf.contains(APFloat::getInf(Sem, /*Negative=*/false))); 281 EXPECT_TRUE(NegInf.contains(APFloat::getInf(Sem, /*Negative=*/true))); 282 EXPECT_TRUE(NaN.contains(APFloat::getQNaN(Sem))); 283 EXPECT_TRUE(NaN.contains(APFloat::getSNaN(Sem))); 284 EXPECT_TRUE(NaN.contains(SNaN)); 285 EXPECT_TRUE(NaN.contains(QNaN)); 286 287 EXPECT_TRUE(Some.contains(APFloat(3.0))); 288 EXPECT_TRUE(Some.contains(APFloat(-3.0))); 289 EXPECT_FALSE(Some.contains(APFloat(4.0))); 290 APFloat Next1(3.0); 291 Next1.next(/*nextDown=*/true); 292 EXPECT_TRUE(Some.contains(Next1)); 293 APFloat Next2(3.0); 294 Next2.next(/*nextDown=*/false); 295 EXPECT_FALSE(Some.contains(Next2)); 296 EXPECT_TRUE(Some.contains(Zero)); 297 EXPECT_TRUE(Some.contains(Some)); 298 EXPECT_TRUE(Some.contains(One)); 299 EXPECT_FALSE(Some.contains(NaN)); 300 EXPECT_FALSE(Some.contains(PosInf)); 301 EXPECT_TRUE(SomePos.contains(APFloat(3.0))); 302 EXPECT_FALSE(SomeNeg.contains(APFloat(3.0))); 303 EXPECT_TRUE(SomeNeg.contains(APFloat(-3.0))); 304 EXPECT_FALSE(SomePos.contains(APFloat(-3.0))); 305 EXPECT_TRUE(Some.contains(SomePos)); 306 EXPECT_TRUE(Some.contains(SomeNeg)); 307 } 308 309 TEST_F(ConstantFPRangeTest, Equality) { 310 EXPECT_EQ(Full, Full); 311 EXPECT_EQ(Empty, Empty); 312 EXPECT_EQ(One, One); 313 EXPECT_EQ(Some, Some); 314 EXPECT_NE(Full, Empty); 315 EXPECT_NE(Zero, PosZero); 316 EXPECT_NE(One, NaN); 317 EXPECT_NE(Some, One); 318 EXPECT_NE(SNaN, QNaN); 319 } 320 321 TEST_F(ConstantFPRangeTest, SingleElement) { 322 EXPECT_EQ(Full.getSingleElement(), static_cast<APFloat *>(nullptr)); 323 EXPECT_EQ(Empty.getSingleElement(), static_cast<APFloat *>(nullptr)); 324 EXPECT_EQ(Finite.getSingleElement(), static_cast<APFloat *>(nullptr)); 325 EXPECT_EQ(Zero.getSingleElement(), static_cast<APFloat *>(nullptr)); 326 EXPECT_EQ(NaN.getSingleElement(), static_cast<APFloat *>(nullptr)); 327 EXPECT_EQ(SNaN.getSingleElement(), static_cast<APFloat *>(nullptr)); 328 EXPECT_EQ(QNaN.getSingleElement(), static_cast<APFloat *>(nullptr)); 329 330 EXPECT_EQ(*One.getSingleElement(), APFloat(1.0)); 331 EXPECT_EQ(*PosZero.getSingleElement(), APFloat::getZero(Sem)); 332 EXPECT_EQ(*PosInf.getSingleElement(), APFloat::getInf(Sem)); 333 ConstantFPRange PosZeroOrNaN = PosZero.unionWith(NaN); 334 EXPECT_EQ(*PosZeroOrNaN.getSingleElement(/*ExcludesNaN=*/true), 335 APFloat::getZero(Sem)); 336 337 EXPECT_FALSE(Full.isSingleElement()); 338 EXPECT_FALSE(Empty.isSingleElement()); 339 EXPECT_TRUE(One.isSingleElement()); 340 EXPECT_FALSE(Some.isSingleElement()); 341 EXPECT_FALSE(Zero.isSingleElement()); 342 EXPECT_TRUE(PosZeroOrNaN.isSingleElement(/*ExcludesNaN=*/true)); 343 } 344 345 TEST_F(ConstantFPRangeTest, ExhaustivelyEnumerate) { 346 constexpr unsigned NNaNValues = (1 << 8) - 2 * ((1 << 3) - 1); 347 constexpr unsigned Expected = 4 * ((NNaNValues + 1) * NNaNValues / 2 + 1); 348 unsigned Count = 0; 349 EnumerateConstantFPRanges([&](const ConstantFPRange &) { ++Count; }, 350 /*Exhaustive=*/true); 351 EXPECT_EQ(Expected, Count); 352 } 353 354 TEST_F(ConstantFPRangeTest, Enumerate) { 355 constexpr unsigned NNaNValues = 2 * ((1 << 4) - 2 + 4); 356 constexpr unsigned Expected = 4 * ((NNaNValues + 1) * NNaNValues / 2 + 1); 357 unsigned Count = 0; 358 EnumerateConstantFPRanges([&](const ConstantFPRange &) { ++Count; }, 359 /*Exhaustive=*/false); 360 EXPECT_EQ(Expected, Count); 361 } 362 363 TEST_F(ConstantFPRangeTest, IntersectWith) { 364 EXPECT_EQ(Empty.intersectWith(Full), Empty); 365 EXPECT_EQ(Empty.intersectWith(Empty), Empty); 366 EXPECT_EQ(Empty.intersectWith(One), Empty); 367 EXPECT_EQ(Empty.intersectWith(Some), Empty); 368 EXPECT_EQ(Full.intersectWith(Full), Full); 369 EXPECT_EQ(Some.intersectWith(Some), Some); 370 EXPECT_EQ(Some.intersectWith(One), One); 371 EXPECT_EQ(Full.intersectWith(One), One); 372 EXPECT_EQ(Full.intersectWith(Some), Some); 373 EXPECT_EQ(Some.intersectWith(SomePos), SomePos); 374 EXPECT_EQ(Some.intersectWith(SomeNeg), SomeNeg); 375 EXPECT_EQ(NaN.intersectWith(Finite), Empty); 376 EXPECT_EQ(NaN.intersectWith(SNaN), SNaN); 377 EXPECT_EQ(NaN.intersectWith(QNaN), QNaN); 378 EXPECT_EQ(Finite.intersectWith(One), One); 379 EXPECT_EQ(Some.intersectWith(Zero), Zero); 380 EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(4.0)) 381 .intersectWith( 382 ConstantFPRange::getNonNaN(APFloat(3.0), APFloat(6.0))), 383 ConstantFPRange::getNonNaN(APFloat(3.0), APFloat(4.0))); 384 EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0)) 385 .intersectWith( 386 ConstantFPRange::getNonNaN(APFloat(5.0), APFloat(6.0))), 387 Empty); 388 } 389 390 TEST_F(ConstantFPRangeTest, UnionWith) { 391 EXPECT_EQ(Empty.unionWith(Full), Full); 392 EXPECT_EQ(Empty.unionWith(Empty), Empty); 393 EXPECT_EQ(Empty.unionWith(One), One); 394 EXPECT_EQ(Empty.unionWith(Some), Some); 395 EXPECT_EQ(Full.unionWith(Full), Full); 396 EXPECT_EQ(Some.unionWith(Some), Some); 397 EXPECT_EQ(Some.unionWith(One), Some); 398 EXPECT_EQ(Full.unionWith(Some), Full); 399 EXPECT_EQ(Some.unionWith(SomePos), Some); 400 EXPECT_EQ(Some.unionWith(SomeNeg), Some); 401 EXPECT_EQ(Finite.unionWith(One), Finite); 402 EXPECT_EQ(Some.unionWith(Zero), Some); 403 EXPECT_EQ(Finite.unionWith(PosInf).unionWith(NegInf).unionWith(NaN), Full); 404 EXPECT_EQ(PosZero.unionWith(NegZero), Zero); 405 EXPECT_EQ(NaN.unionWith(SNaN), NaN); 406 EXPECT_EQ(NaN.unionWith(QNaN), NaN); 407 EXPECT_EQ(SNaN.unionWith(QNaN), NaN); 408 EXPECT_EQ( 409 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(4.0)) 410 .unionWith(ConstantFPRange::getNonNaN(APFloat(3.0), APFloat(6.0))), 411 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(6.0))); 412 EXPECT_EQ( 413 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0)) 414 .unionWith(ConstantFPRange::getNonNaN(APFloat(5.0), APFloat(6.0))), 415 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(6.0))); 416 } 417 418 TEST_F(ConstantFPRangeTest, FPClassify) { 419 EXPECT_EQ(Empty.classify(), fcNone); 420 EXPECT_EQ(Full.classify(), fcAllFlags); 421 EXPECT_EQ(Finite.classify(), fcFinite); 422 EXPECT_EQ(Zero.classify(), fcZero); 423 EXPECT_EQ(NaN.classify(), fcNan); 424 EXPECT_EQ(SNaN.classify(), fcSNan); 425 EXPECT_EQ(QNaN.classify(), fcQNan); 426 EXPECT_EQ(One.classify(), fcPosNormal); 427 EXPECT_EQ(Some.classify(), fcFinite); 428 EXPECT_EQ(SomePos.classify(), fcPosFinite); 429 EXPECT_EQ(SomeNeg.classify(), fcNegFinite); 430 EXPECT_EQ(PosInf.classify(), fcPosInf); 431 EXPECT_EQ(NegInf.classify(), fcNegInf); 432 EXPECT_EQ(Finite.getSignBit(), std::nullopt); 433 EXPECT_EQ(PosZero.getSignBit(), false); 434 EXPECT_EQ(NegZero.getSignBit(), true); 435 EXPECT_EQ(SomePos.getSignBit(), false); 436 EXPECT_EQ(SomeNeg.getSignBit(), true); 437 438 #if defined(EXPENSIVE_CHECKS) 439 EnumerateConstantFPRanges( 440 [](const ConstantFPRange &CR) { 441 unsigned Mask = fcNone; 442 bool HasPos = false, HasNeg = false; 443 EnumerateValuesInConstantFPRange( 444 CR, 445 [&](const APFloat &V) { 446 Mask |= V.classify(); 447 if (V.isNegative()) 448 HasNeg = true; 449 else 450 HasPos = true; 451 }, 452 /*IgnoreNaNPayload=*/true); 453 454 std::optional<bool> SignBit = std::nullopt; 455 if (HasPos != HasNeg) 456 SignBit = HasNeg; 457 458 EXPECT_EQ(SignBit, CR.getSignBit()) << CR; 459 EXPECT_EQ(Mask, CR.classify()) << CR; 460 }, 461 /*Exhaustive=*/true); 462 #endif 463 } 464 465 TEST_F(ConstantFPRangeTest, Print) { 466 auto ToString = [](const ConstantFPRange &CR) { 467 std::string Str; 468 raw_string_ostream OS(Str); 469 CR.print(OS); 470 return Str; 471 }; 472 473 EXPECT_EQ(ToString(Full), "full-set"); 474 EXPECT_EQ(ToString(Empty), "empty-set"); 475 EXPECT_EQ(ToString(NaN), "NaN"); 476 EXPECT_EQ(ToString(SNaN), "SNaN"); 477 EXPECT_EQ(ToString(QNaN), "QNaN"); 478 EXPECT_EQ(ToString(One), "[1, 1]"); 479 EXPECT_EQ(ToString(Some.unionWith(SNaN)), "[-3, 3] with SNaN"); 480 } 481 482 #ifdef GTEST_HAS_DEATH_TEST 483 #ifndef NDEBUG 484 TEST_F(ConstantFPRangeTest, NonCanonicalEmptySet) { 485 EXPECT_DEATH((void)(ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(0.0))), 486 "Non-canonical form"); 487 } 488 TEST_F(ConstantFPRangeTest, MismatchedSemantics) { 489 EXPECT_DEATH((void)(ConstantFPRange::getNonNaN(APFloat(0.0), APFloat(1.0f))), 490 "Should only use the same semantics"); 491 EXPECT_DEATH((void)(One.contains(APFloat(1.0f))), 492 "Should only use the same semantics"); 493 ConstantFPRange OneF32 = ConstantFPRange(APFloat(1.0f)); 494 EXPECT_DEATH((void)(One.contains(OneF32)), 495 "Should only use the same semantics"); 496 EXPECT_DEATH((void)(One.intersectWith(OneF32)), 497 "Should only use the same semantics"); 498 EXPECT_DEATH((void)(One.unionWith(OneF32)), 499 "Should only use the same semantics"); 500 } 501 #endif 502 #endif 503 504 TEST_F(ConstantFPRangeTest, makeAllowedFCmpRegion) { 505 EXPECT_EQ(ConstantFPRange::makeAllowedFCmpRegion( 506 FCmpInst::FCMP_OLE, 507 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))), 508 ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true), 509 APFloat(2.0))); 510 EXPECT_EQ( 511 ConstantFPRange::makeAllowedFCmpRegion( 512 FCmpInst::FCMP_OLT, 513 ConstantFPRange::getNonNaN(APFloat(1.0), 514 APFloat::getInf(Sem, /*Negative=*/false))), 515 ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true), 516 APFloat::getLargest(Sem, /*Negative=*/false))); 517 EXPECT_EQ( 518 ConstantFPRange::makeAllowedFCmpRegion( 519 FCmpInst::FCMP_OGT, 520 ConstantFPRange::getNonNaN(APFloat::getZero(Sem, /*Negative=*/true), 521 APFloat(2.0))), 522 ConstantFPRange::getNonNaN(APFloat::getSmallest(Sem, /*Negative=*/false), 523 APFloat::getInf(Sem, /*Negative=*/false))); 524 EXPECT_EQ(ConstantFPRange::makeAllowedFCmpRegion( 525 FCmpInst::FCMP_OGE, 526 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))), 527 ConstantFPRange::getNonNaN( 528 APFloat(1.0), APFloat::getInf(Sem, /*Negative=*/false))); 529 EXPECT_EQ(ConstantFPRange::makeAllowedFCmpRegion( 530 FCmpInst::FCMP_OEQ, 531 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))), 532 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))); 533 534 #if defined(EXPENSIVE_CHECKS) 535 for (auto Pred : FCmpInst::predicates()) { 536 EnumerateConstantFPRanges( 537 [Pred](const ConstantFPRange &CR) { 538 ConstantFPRange Res = 539 ConstantFPRange::makeAllowedFCmpRegion(Pred, CR); 540 ConstantFPRange Optimal = 541 ConstantFPRange::getEmpty(CR.getSemantics()); 542 EnumerateValuesInConstantFPRange( 543 ConstantFPRange::getFull(CR.getSemantics()), 544 [&](const APFloat &V) { 545 if (AnyOfValueInConstantFPRange( 546 CR, 547 [&](const APFloat &U) { 548 return FCmpInst::compare(V, U, Pred); 549 }, 550 /*IgnoreNaNPayload=*/true)) 551 Optimal = Optimal.unionWith(ConstantFPRange(V)); 552 }, 553 /*IgnoreNaNPayload=*/true); 554 555 EXPECT_TRUE(Res.contains(Optimal)) 556 << "Wrong result for makeAllowedFCmpRegion(" << Pred << ", " << CR 557 << "). Expected " << Optimal << ", but got " << Res; 558 EXPECT_EQ(Res, Optimal) 559 << "Suboptimal result for makeAllowedFCmpRegion(" << Pred << ", " 560 << CR << ")"; 561 }, 562 /*Exhaustive=*/false); 563 } 564 #endif 565 } 566 567 TEST_F(ConstantFPRangeTest, makeSatisfyingFCmpRegion) { 568 EXPECT_EQ(ConstantFPRange::makeSatisfyingFCmpRegion( 569 FCmpInst::FCMP_OLE, 570 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))), 571 ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true), 572 APFloat(1.0))); 573 EXPECT_EQ( 574 ConstantFPRange::makeSatisfyingFCmpRegion( 575 FCmpInst::FCMP_OLT, ConstantFPRange::getNonNaN( 576 APFloat::getSmallest(Sem, /*Negative=*/false), 577 APFloat::getInf(Sem, /*Negative=*/false))), 578 ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true), 579 APFloat::getZero(Sem, /*Negative=*/false))); 580 EXPECT_EQ( 581 ConstantFPRange::makeSatisfyingFCmpRegion( 582 FCmpInst::FCMP_OGT, ConstantFPRange::getNonNaN( 583 APFloat::getZero(Sem, /*Negative=*/true), 584 APFloat::getZero(Sem, /*Negative=*/false))), 585 ConstantFPRange::getNonNaN(APFloat::getSmallest(Sem, /*Negative=*/false), 586 APFloat::getInf(Sem, /*Negative=*/false))); 587 EXPECT_EQ(ConstantFPRange::makeSatisfyingFCmpRegion( 588 FCmpInst::FCMP_OGE, 589 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))), 590 ConstantFPRange::getNonNaN( 591 APFloat(2.0), APFloat::getInf(Sem, /*Negative=*/false))); 592 EXPECT_EQ(ConstantFPRange::makeSatisfyingFCmpRegion( 593 FCmpInst::FCMP_OEQ, 594 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))), 595 ConstantFPRange::getEmpty(Sem)); 596 EXPECT_EQ(ConstantFPRange::makeSatisfyingFCmpRegion( 597 FCmpInst::FCMP_OEQ, 598 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(1.0))), 599 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(1.0))); 600 601 #if defined(EXPENSIVE_CHECKS) 602 for (auto Pred : FCmpInst::predicates()) { 603 EnumerateConstantFPRanges( 604 [Pred](const ConstantFPRange &CR) { 605 ConstantFPRange Res = 606 ConstantFPRange::makeSatisfyingFCmpRegion(Pred, CR); 607 // Super set of the optimal set excluding NaNs 608 ConstantFPRange SuperSet(CR.getSemantics()); 609 bool ContainsSNaN = false; 610 bool ContainsQNaN = false; 611 unsigned NonNaNValsInOptimalSet = 0; 612 EnumerateValuesInConstantFPRange( 613 ConstantFPRange::getFull(CR.getSemantics()), 614 [&](const APFloat &V) { 615 if (AnyOfValueInConstantFPRange( 616 CR, 617 [&](const APFloat &U) { 618 return !FCmpInst::compare(V, U, Pred); 619 }, 620 /*IgnoreNaNPayload=*/true)) { 621 EXPECT_FALSE(Res.contains(V)) 622 << "Wrong result for makeSatisfyingFCmpRegion(" << Pred 623 << ", " << CR << "). The result " << Res 624 << " should not contain " << V; 625 } else { 626 if (V.isNaN()) { 627 if (V.isSignaling()) 628 ContainsSNaN = true; 629 else 630 ContainsQNaN = true; 631 } else { 632 SuperSet = SuperSet.unionWith(ConstantFPRange(V)); 633 ++NonNaNValsInOptimalSet; 634 } 635 } 636 }, 637 /*IgnoreNaNPayload=*/true); 638 639 // Check optimality 640 641 // The usefullness of making the result optimal for one/une is 642 // questionable. 643 if (Pred == FCmpInst::FCMP_ONE || Pred == FCmpInst::FCMP_UNE) 644 return; 645 646 EXPECT_FALSE(ContainsSNaN && !Res.containsSNaN()) 647 << "Suboptimal result for makeSatisfyingFCmpRegion(" << Pred 648 << ", " << CR << "), should contain SNaN, but got " << Res; 649 EXPECT_FALSE(ContainsQNaN && !Res.containsQNaN()) 650 << "Suboptimal result for makeSatisfyingFCmpRegion(" << Pred 651 << ", " << CR << "), should contain QNaN, but got " << Res; 652 653 // We only care about the cases where the result is representable by 654 // ConstantFPRange. 655 unsigned NonNaNValsInSuperSet = 0; 656 EnumerateValuesInConstantFPRange( 657 SuperSet, 658 [&](const APFloat &V) { 659 if (!V.isNaN()) 660 ++NonNaNValsInSuperSet; 661 }, 662 /*IgnoreNaNPayload=*/true); 663 664 if (NonNaNValsInSuperSet == NonNaNValsInOptimalSet) { 665 ConstantFPRange Optimal = 666 ConstantFPRange(SuperSet.getLower(), SuperSet.getUpper(), 667 ContainsQNaN, ContainsSNaN); 668 EXPECT_EQ(Res, Optimal) 669 << "Suboptimal result for makeSatisfyingFCmpRegion(" << Pred 670 << ", " << CR << ")"; 671 } 672 }, 673 /*Exhaustive=*/false); 674 } 675 #endif 676 } 677 678 TEST_F(ConstantFPRangeTest, fcmp) { 679 std::vector<ConstantFPRange> InterestingRanges; 680 const fltSemantics &Sem = APFloat::Float8E4M3(); 681 auto FpImm = [&](double V) { 682 bool ignored; 683 APFloat APF(V); 684 APF.convert(Sem, APFloat::rmNearestTiesToEven, &ignored); 685 return APF; 686 }; 687 688 InterestingRanges.push_back(ConstantFPRange::getEmpty(Sem)); 689 InterestingRanges.push_back(ConstantFPRange::getFull(Sem)); 690 InterestingRanges.push_back(ConstantFPRange::getFinite(Sem)); 691 InterestingRanges.push_back(ConstantFPRange(FpImm(1.0))); 692 InterestingRanges.push_back( 693 ConstantFPRange(APFloat::getZero(Sem, /*Negative=*/false))); 694 InterestingRanges.push_back( 695 ConstantFPRange(APFloat::getZero(Sem, /*Negative=*/true))); 696 InterestingRanges.push_back( 697 ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/false))); 698 InterestingRanges.push_back( 699 ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/true))); 700 InterestingRanges.push_back( 701 ConstantFPRange(APFloat::getSmallest(Sem, /*Negative=*/false))); 702 InterestingRanges.push_back( 703 ConstantFPRange(APFloat::getSmallest(Sem, /*Negative=*/true))); 704 InterestingRanges.push_back( 705 ConstantFPRange(APFloat::getLargest(Sem, /*Negative=*/false))); 706 InterestingRanges.push_back( 707 ConstantFPRange(APFloat::getLargest(Sem, /*Negative=*/true))); 708 InterestingRanges.push_back( 709 ConstantFPRange::getNaNOnly(Sem, /*MayBeQNaN=*/true, /*MayBeSNaN=*/true)); 710 InterestingRanges.push_back( 711 ConstantFPRange::getNonNaN(FpImm(0.0), FpImm(1.0))); 712 InterestingRanges.push_back( 713 ConstantFPRange::getNonNaN(FpImm(2.0), FpImm(3.0))); 714 InterestingRanges.push_back( 715 ConstantFPRange::getNonNaN(FpImm(-1.0), FpImm(1.0))); 716 InterestingRanges.push_back( 717 ConstantFPRange::getNonNaN(FpImm(-1.0), FpImm(-0.0))); 718 InterestingRanges.push_back(ConstantFPRange::getNonNaN( 719 APFloat::getInf(Sem, /*Negative=*/true), FpImm(-1.0))); 720 InterestingRanges.push_back(ConstantFPRange::getNonNaN( 721 FpImm(1.0), APFloat::getInf(Sem, /*Negative=*/false))); 722 723 for (auto &LHS : InterestingRanges) { 724 for (auto &RHS : InterestingRanges) { 725 for (auto Pred : FCmpInst::predicates()) { 726 if (LHS.fcmp(Pred, RHS)) { 727 EnumerateValuesInConstantFPRange( 728 LHS, 729 [&](const APFloat &LHSC) { 730 EnumerateValuesInConstantFPRange( 731 RHS, 732 [&](const APFloat &RHSC) { 733 EXPECT_TRUE(FCmpInst::compare(LHSC, RHSC, Pred)) 734 << LHS << " " << Pred << " " << RHS 735 << " doesn't hold"; 736 }, 737 /*IgnoreNaNPayload=*/true); 738 }, 739 /*IgnoreNaNPayload=*/true); 740 } 741 } 742 } 743 } 744 } 745 746 TEST_F(ConstantFPRangeTest, makeExactFCmpRegion) { 747 for (auto Pred : FCmpInst::predicates()) { 748 EnumerateValuesInConstantFPRange( 749 ConstantFPRange::getFull(APFloat::Float8E4M3()), 750 [Pred](const APFloat &V) { 751 std::optional<ConstantFPRange> Res = 752 ConstantFPRange::makeExactFCmpRegion(Pred, V); 753 ConstantFPRange Allowed = 754 ConstantFPRange::makeAllowedFCmpRegion(Pred, ConstantFPRange(V)); 755 ConstantFPRange Satisfying = 756 ConstantFPRange::makeSatisfyingFCmpRegion(Pred, 757 ConstantFPRange(V)); 758 if (Allowed == Satisfying) 759 EXPECT_EQ(Res, Allowed) << "Wrong result for makeExactFCmpRegion(" 760 << Pred << ", " << V << ")."; 761 else 762 EXPECT_FALSE(Res.has_value()) 763 << "Wrong result for makeExactFCmpRegion(" << Pred << ", " << V 764 << ")."; 765 }, 766 /*IgnoreNaNPayload=*/true); 767 } 768 } 769 770 } // anonymous namespace 771