xref: /llvm-project/llvm/unittests/IR/ConstantFPRangeTest.cpp (revision a3a253d3c7780977077dd46493917b1949c0166d)
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