1 //===- ConstantRangeTest.cpp - ConstantRange tests ------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/IR/ConstantFPRange.h"
10 #include "llvm/IR/Instructions.h"
11 #include "llvm/IR/Operator.h"
12 #include "gtest/gtest.h"
18 class ConstantFPRangeTest
: public ::testing::Test
{
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.
76 V
= APFloat::getZero(V
.getSemantics(), /*Negative=*/false);
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
));
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
)
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
));
112 auto Next
= [&](APFloat
&V
) {
113 if (V
.isPosInfinity())
119 APFloat Lower
= NegInf
;
121 APFloat Upper
= Lower
;
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,
134 EnumerateConstantFPRangesImpl(TestFn
, Exhaustive
, /*MayBeQNaN=*/true,
135 /*MayBeSNaN=*/false);
136 EnumerateConstantFPRangesImpl(TestFn
, Exhaustive
, /*MayBeQNaN=*/true,
140 template <typename Fn
>
141 static void EnumerateTwoInterestingConstantFPRanges(Fn TestFn
,
143 EnumerateConstantFPRanges(
144 [&](const ConstantFPRange
&CR1
) {
145 EnumerateConstantFPRanges(
146 [&](const ConstantFPRange
&CR2
) { TestFn(CR1
, CR2
); }, 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));
166 APFloat Lower
= CR
.getLower();
167 const APFloat
&Upper
= CR
.getUpper();
168 auto Next
= [&](APFloat
&V
) {
169 if (V
.bitwiseIsEqual(Upper
))
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
));
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)))
196 if (TestFn(APFloat::getSNaN(Sem
, true)))
199 if (CR
.containsQNaN()) {
200 if (TestFn(APFloat::getQNaN(Sem
, false)))
202 if (TestFn(APFloat::getQNaN(Sem
, true)))
207 APFloat Lower
= CR
.getLower();
208 const APFloat
&Upper
= CR
.getUpper();
209 auto Next
= [&](APFloat
&V
) {
210 if (V
.bitwiseIsEqual(Upper
))
218 } while (Next(Lower
));
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
))
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)));
291 Next1
.next(/*nextDown=*/true);
292 EXPECT_TRUE(Some
.contains(Next1
));
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
);
313 EXPECT_EQ(Some
, Some
);
314 EXPECT_NE(Full
, Empty
);
315 EXPECT_NE(Zero
, PosZero
);
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);
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);
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))
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))
386 ConstantFPRange::getNonNaN(APFloat(5.0), APFloat(6.0))),
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
);
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)));
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();
452 /*IgnoreNaNPayload=*/true);
454 std::optional
<bool> SignBit
= std::nullopt
;
455 if (HasPos
!= HasNeg
)
458 EXPECT_EQ(SignBit
, CR
.getSignBit()) << CR
;
459 EXPECT_EQ(Mask
, CR
.classify()) << CR
;
461 /*Exhaustive=*/true);
465 TEST_F(ConstantFPRangeTest
, Print
) {
466 auto ToString
= [](const ConstantFPRange
&CR
) {
468 raw_string_ostream
OS(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
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");
504 TEST_F(ConstantFPRangeTest
, makeAllowedFCmpRegion
) {
505 EXPECT_EQ(ConstantFPRange::makeAllowedFCmpRegion(
507 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))),
508 ConstantFPRange::getNonNaN(APFloat::getInf(Sem
, /*Negative=*/true),
511 ConstantFPRange::makeAllowedFCmpRegion(
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)));
518 ConstantFPRange::makeAllowedFCmpRegion(
520 ConstantFPRange::getNonNaN(APFloat::getZero(Sem
, /*Negative=*/true),
522 ConstantFPRange::getNonNaN(APFloat::getSmallest(Sem
, /*Negative=*/false),
523 APFloat::getInf(Sem
, /*Negative=*/false)));
524 EXPECT_EQ(ConstantFPRange::makeAllowedFCmpRegion(
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(
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
<< ", "
562 /*Exhaustive=*/false);
567 TEST_F(ConstantFPRangeTest
, makeSatisfyingFCmpRegion
) {
568 EXPECT_EQ(ConstantFPRange::makeSatisfyingFCmpRegion(
570 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))),
571 ConstantFPRange::getNonNaN(APFloat::getInf(Sem
, /*Negative=*/true),
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)));
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(
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(
594 ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))),
595 ConstantFPRange::getEmpty(Sem
));
596 EXPECT_EQ(ConstantFPRange::makeSatisfyingFCmpRegion(
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
;
632 SuperSet
= SuperSet
.unionWith(ConstantFPRange(V
));
633 ++NonNaNValsInOptimalSet
;
637 /*IgnoreNaNPayload=*/true);
641 // The usefullness of making the result optimal for one/une is
643 if (Pred
== FCmpInst::FCMP_ONE
|| Pred
== FCmpInst::FCMP_UNE
)
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
655 unsigned NonNaNValsInSuperSet
= 0;
656 EnumerateValuesInConstantFPRange(
658 [&](const APFloat
&V
) {
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);
678 TEST_F(ConstantFPRangeTest
, fcmp
) {
679 std::vector
<ConstantFPRange
> InterestingRanges
;
680 const fltSemantics
&Sem
= APFloat::Float8E4M3();
681 auto FpImm
= [&](double V
) {
684 APF
.convert(Sem
, APFloat::rmNearestTiesToEven
, &ignored
);
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(
729 [&](const APFloat
&LHSC
) {
730 EnumerateValuesInConstantFPRange(
732 [&](const APFloat
&RHSC
) {
733 EXPECT_TRUE(FCmpInst::compare(LHSC
, RHSC
, Pred
))
734 << LHS
<< " " << Pred
<< " " << RHS
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
,
758 if (Allowed
== Satisfying
)
759 EXPECT_EQ(Res
, Allowed
) << "Wrong result for makeExactFCmpRegion("
760 << Pred
<< ", " << V
<< ").";
762 EXPECT_FALSE(Res
.has_value())
763 << "Wrong result for makeExactFCmpRegion(" << Pred
<< ", " << V
766 /*IgnoreNaNPayload=*/true);
770 } // anonymous namespace