[TableGen][GISel] Add const to some member functions & reformat (NFC) (#120899)
[llvm-project.git] / llvm / unittests / IR / ConstantFPRangeTest.cpp
blob255f62d77b748d6b7f5db7aaa439924b994470dd
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 //===----------------------------------------------------------------------===//
9 #include "llvm/IR/ConstantFPRange.h"
10 #include "llvm/IR/Instructions.h"
11 #include "llvm/IR/Operator.h"
12 #include "gtest/gtest.h"
14 using namespace llvm;
16 namespace {
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;
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));
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);
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));
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;
112 auto Next = [&](APFloat &V) {
113 if (V.isPosInfinity())
114 return false;
115 strictNext(V);
116 return true;
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));
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);
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);
148 Exhaustive);
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));
160 if (CR.containsQNaN()) {
161 TestFn(APFloat::getQNaN(Sem, false));
162 TestFn(APFloat::getQNaN(Sem, true));
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;
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);
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;
199 if (CR.containsQNaN()) {
200 if (TestFn(APFloat::getQNaN(Sem, false)))
201 return true;
202 if (TestFn(APFloat::getQNaN(Sem, true)))
203 return true;
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;
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;
228 return false;
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));
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));
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));
269 EXPECT_TRUE(One.contains(APFloat(1.0)));
270 EXPECT_FALSE(One.contains(APFloat(1.1)));
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));
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));
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);
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));
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));
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));
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);
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);
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);
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)));
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);
438 #if defined(EXPENSIVE_CHECKS)
439 EnumerateConstantFPRanges(
440 [](const ConstantFPRange &CR) {
441 unsigned Mask = fcNone;
442 bool HasPos = false, HasNeg = false;
443 EnumerateValuesInConstantFPRange(
445 [&](const APFloat &V) {
446 Mask |= V.classify();
447 if (V.isNegative())
448 HasNeg = true;
449 else
450 HasPos = true;
452 /*IgnoreNaNPayload=*/true);
454 std::optional<bool> SignBit = std::nullopt;
455 if (HasPos != HasNeg)
456 SignBit = HasNeg;
458 EXPECT_EQ(SignBit, CR.getSignBit()) << CR;
459 EXPECT_EQ(Mask, CR.classify()) << CR;
461 /*Exhaustive=*/true);
462 #endif
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;
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");
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");
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");
501 #endif
502 #endif
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)));
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(
547 [&](const APFloat &U) {
548 return FCmpInst::compare(V, U, Pred);
550 /*IgnoreNaNPayload=*/true))
551 Optimal = Optimal.unionWith(ConstantFPRange(V));
553 /*IgnoreNaNPayload=*/true);
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 << ")";
562 /*Exhaustive=*/false);
564 #endif
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)));
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(
617 [&](const APFloat &U) {
618 return !FCmpInst::compare(V, U, Pred);
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;
637 /*IgnoreNaNPayload=*/true);
639 // Check optimality
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;
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;
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;
662 /*IgnoreNaNPayload=*/true);
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 << ")";
673 /*Exhaustive=*/false);
675 #endif
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;
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)));
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";
737 /*IgnoreNaNPayload=*/true);
739 /*IgnoreNaNPayload=*/true);
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 << ").";
766 /*IgnoreNaNPayload=*/true);
770 } // anonymous namespace