1 | //===- llvm/unittests/ADT/BitFieldsTest.cpp - BitFields unit 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/ADT/Bitfields.h" |
10 | #include "gtest/gtest.h" |
11 | |
12 | using namespace llvm; |
13 | |
14 | namespace { |
15 | |
16 | TEST(BitfieldsTest, Example) { |
17 | uint8_t Storage = 0; |
18 | |
19 | // Store and retrieve a single bit as bool. |
20 | using Bool = Bitfield::Element<bool, 0, 1>; |
21 | Bitfield::set<Bool>(Packed&: Storage, Value: true); |
22 | EXPECT_EQ(Storage, 0b00000001); |
23 | // ^ |
24 | EXPECT_EQ(Bitfield::get<Bool>(Storage), true); |
25 | |
26 | // Store and retrieve a 2 bit typed enum. |
27 | // Note: enum underlying type must be unsigned. |
28 | enum class SuitEnum : uint8_t { CLUBS, DIAMONDS, HEARTS, SPADES }; |
29 | // Note: enum maximum value needs to be passed in as last parameter. |
30 | using Suit = Bitfield::Element<SuitEnum, 1, 2, SuitEnum::SPADES>; |
31 | Bitfield::set<Suit>(Packed&: Storage, Value: SuitEnum::HEARTS); |
32 | EXPECT_EQ(Storage, 0b00000101); |
33 | // ^^ |
34 | EXPECT_EQ(Bitfield::get<Suit>(Storage), SuitEnum::HEARTS); |
35 | |
36 | // Store and retrieve a 5 bit value as unsigned. |
37 | using Value = Bitfield::Element<unsigned, 3, 5>; |
38 | Bitfield::set<Value>(Packed&: Storage, Value: 10); |
39 | EXPECT_EQ(Storage, 0b01010101); |
40 | // ^^^^^ |
41 | EXPECT_EQ(Bitfield::get<Value>(Storage), 10U); |
42 | |
43 | // Interpret the same 5 bit value as signed. |
44 | using SignedValue = Bitfield::Element<int, 3, 5>; |
45 | Bitfield::set<SignedValue>(Packed&: Storage, Value: -2); |
46 | EXPECT_EQ(Storage, 0b11110101); |
47 | // ^^^^^ |
48 | EXPECT_EQ(Bitfield::get<SignedValue>(Storage), -2); |
49 | |
50 | // Ability to efficiently test if a field is non zero. |
51 | EXPECT_TRUE(Bitfield::test<Value>(Storage)); |
52 | |
53 | // Alter Storage changes value. |
54 | Storage = 0; |
55 | EXPECT_EQ(Bitfield::get<Bool>(Storage), false); |
56 | EXPECT_EQ(Bitfield::get<Suit>(Storage), SuitEnum::CLUBS); |
57 | EXPECT_EQ(Bitfield::get<Value>(Storage), 0U); |
58 | EXPECT_EQ(Bitfield::get<SignedValue>(Storage), 0); |
59 | |
60 | Storage = 255; |
61 | EXPECT_EQ(Bitfield::get<Bool>(Storage), true); |
62 | EXPECT_EQ(Bitfield::get<Suit>(Storage), SuitEnum::SPADES); |
63 | EXPECT_EQ(Bitfield::get<Value>(Storage), 31U); |
64 | EXPECT_EQ(Bitfield::get<SignedValue>(Storage), -1); |
65 | } |
66 | |
67 | TEST(BitfieldsTest, FirstBit) { |
68 | uint8_t Storage = 0; |
69 | using FirstBit = Bitfield::Element<bool, 0, 1>; |
70 | // Set true |
71 | Bitfield::set<FirstBit>(Packed&: Storage, Value: true); |
72 | EXPECT_EQ(Bitfield::get<FirstBit>(Storage), true); |
73 | EXPECT_EQ(Storage, 0x1ULL); |
74 | // Set false |
75 | Bitfield::set<FirstBit>(Packed&: Storage, Value: false); |
76 | EXPECT_EQ(Bitfield::get<FirstBit>(Storage), false); |
77 | EXPECT_EQ(Storage, 0x0ULL); |
78 | } |
79 | |
80 | TEST(BitfieldsTest, SecondBit) { |
81 | uint8_t Storage = 0; |
82 | using SecondBit = Bitfield::Element<bool, 1, 1>; |
83 | // Set true |
84 | Bitfield::set<SecondBit>(Packed&: Storage, Value: true); |
85 | EXPECT_EQ(Bitfield::get<SecondBit>(Storage), true); |
86 | EXPECT_EQ(Storage, 0x2ULL); |
87 | // Set false |
88 | Bitfield::set<SecondBit>(Packed&: Storage, Value: false); |
89 | EXPECT_EQ(Bitfield::get<SecondBit>(Storage), false); |
90 | EXPECT_EQ(Storage, 0x0ULL); |
91 | } |
92 | |
93 | TEST(BitfieldsTest, LastBit) { |
94 | uint8_t Storage = 0; |
95 | using LastBit = Bitfield::Element<bool, 7, 1>; |
96 | // Set true |
97 | Bitfield::set<LastBit>(Packed&: Storage, Value: true); |
98 | EXPECT_EQ(Bitfield::get<LastBit>(Storage), true); |
99 | EXPECT_EQ(Storage, 0x80ULL); |
100 | // Set false |
101 | Bitfield::set<LastBit>(Packed&: Storage, Value: false); |
102 | EXPECT_EQ(Bitfield::get<LastBit>(Storage), false); |
103 | EXPECT_EQ(Storage, 0x0ULL); |
104 | } |
105 | |
106 | TEST(BitfieldsTest, LastBitUint64) { |
107 | uint64_t Storage = 0; |
108 | using LastBit = Bitfield::Element<bool, 63, 1>; |
109 | // Set true |
110 | Bitfield::set<LastBit>(Packed&: Storage, Value: true); |
111 | EXPECT_EQ(Bitfield::get<LastBit>(Storage), true); |
112 | EXPECT_EQ(Storage, 0x8000000000000000ULL); |
113 | // Set false |
114 | Bitfield::set<LastBit>(Packed&: Storage, Value: false); |
115 | EXPECT_EQ(Bitfield::get<LastBit>(Storage), false); |
116 | EXPECT_EQ(Storage, 0x0ULL); |
117 | } |
118 | |
119 | TEST(BitfieldsTest, Enum) { |
120 | enum Enum : unsigned { Zero = 0, Two = 2, LAST = Two }; |
121 | |
122 | uint8_t Storage = 0; |
123 | using OrderingField = Bitfield::Element<Enum, 1, 2, LAST>; |
124 | EXPECT_EQ(Bitfield::get<OrderingField>(Storage), Zero); |
125 | Bitfield::set<OrderingField>(Packed&: Storage, Value: Two); |
126 | EXPECT_EQ(Bitfield::get<OrderingField>(Storage), Two); |
127 | EXPECT_EQ(Storage, 0b00000100); |
128 | // value 2 in ^^ |
129 | } |
130 | |
131 | TEST(BitfieldsTest, EnumClass) { |
132 | enum class Enum : unsigned { Zero = 0, Two = 2, LAST = Two }; |
133 | |
134 | uint8_t Storage = 0; |
135 | using OrderingField = Bitfield::Element<Enum, 1, 2, Enum::LAST>; |
136 | EXPECT_EQ(Bitfield::get<OrderingField>(Storage), Enum::Zero); |
137 | Bitfield::set<OrderingField>(Packed&: Storage, Value: Enum::Two); |
138 | EXPECT_EQ(Bitfield::get<OrderingField>(Storage), Enum::Two); |
139 | EXPECT_EQ(Storage, 0b00000100); |
140 | // value 2 in ^^ |
141 | } |
142 | |
143 | TEST(BitfieldsTest, OneBitSigned) { |
144 | uint8_t Storage = 0; |
145 | using SignedField = Bitfield::Element<int, 1, 1>; |
146 | EXPECT_EQ(Bitfield::get<SignedField>(Storage), 0); |
147 | EXPECT_EQ(Storage, 0b00000000); |
148 | // value 0 in ^ |
149 | Bitfield::set<SignedField>(Packed&: Storage, Value: -1); |
150 | EXPECT_EQ(Bitfield::get<SignedField>(Storage), -1); |
151 | EXPECT_EQ(Storage, 0b00000010); |
152 | // value 1 in ^ |
153 | } |
154 | |
155 | TEST(BitfieldsTest, TwoBitSigned) { |
156 | uint8_t Storage = 0; |
157 | using SignedField = Bitfield::Element<int, 1, 2>; |
158 | EXPECT_EQ(Bitfield::get<SignedField>(Storage), 0); |
159 | EXPECT_EQ(Storage, 0b00000000); |
160 | // value 0 in ^^ |
161 | Bitfield::set<SignedField>(Packed&: Storage, Value: 1); |
162 | EXPECT_EQ(Bitfield::get<SignedField>(Storage), 1); |
163 | EXPECT_EQ(Storage, 0b00000010); |
164 | // value 1 in ^^ |
165 | Bitfield::set<SignedField>(Packed&: Storage, Value: -1); |
166 | EXPECT_EQ(Bitfield::get<SignedField>(Storage), -1); |
167 | EXPECT_EQ(Storage, 0b00000110); |
168 | // value -1 in ^^ |
169 | Bitfield::set<SignedField>(Packed&: Storage, Value: -2); |
170 | EXPECT_EQ(Bitfield::get<SignedField>(Storage), -2); |
171 | EXPECT_EQ(Storage, 0b00000100); |
172 | // value -2 in ^^ |
173 | } |
174 | |
175 | TEST(BitfieldsTest, isOverlapping) { |
176 | // 01234567 |
177 | // A: -------- |
178 | // B: --- |
179 | // C: --- |
180 | // D: --- |
181 | using A = Bitfield::Element<unsigned, 0, 8>; |
182 | using B = Bitfield::Element<unsigned, 3, 3>; |
183 | using C = Bitfield::Element<unsigned, 1, 3>; |
184 | using D = Bitfield::Element<unsigned, 4, 3>; |
185 | EXPECT_TRUE((Bitfield::isOverlapping<A, B>())); |
186 | EXPECT_TRUE((Bitfield::isOverlapping<A, C>())); |
187 | EXPECT_TRUE((Bitfield::isOverlapping<A, B>())); |
188 | EXPECT_TRUE((Bitfield::isOverlapping<A, D>())); |
189 | |
190 | EXPECT_TRUE((Bitfield::isOverlapping<B, C>())); |
191 | EXPECT_TRUE((Bitfield::isOverlapping<B, D>())); |
192 | EXPECT_FALSE((Bitfield::isOverlapping<C, D>())); |
193 | } |
194 | |
195 | TEST(BitfieldsTest, areContiguous) { |
196 | using A = Bitfield::Element<unsigned, 0, 1>; // Next Bit:1 |
197 | using B = Bitfield::Element<unsigned, 1, 4>; // Next Bit:5 |
198 | using C = Bitfield::Element<unsigned, 5, 3>; // Next Bit:8 |
199 | EXPECT_TRUE((Bitfield::areContiguous<A, B>())); |
200 | EXPECT_TRUE((Bitfield::areContiguous<A, B, C>())); |
201 | |
202 | EXPECT_FALSE((Bitfield::areContiguous<A, C>())); |
203 | EXPECT_FALSE((Bitfield::areContiguous<A, A>())); |
204 | EXPECT_FALSE((Bitfield::areContiguous<B, A>())); |
205 | } |
206 | |
207 | TEST(BitfieldsTest, FullUint64) { |
208 | uint64_t Storage = 0; |
209 | using Value = Bitfield::Element<uint64_t, 0, 64>; |
210 | Bitfield::set<Value>(Packed&: Storage, Value: -1ULL); |
211 | EXPECT_EQ(Bitfield::get<Value>(Storage), -1ULL); |
212 | Bitfield::set<Value>(Packed&: Storage, Value: 0ULL); |
213 | EXPECT_EQ(Bitfield::get<Value>(Storage), 0ULL); |
214 | } |
215 | |
216 | TEST(BitfieldsTest, FullInt64) { |
217 | uint64_t Storage = 0; |
218 | using Value = Bitfield::Element<int64_t, 0, 64>; |
219 | Bitfield::set<Value>(Packed&: Storage, Value: -1); |
220 | EXPECT_EQ(Bitfield::get<Value>(Storage), -1); |
221 | Bitfield::set<Value>(Packed&: Storage, Value: 0); |
222 | EXPECT_EQ(Bitfield::get<Value>(Storage), 0); |
223 | } |
224 | |
225 | #ifdef EXPECT_DEBUG_DEATH |
226 | |
227 | TEST(BitfieldsTest, ValueTooBigBool) { |
228 | uint64_t Storage = 0; |
229 | using A = Bitfield::Element<unsigned, 0, 1>; |
230 | Bitfield::set<A>(Packed&: Storage, Value: true); |
231 | Bitfield::set<A>(Packed&: Storage, Value: false); |
232 | EXPECT_DEBUG_DEATH(Bitfield::set<A>(Storage, 2), "value is too big" ); |
233 | } |
234 | |
235 | TEST(BitfieldsTest, ValueTooBigInt) { |
236 | uint64_t Storage = 0; |
237 | using A = Bitfield::Element<unsigned, 0, 2>; |
238 | Bitfield::set<A>(Packed&: Storage, Value: 3); |
239 | EXPECT_DEBUG_DEATH(Bitfield::set<A>(Storage, 4), "value is too big" ); |
240 | EXPECT_DEBUG_DEATH(Bitfield::set<A>(Storage, -1), "value is too big" ); |
241 | } |
242 | |
243 | TEST(BitfieldsTest, ValueTooBigBounded) { |
244 | uint8_t Storage = 0; |
245 | using A = Bitfield::Element<int, 1, 2>; |
246 | Bitfield::set<A>(Packed&: Storage, Value: 1); |
247 | Bitfield::set<A>(Packed&: Storage, Value: 0); |
248 | Bitfield::set<A>(Packed&: Storage, Value: -1); |
249 | Bitfield::set<A>(Packed&: Storage, Value: -2); |
250 | EXPECT_DEBUG_DEATH(Bitfield::set<A>(Storage, 2), "value is too big" ); |
251 | EXPECT_DEBUG_DEATH(Bitfield::set<A>(Storage, -3), "value is too small" ); |
252 | } |
253 | |
254 | #endif |
255 | |
256 | } // namespace |
257 | |