Skip to content

Commit e2bdba2

Browse files
committed
[ConstantFPRange] Add basic unit tests.
1 parent b4eb25f commit e2bdba2

File tree

4 files changed

+312
-13
lines changed

4 files changed

+312
-13
lines changed

llvm/include/llvm/IR/ConstantFPRange.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class [[nodiscard]] ConstantFPRange {
6161

6262
/// Initialize a range of values explicitly.
6363
ConstantFPRange(APFloat LowerVal, APFloat UpperVal, bool MayBeQNaN = true,
64-
bool MaybeSNaN = true);
64+
bool MayBeSNaN = true);
6565

6666
/// Create empty constant range with the given semantics.
6767
static ConstantFPRange getEmpty(const fltSemantics &Sem) {
@@ -73,6 +73,15 @@ class [[nodiscard]] ConstantFPRange {
7373
return ConstantFPRange(Sem, /*IsFullSet=*/true);
7474
}
7575

76+
/// Helper for (-inf, inf) to represent all finite values.
77+
static ConstantFPRange getFinite(const fltSemantics &Sem);
78+
79+
/// Create a range which doesn't contain NaNs.
80+
static ConstantFPRange getNonNaN(APFloat LowerVal, APFloat UpperVal) {
81+
return ConstantFPRange(std::move(LowerVal), std::move(UpperVal),
82+
/*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
83+
}
84+
7685
/// Produce the smallest range such that all values that may satisfy the given
7786
/// predicate with any value contained within Other is contained in the
7887
/// returned range. Formally, this returns a superset of
@@ -167,9 +176,6 @@ class [[nodiscard]] ConstantFPRange {
167176
/// with another range. The resultant range is guaranteed to include the
168177
/// elements of both sets, but may contain more.
169178
ConstantFPRange unionWith(const ConstantFPRange &CR) const;
170-
171-
/// Return a new range that is the logical not of the current set.
172-
ConstantFPRange inverse() const;
173179
};
174180

175181
inline raw_ostream &operator<<(raw_ostream &OS, const ConstantFPRange &CR) {

llvm/lib/IR/ConstantFPRange.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
using namespace llvm;
1717

18-
// A floating point format must supports NaN, Inf and -0.
18+
// A floating point format must support NaN, Inf and -0.
1919
bool ConstantFPRange::isSupportedSemantics(const fltSemantics &Sem) {
2020
switch (APFloat::SemanticsToEnum(Sem)) {
2121
default:
@@ -65,9 +65,9 @@ ConstantFPRange::ConstantFPRange(const APFloat &Value)
6565

6666
if (Value.isNaN()) {
6767
makeEmpty();
68-
bool isSNaN = Value.isSignaling();
69-
MayBeQNaN = !isSNaN;
70-
MayBeSNaN = isSNaN;
68+
bool IsSNaN = Value.isSignaling();
69+
MayBeQNaN = !IsSNaN;
70+
MayBeSNaN = IsSNaN;
7171
} else {
7272
Lower = Upper = Value;
7373
MayBeQNaN = MayBeSNaN = false;
@@ -87,7 +87,7 @@ static APFloat::cmpResult strictCompare(const APFloat &LHS,
8787
}
8888

8989
ConstantFPRange::ConstantFPRange(APFloat LowerVal, APFloat UpperVal,
90-
bool MayBeQNaN, bool MaybeSNaN)
90+
bool MayBeQNaN, bool MayBeSNaN)
9191
: Lower(std::move(LowerVal)), Upper(std::move(UpperVal)) {
9292
assert(isSupportedSemantics(getSemantics()) && "Unsupported fp format");
9393

@@ -99,6 +99,12 @@ ConstantFPRange::ConstantFPRange(APFloat LowerVal, APFloat UpperVal,
9999
this->MayBeSNaN = MayBeSNaN;
100100
}
101101

102+
ConstantFPRange ConstantFPRange::getFinite(const fltSemantics &Sem) {
103+
return ConstantFPRange(APFloat::getLargest(Sem, /*Negative=*/true),
104+
APFloat::getLargest(Sem, /*Negative=*/false),
105+
/*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
106+
}
107+
102108
ConstantFPRange
103109
ConstantFPRange::makeAllowedFCmpRegion(FCmpInst::Predicate Pred,
104110
const ConstantFPRange &Other) {
@@ -207,10 +213,12 @@ void ConstantFPRange::print(raw_ostream &OS) const {
207213
bool NaNOnly = isNaNOnly();
208214
if (!NaNOnly) {
209215
OS << '[';
210-
Lower.print(OS);
211-
OS << ", ";
212-
Upper.print(OS);
213-
OS << ']';
216+
SmallVector<char, 16> Buffer;
217+
Lower.toString(Buffer);
218+
OS << Buffer << ", ";
219+
Buffer.clear();
220+
Upper.toString(Buffer);
221+
OS << Buffer << ']';
214222
}
215223

216224
if (MayBeSNaN || MayBeQNaN) {

llvm/unittests/IR/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ add_llvm_unittest(IRTests
1616
BasicBlockTest.cpp
1717
BasicBlockDbgInfoTest.cpp
1818
CFGBuilder.cpp
19+
ConstantFPRangeTest.cpp
1920
ConstantRangeTest.cpp
2021
ConstantRangeListTest.cpp
2122
ConstantsTest.cpp
Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
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/ADT/BitVector.h"
11+
#include "llvm/ADT/Sequence.h"
12+
#include "llvm/ADT/SmallBitVector.h"
13+
#include "llvm/Analysis/ValueTracking.h"
14+
#include "llvm/IR/Instructions.h"
15+
#include "llvm/IR/Operator.h"
16+
#include "llvm/Support/KnownBits.h"
17+
#include "gtest/gtest.h"
18+
19+
using namespace llvm;
20+
21+
namespace {
22+
23+
class ConstantFPRangeTest : public ::testing::Test {
24+
protected:
25+
static const fltSemantics &Sem;
26+
static ConstantFPRange Full;
27+
static ConstantFPRange Empty;
28+
static ConstantFPRange Finite;
29+
static ConstantFPRange One;
30+
static ConstantFPRange PosZero;
31+
static ConstantFPRange NegZero;
32+
static ConstantFPRange Zero;
33+
static ConstantFPRange PosInf;
34+
static ConstantFPRange NegInf;
35+
static ConstantFPRange Denormal;
36+
static ConstantFPRange NaN;
37+
static ConstantFPRange SNaN;
38+
static ConstantFPRange QNaN;
39+
static ConstantFPRange Some;
40+
static ConstantFPRange SomePos;
41+
static ConstantFPRange SomeNeg;
42+
};
43+
44+
const fltSemantics &ConstantFPRangeTest::Sem = APFloat::IEEEdouble();
45+
ConstantFPRange ConstantFPRangeTest::Full =
46+
ConstantFPRange::getFull(APFloat::IEEEdouble());
47+
ConstantFPRange ConstantFPRangeTest::Empty =
48+
ConstantFPRange::getEmpty(APFloat::IEEEdouble());
49+
ConstantFPRange ConstantFPRangeTest::Finite =
50+
ConstantFPRange::getFinite(APFloat::IEEEdouble());
51+
ConstantFPRange ConstantFPRangeTest::One = ConstantFPRange(APFloat(1.0));
52+
ConstantFPRange ConstantFPRangeTest::PosZero = ConstantFPRange(
53+
APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/false));
54+
ConstantFPRange ConstantFPRangeTest::NegZero =
55+
ConstantFPRange(APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/true));
56+
ConstantFPRange ConstantFPRangeTest::Zero = ConstantFPRange::getNonNaN(
57+
APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/true),
58+
APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/false));
59+
ConstantFPRange ConstantFPRangeTest::Denormal =
60+
ConstantFPRange(APFloat::getSmallest(APFloat::IEEEdouble()));
61+
ConstantFPRange ConstantFPRangeTest::PosInf =
62+
ConstantFPRange(APFloat::getInf(APFloat::IEEEdouble(), /*Negative=*/false));
63+
ConstantFPRange ConstantFPRangeTest::NegInf =
64+
ConstantFPRange(APFloat::getInf(APFloat::IEEEdouble(), /*Negative=*/true));
65+
ConstantFPRange ConstantFPRangeTest::NaN =
66+
ConstantFPRange(APFloat(1.0), APFloat(-1.0));
67+
ConstantFPRange ConstantFPRangeTest::SNaN =
68+
ConstantFPRange(APFloat::getSNaN(APFloat::IEEEdouble()));
69+
ConstantFPRange ConstantFPRangeTest::QNaN =
70+
ConstantFPRange(APFloat::getQNaN(APFloat::IEEEdouble()));
71+
ConstantFPRange ConstantFPRangeTest::Some =
72+
ConstantFPRange::getNonNaN(APFloat(-3.0), APFloat(3.0));
73+
ConstantFPRange ConstantFPRangeTest::SomePos = ConstantFPRange::getNonNaN(
74+
APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/false), APFloat(3.0));
75+
ConstantFPRange ConstantFPRangeTest::SomeNeg = ConstantFPRange::getNonNaN(
76+
APFloat(-3.0), APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/true));
77+
78+
TEST_F(ConstantFPRangeTest, Basics) {
79+
EXPECT_TRUE(Full.isFullSet());
80+
EXPECT_FALSE(Full.isEmptySet());
81+
EXPECT_TRUE(Full.contains(APFloat::getNaN(Sem)));
82+
EXPECT_TRUE(Full.contains(APFloat::getInf(Sem, /*Negative=*/false)));
83+
EXPECT_TRUE(Full.contains(APFloat::getInf(Sem, /*Negative=*/true)));
84+
EXPECT_TRUE(Full.contains(APFloat::getZero(Sem, /*Negative=*/false)));
85+
EXPECT_TRUE(Full.contains(APFloat::getZero(Sem, /*Negative=*/true)));
86+
EXPECT_TRUE(Full.contains(APFloat::getSmallest(Sem)));
87+
EXPECT_TRUE(Full.contains(APFloat(2.0)));
88+
EXPECT_TRUE(Full.contains(Full));
89+
EXPECT_TRUE(Full.contains(Empty));
90+
EXPECT_TRUE(Full.contains(Finite));
91+
EXPECT_TRUE(Full.contains(Zero));
92+
EXPECT_TRUE(Full.contains(Some));
93+
94+
EXPECT_FALSE(Empty.isFullSet());
95+
EXPECT_TRUE(Empty.isEmptySet());
96+
EXPECT_FALSE(Empty.contains(APFloat::getNaN(Sem)));
97+
EXPECT_FALSE(Empty.contains(APFloat::getInf(Sem, /*Negative=*/false)));
98+
EXPECT_FALSE(Empty.contains(APFloat::getZero(Sem, /*Negative=*/true)));
99+
EXPECT_FALSE(Empty.contains(APFloat(2.0)));
100+
EXPECT_TRUE(Empty.contains(Empty));
101+
102+
EXPECT_FALSE(Finite.isFullSet());
103+
EXPECT_FALSE(Finite.isEmptySet());
104+
EXPECT_FALSE(Finite.contains(APFloat::getNaN(Sem)));
105+
EXPECT_FALSE(Finite.contains(APFloat::getInf(Sem, /*Negative=*/false)));
106+
EXPECT_FALSE(Finite.contains(APFloat::getInf(Sem, /*Negative=*/true)));
107+
EXPECT_TRUE(Finite.contains(APFloat::getLargest(Sem, /*Negative=*/false)));
108+
EXPECT_TRUE(Finite.contains(APFloat::getLargest(Sem, /*Negative=*/true)));
109+
EXPECT_TRUE(Finite.contains(Finite));
110+
EXPECT_TRUE(Finite.contains(Some));
111+
EXPECT_TRUE(Finite.contains(Denormal));
112+
EXPECT_TRUE(Finite.contains(Zero));
113+
EXPECT_FALSE(Finite.contains(PosInf));
114+
EXPECT_FALSE(Finite.contains(NaN));
115+
116+
EXPECT_TRUE(One.contains(APFloat(1.0)));
117+
EXPECT_FALSE(One.contains(APFloat(1.1)));
118+
119+
EXPECT_TRUE(PosZero.contains(APFloat::getZero(Sem, /*Negative=*/false)));
120+
EXPECT_FALSE(PosZero.contains(APFloat::getZero(Sem, /*Negative=*/true)));
121+
EXPECT_TRUE(NegZero.contains(APFloat::getZero(Sem, /*Negative=*/true)));
122+
EXPECT_FALSE(NegZero.contains(APFloat::getZero(Sem, /*Negative=*/false)));
123+
EXPECT_TRUE(Zero.contains(PosZero));
124+
EXPECT_TRUE(Zero.contains(NegZero));
125+
EXPECT_TRUE(Denormal.contains(APFloat::getSmallest(Sem)));
126+
EXPECT_FALSE(Denormal.contains(APFloat::getSmallestNormalized(Sem)));
127+
EXPECT_TRUE(PosInf.contains(APFloat::getInf(Sem, /*Negative=*/false)));
128+
EXPECT_TRUE(NegInf.contains(APFloat::getInf(Sem, /*Negative=*/true)));
129+
EXPECT_TRUE(NaN.contains(APFloat::getQNaN(Sem)));
130+
EXPECT_TRUE(NaN.contains(APFloat::getSNaN(Sem)));
131+
EXPECT_TRUE(NaN.contains(SNaN));
132+
EXPECT_TRUE(NaN.contains(QNaN));
133+
134+
EXPECT_TRUE(Some.contains(APFloat(3.0)));
135+
EXPECT_TRUE(Some.contains(APFloat(-3.0)));
136+
EXPECT_FALSE(Some.contains(APFloat(4.0)));
137+
APFloat Next1(3.0);
138+
Next1.next(/*nextDown=*/true);
139+
EXPECT_TRUE(Some.contains(Next1));
140+
APFloat Next2(3.0);
141+
Next2.next(/*nextDown=*/false);
142+
EXPECT_FALSE(Some.contains(Next2));
143+
EXPECT_TRUE(Some.contains(Zero));
144+
EXPECT_TRUE(Some.contains(Some));
145+
EXPECT_TRUE(Some.contains(One));
146+
EXPECT_FALSE(Some.contains(NaN));
147+
EXPECT_FALSE(Some.contains(PosInf));
148+
EXPECT_TRUE(SomePos.contains(APFloat(3.0)));
149+
EXPECT_FALSE(SomeNeg.contains(APFloat(3.0)));
150+
EXPECT_TRUE(SomeNeg.contains(APFloat(-3.0)));
151+
EXPECT_FALSE(SomePos.contains(APFloat(-3.0)));
152+
EXPECT_TRUE(Some.contains(SomePos));
153+
EXPECT_TRUE(Some.contains(SomeNeg));
154+
}
155+
156+
TEST_F(ConstantFPRangeTest, Equality) {
157+
EXPECT_EQ(Full, Full);
158+
EXPECT_EQ(Empty, Empty);
159+
EXPECT_EQ(One, One);
160+
EXPECT_EQ(Some, Some);
161+
EXPECT_NE(Full, Empty);
162+
EXPECT_NE(Zero, PosZero);
163+
EXPECT_NE(One, NaN);
164+
EXPECT_NE(Some, One);
165+
EXPECT_NE(SNaN, QNaN);
166+
}
167+
168+
TEST_F(ConstantFPRangeTest, SingleElement) {
169+
EXPECT_EQ(Full.getSingleElement(), static_cast<APFloat *>(nullptr));
170+
EXPECT_EQ(Empty.getSingleElement(), static_cast<APFloat *>(nullptr));
171+
EXPECT_EQ(Finite.getSingleElement(), static_cast<APFloat *>(nullptr));
172+
EXPECT_EQ(Zero.getSingleElement(), static_cast<APFloat *>(nullptr));
173+
EXPECT_EQ(NaN.getSingleElement(), static_cast<APFloat *>(nullptr));
174+
EXPECT_EQ(SNaN.getSingleElement(), static_cast<APFloat *>(nullptr));
175+
EXPECT_EQ(QNaN.getSingleElement(), static_cast<APFloat *>(nullptr));
176+
177+
EXPECT_EQ(*One.getSingleElement(), APFloat(1.0));
178+
EXPECT_EQ(*PosZero.getSingleElement(), APFloat::getZero(Sem));
179+
EXPECT_EQ(*PosInf.getSingleElement(), APFloat::getInf(Sem));
180+
181+
EXPECT_FALSE(Full.isSingleElement());
182+
EXPECT_FALSE(Empty.isSingleElement());
183+
EXPECT_TRUE(One.isSingleElement());
184+
EXPECT_FALSE(Some.isSingleElement());
185+
EXPECT_FALSE(Zero.isSingleElement());
186+
}
187+
188+
TEST_F(ConstantFPRangeTest, IntersectWith) {
189+
EXPECT_EQ(Empty.intersectWith(Full), Empty);
190+
EXPECT_EQ(Empty.intersectWith(Empty), Empty);
191+
EXPECT_EQ(Empty.intersectWith(One), Empty);
192+
EXPECT_EQ(Empty.intersectWith(Some), Empty);
193+
EXPECT_EQ(Full.intersectWith(Full), Full);
194+
EXPECT_EQ(Some.intersectWith(Some), Some);
195+
EXPECT_EQ(Some.intersectWith(One), One);
196+
EXPECT_EQ(Full.intersectWith(One), One);
197+
EXPECT_EQ(Full.intersectWith(Some), Some);
198+
EXPECT_EQ(Some.intersectWith(SomePos), SomePos);
199+
EXPECT_EQ(Some.intersectWith(SomeNeg), SomeNeg);
200+
EXPECT_EQ(NaN.intersectWith(Finite), Empty);
201+
EXPECT_EQ(NaN.intersectWith(SNaN), SNaN);
202+
EXPECT_EQ(NaN.intersectWith(QNaN), QNaN);
203+
EXPECT_EQ(Finite.intersectWith(One), One);
204+
EXPECT_EQ(Some.intersectWith(Zero), Zero);
205+
EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(4.0))
206+
.intersectWith(
207+
ConstantFPRange::getNonNaN(APFloat(3.0), APFloat(6.0))),
208+
ConstantFPRange::getNonNaN(APFloat(3.0), APFloat(4.0)));
209+
EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))
210+
.intersectWith(
211+
ConstantFPRange::getNonNaN(APFloat(5.0), APFloat(6.0))),
212+
Empty);
213+
}
214+
215+
TEST_F(ConstantFPRangeTest, UnionWith) {
216+
EXPECT_EQ(Empty.unionWith(Full), Full);
217+
EXPECT_EQ(Empty.unionWith(Empty), Empty);
218+
EXPECT_EQ(Empty.unionWith(One), One);
219+
EXPECT_EQ(Empty.unionWith(Some), Some);
220+
EXPECT_EQ(Full.unionWith(Full), Full);
221+
EXPECT_EQ(Some.unionWith(Some), Some);
222+
EXPECT_EQ(Some.unionWith(One), Some);
223+
EXPECT_EQ(Full.unionWith(Some), Full);
224+
EXPECT_EQ(Some.unionWith(SomePos), Some);
225+
EXPECT_EQ(Some.unionWith(SomeNeg), Some);
226+
EXPECT_EQ(Finite.unionWith(One), Finite);
227+
EXPECT_EQ(Some.unionWith(Zero), Some);
228+
EXPECT_EQ(Finite.unionWith(PosInf).unionWith(NegInf).unionWith(NaN), Full);
229+
EXPECT_EQ(PosZero.unionWith(NegZero), Zero);
230+
EXPECT_EQ(NaN.unionWith(SNaN), NaN);
231+
EXPECT_EQ(NaN.unionWith(QNaN), NaN);
232+
EXPECT_EQ(SNaN.unionWith(QNaN), NaN);
233+
EXPECT_EQ(
234+
ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(4.0))
235+
.unionWith(ConstantFPRange::getNonNaN(APFloat(3.0), APFloat(6.0))),
236+
ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(6.0)));
237+
EXPECT_EQ(
238+
ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))
239+
.unionWith(ConstantFPRange::getNonNaN(APFloat(5.0), APFloat(6.0))),
240+
ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(6.0)));
241+
}
242+
243+
TEST_F(ConstantFPRangeTest, FPClassify) {
244+
EXPECT_EQ(Empty.classify(), fcNone);
245+
EXPECT_EQ(Full.classify(), fcAllFlags);
246+
EXPECT_EQ(Finite.classify(), fcFinite);
247+
EXPECT_EQ(Zero.classify(), fcZero);
248+
EXPECT_EQ(NaN.classify(), fcNan);
249+
EXPECT_EQ(SNaN.classify(), fcSNan);
250+
EXPECT_EQ(QNaN.classify(), fcQNan);
251+
EXPECT_EQ(One.classify(), fcPosNormal);
252+
EXPECT_EQ(Some.classify(), fcFinite);
253+
EXPECT_EQ(SomePos.classify(), fcPosFinite);
254+
EXPECT_EQ(SomeNeg.classify(), fcNegFinite);
255+
EXPECT_EQ(PosInf.classify(), fcPosInf);
256+
EXPECT_EQ(NegInf.classify(), fcNegInf);
257+
EXPECT_TRUE(SomePos.toKnownFPClass().cannotBeOrderedLessThanZero());
258+
EXPECT_EQ(Finite.getSignBit(), std::nullopt);
259+
EXPECT_EQ(PosZero.getSignBit(), false);
260+
EXPECT_EQ(NegZero.getSignBit(), true);
261+
EXPECT_EQ(SomePos.getSignBit(), false);
262+
EXPECT_EQ(SomeNeg.getSignBit(), true);
263+
EXPECT_EQ(SomePos.toKnownFPClass().SignBit, false);
264+
EXPECT_EQ(SomeNeg.toKnownFPClass().SignBit, true);
265+
}
266+
267+
TEST_F(ConstantFPRangeTest, Print) {
268+
auto ToString = [](const ConstantFPRange &CR) {
269+
std::string Str;
270+
raw_string_ostream OS(Str);
271+
CR.print(OS);
272+
return Str;
273+
};
274+
275+
EXPECT_EQ(ToString(Full), "full-set");
276+
EXPECT_EQ(ToString(Empty), "empty-set");
277+
EXPECT_EQ(ToString(NaN), "NaN");
278+
EXPECT_EQ(ToString(SNaN), "SNaN");
279+
EXPECT_EQ(ToString(QNaN), "QNaN");
280+
EXPECT_EQ(ToString(One), "[1, 1]");
281+
EXPECT_EQ(ToString(Some.unionWith(SNaN)), "[-3, 3] with SNaN");
282+
}
283+
284+
} // anonymous namespace

0 commit comments

Comments
 (0)