1 | //===-- RegisterFlagsTest.cpp ---------------------------------------------===// |
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 "lldb/Target/RegisterFlags.h" |
10 | #include "lldb/Utility/StreamString.h" |
11 | #include "gmock/gmock.h" |
12 | #include "gtest/gtest.h" |
13 | |
14 | using namespace lldb_private; |
15 | using namespace lldb; |
16 | |
17 | TEST(RegisterFlagsTest, Field) { |
18 | // We assume that start <= end is always true, so that is not tested here. |
19 | |
20 | RegisterFlags::Field f1("abc" , 0); |
21 | ASSERT_EQ(f1.GetName(), "abc" ); |
22 | // start == end means a 1 bit field. |
23 | ASSERT_EQ(f1.GetSizeInBits(), (unsigned)1); |
24 | ASSERT_EQ(f1.GetMask(), (uint64_t)1); |
25 | ASSERT_EQ(f1.GetValue(0), (uint64_t)0); |
26 | ASSERT_EQ(f1.GetValue(3), (uint64_t)1); |
27 | |
28 | // End is inclusive meaning that start 0 to end 1 includes bit 1 |
29 | // to make a 2 bit field. |
30 | RegisterFlags::Field f2("" , 0, 1); |
31 | ASSERT_EQ(f2.GetSizeInBits(), (unsigned)2); |
32 | ASSERT_EQ(f2.GetMask(), (uint64_t)3); |
33 | ASSERT_EQ(f2.GetValue(UINT64_MAX), (uint64_t)3); |
34 | ASSERT_EQ(f2.GetValue(UINT64_MAX & ~(uint64_t)3), (uint64_t)0); |
35 | |
36 | // If the field doesn't start at 0 we need to shift up/down |
37 | // to account for it. |
38 | RegisterFlags::Field f3("" , 2, 5); |
39 | ASSERT_EQ(f3.GetSizeInBits(), (unsigned)4); |
40 | ASSERT_EQ(f3.GetMask(), (uint64_t)0x3c); |
41 | ASSERT_EQ(f3.GetValue(UINT64_MAX), (uint64_t)0xf); |
42 | ASSERT_EQ(f3.GetValue(UINT64_MAX & ~(uint64_t)0x3c), (uint64_t)0); |
43 | |
44 | // Fields are sorted lowest starting bit first. |
45 | ASSERT_TRUE(f2 < f3); |
46 | ASSERT_FALSE(f3 < f1); |
47 | ASSERT_FALSE(f1 < f2); |
48 | ASSERT_FALSE(f1 < f1); |
49 | } |
50 | |
51 | static RegisterFlags::Field make_field(unsigned start, unsigned end) { |
52 | return RegisterFlags::Field("" , start, end); |
53 | } |
54 | |
55 | static RegisterFlags::Field make_field(unsigned bit) { |
56 | return RegisterFlags::Field("" , bit); |
57 | } |
58 | |
59 | TEST(RegisterFlagsTest, FieldOverlaps) { |
60 | // Single bit fields |
61 | ASSERT_FALSE(make_field(0, 0).Overlaps(make_field(1))); |
62 | ASSERT_TRUE(make_field(1, 1).Overlaps(make_field(1))); |
63 | ASSERT_FALSE(make_field(1, 1).Overlaps(make_field(3))); |
64 | |
65 | ASSERT_TRUE(make_field(0, 1).Overlaps(make_field(1, 2))); |
66 | ASSERT_TRUE(make_field(1, 2).Overlaps(make_field(0, 1))); |
67 | ASSERT_FALSE(make_field(0, 1).Overlaps(make_field(2, 3))); |
68 | ASSERT_FALSE(make_field(2, 3).Overlaps(make_field(0, 1))); |
69 | |
70 | ASSERT_FALSE(make_field(1, 5).Overlaps(make_field(10, 20))); |
71 | ASSERT_FALSE(make_field(15, 30).Overlaps(make_field(7, 12))); |
72 | } |
73 | |
74 | TEST(RegisterFlagsTest, PaddingDistance) { |
75 | // We assume that this method is always called with a more significant |
76 | // (start bit is higher) field first and that they do not overlap. |
77 | |
78 | // [field 1][field 2] |
79 | ASSERT_EQ(make_field(1, 1).PaddingDistance(make_field(0)), 0ULL); |
80 | // [field 1][..][field 2] |
81 | ASSERT_EQ(make_field(2, 2).PaddingDistance(make_field(0)), 1ULL); |
82 | // [field 1][field 1][field 2] |
83 | ASSERT_EQ(make_field(1, 2).PaddingDistance(make_field(0)), 0ULL); |
84 | // [field 1][30 bits free][field 2] |
85 | ASSERT_EQ(make_field(31, 31).PaddingDistance(make_field(0)), 30ULL); |
86 | } |
87 | |
88 | static void test_padding(const std::vector<RegisterFlags::Field> &fields, |
89 | const std::vector<RegisterFlags::Field> &expected) { |
90 | RegisterFlags rf("" , 4, fields); |
91 | EXPECT_THAT(expected, ::testing::ContainerEq(rf.GetFields())); |
92 | } |
93 | |
94 | TEST(RegisterFlagsTest, RegisterFlagsPadding) { |
95 | // When creating a set of flags we assume that: |
96 | // * There are >= 1 fields. |
97 | // * They are sorted in descending order. |
98 | // * There may be gaps between each field. |
99 | |
100 | // Needs no padding |
101 | auto fields = |
102 | std::vector<RegisterFlags::Field>{make_field(start: 16, end: 31), make_field(start: 0, end: 15)}; |
103 | test_padding(fields, expected: fields); |
104 | |
105 | // Needs padding in between the fields, single bit. |
106 | test_padding(fields: {make_field(start: 17, end: 31), make_field(start: 0, end: 15)}, |
107 | expected: {make_field(start: 17, end: 31), make_field(bit: 16), make_field(start: 0, end: 15)}); |
108 | // Multiple bits of padding. |
109 | test_padding(fields: {make_field(start: 17, end: 31), make_field(start: 0, end: 14)}, |
110 | expected: {make_field(start: 17, end: 31), make_field(start: 15, end: 16), make_field(start: 0, end: 14)}); |
111 | |
112 | // Padding before first field, single bit. |
113 | test_padding(fields: {make_field(start: 0, end: 30)}, expected: {make_field(bit: 31), make_field(start: 0, end: 30)}); |
114 | // Multiple bits. |
115 | test_padding(fields: {make_field(start: 0, end: 15)}, expected: {make_field(start: 16, end: 31), make_field(start: 0, end: 15)}); |
116 | |
117 | // Padding after last field, single bit. |
118 | test_padding(fields: {make_field(start: 1, end: 31)}, expected: {make_field(start: 1, end: 31), make_field(bit: 0)}); |
119 | // Multiple bits. |
120 | test_padding(fields: {make_field(start: 2, end: 31)}, expected: {make_field(start: 2, end: 31), make_field(start: 0, end: 1)}); |
121 | |
122 | // Fields need padding before, in between and after. |
123 | // [31-28][field 27-24][23-22][field 21-20][19-12][field 11-8][7-0] |
124 | test_padding(fields: {make_field(start: 24, end: 27), make_field(start: 20, end: 21), make_field(start: 8, end: 11)}, |
125 | expected: {make_field(start: 28, end: 31), make_field(start: 24, end: 27), make_field(start: 22, end: 23), |
126 | make_field(start: 20, end: 21), make_field(start: 12, end: 19), make_field(start: 8, end: 11), |
127 | make_field(start: 0, end: 7)}); |
128 | } |
129 | |
130 | TEST(RegisterFieldsTest, ReverseFieldOrder) { |
131 | // Unchanged |
132 | RegisterFlags rf("" , 4, {make_field(start: 0, end: 31)}); |
133 | ASSERT_EQ(0x12345678ULL, (unsigned long long)rf.ReverseFieldOrder(0x12345678)); |
134 | |
135 | // Swap the two halves around. |
136 | RegisterFlags rf2("" , 4, {make_field(start: 16, end: 31), make_field(start: 0, end: 15)}); |
137 | ASSERT_EQ(0x56781234ULL, (unsigned long long)rf2.ReverseFieldOrder(0x12345678)); |
138 | |
139 | // Many small fields. |
140 | RegisterFlags rf3( |
141 | "" , 4, {make_field(bit: 31), make_field(bit: 30), make_field(bit: 29), make_field(bit: 28)}); |
142 | ASSERT_EQ(0x00000005ULL, rf3.ReverseFieldOrder(0xA0000000)); |
143 | } |
144 | |
145 | TEST(RegisterFlagsTest, AsTable) { |
146 | // Anonymous fields are shown with an empty name cell, |
147 | // whether they are known up front or added during construction. |
148 | RegisterFlags anon_field("" , 4, {make_field(start: 0, end: 31)}); |
149 | ASSERT_EQ("| 31-0 |\n" |
150 | "|------|\n" |
151 | "| |" , |
152 | anon_field.AsTable(100)); |
153 | |
154 | RegisterFlags anon_with_pad("" , 4, {make_field(start: 16, end: 31)}); |
155 | ASSERT_EQ("| 31-16 | 15-0 |\n" |
156 | "|-------|------|\n" |
157 | "| | |" , |
158 | anon_with_pad.AsTable(100)); |
159 | |
160 | // Use the wider of position and name to set the column width. |
161 | RegisterFlags name_wider("" , 4, {RegisterFlags::Field("aardvark" , 0, 31)}); |
162 | ASSERT_EQ("| 31-0 |\n" |
163 | "|----------|\n" |
164 | "| aardvark |" , |
165 | name_wider.AsTable(100)); |
166 | // When the padding is an odd number, put the remaining 1 on the right. |
167 | RegisterFlags pos_wider("" , 4, {RegisterFlags::Field("?" , 0, 31)}); |
168 | ASSERT_EQ("| 31-0 |\n" |
169 | "|------|\n" |
170 | "| ? |" , |
171 | pos_wider.AsTable(100)); |
172 | |
173 | // Single bit fields don't need to show start and end, just one of them. |
174 | RegisterFlags single_bit("" , 4, {make_field(bit: 31)}); |
175 | ASSERT_EQ("| 31 | 30-0 |\n" |
176 | "|----|------|\n" |
177 | "| | |" , |
178 | single_bit.AsTable(100)); |
179 | |
180 | // Columns are printed horizontally if max width allows. |
181 | RegisterFlags many_fields("" , 4, |
182 | {RegisterFlags::Field("cat" , 28, 31), |
183 | RegisterFlags::Field("pigeon" , 20, 23), |
184 | RegisterFlags::Field("wolf" , 12), |
185 | RegisterFlags::Field("x" , 0, 4)}); |
186 | ASSERT_EQ("| 31-28 | 27-24 | 23-20 | 19-13 | 12 | 11-5 | 4-0 |\n" |
187 | "|-------|-------|--------|-------|------|------|-----|\n" |
188 | "| cat | | pigeon | | wolf | | x |" , |
189 | many_fields.AsTable(100)); |
190 | |
191 | // max_width tells us when we need to split into further tables. |
192 | // Here no split is needed. |
193 | RegisterFlags exact_max_single_col("" , 4, {RegisterFlags::Field("?" , 0, 31)}); |
194 | ASSERT_EQ("| 31-0 |\n" |
195 | "|------|\n" |
196 | "| ? |" , |
197 | exact_max_single_col.AsTable(9)); |
198 | RegisterFlags exact_max_two_col( |
199 | "" , 4, |
200 | {RegisterFlags::Field("?" , 16, 31), RegisterFlags::Field("#" , 0, 15)}); |
201 | ASSERT_EQ("| 31-16 | 15-0 |\n" |
202 | "|-------|------|\n" |
203 | "| ? | # |" , |
204 | exact_max_two_col.AsTable(16)); |
205 | |
206 | // If max is less than a single column, just print the single column. The user |
207 | // will have to put up with some wrapping in this niche case. |
208 | RegisterFlags zero_max_single_col("" , 4, {RegisterFlags::Field("?" , 0, 31)}); |
209 | ASSERT_EQ("| 31-0 |\n" |
210 | "|------|\n" |
211 | "| ? |" , |
212 | zero_max_single_col.AsTable(0)); |
213 | // Same logic for any following columns. Effectively making a "vertical" |
214 | // table, just with more grid lines. |
215 | RegisterFlags zero_max_two_col( |
216 | "" , 4, |
217 | {RegisterFlags::Field("?" , 16, 31), RegisterFlags::Field("#" , 0, 15)}); |
218 | ASSERT_EQ("| 31-16 |\n" |
219 | "|-------|\n" |
220 | "| ? |\n" |
221 | "\n" |
222 | "| 15-0 |\n" |
223 | "|------|\n" |
224 | "| # |" , |
225 | zero_max_two_col.AsTable(0)); |
226 | |
227 | RegisterFlags max_less_than_single_col("" , 4, |
228 | {RegisterFlags::Field("?" , 0, 31)}); |
229 | ASSERT_EQ("| 31-0 |\n" |
230 | "|------|\n" |
231 | "| ? |" , |
232 | max_less_than_single_col.AsTable(3)); |
233 | RegisterFlags max_less_than_two_col( |
234 | "" , 4, |
235 | {RegisterFlags::Field("?" , 16, 31), RegisterFlags::Field("#" , 0, 15)}); |
236 | ASSERT_EQ("| 31-16 |\n" |
237 | "|-------|\n" |
238 | "| ? |\n" |
239 | "\n" |
240 | "| 15-0 |\n" |
241 | "|------|\n" |
242 | "| # |" , |
243 | max_less_than_two_col.AsTable(9)); |
244 | RegisterFlags max_many_columns( |
245 | "" , 4, |
246 | {RegisterFlags::Field("A" , 24, 31), RegisterFlags::Field("B" , 16, 23), |
247 | RegisterFlags::Field("C" , 8, 15), |
248 | RegisterFlags::Field("really long name" , 0, 7)}); |
249 | ASSERT_EQ("| 31-24 | 23-16 |\n" |
250 | "|-------|-------|\n" |
251 | "| A | B |\n" |
252 | "\n" |
253 | "| 15-8 |\n" |
254 | "|------|\n" |
255 | "| C |\n" |
256 | "\n" |
257 | "| 7-0 |\n" |
258 | "|------------------|\n" |
259 | "| really long name |" , |
260 | max_many_columns.AsTable(23)); |
261 | } |
262 | |
263 | TEST(RegisterFieldsTest, ToXML) { |
264 | StreamString strm; |
265 | |
266 | // RegisterFlags requires that some fields be given, so no testing of empty |
267 | // input. |
268 | |
269 | // Unnamed fields are padding that are ignored. This applies to fields passed |
270 | // in, and those generated to fill the other bits (31-1 here). |
271 | RegisterFlags("Foo" , 4, {RegisterFlags::Field("" , 0, 0)}).ToXML(strm); |
272 | ASSERT_EQ(strm.GetString(), "<flags id=\"Foo\" size=\"4\">\n" |
273 | "</flags>\n" ); |
274 | |
275 | strm.Clear(); |
276 | RegisterFlags("Foo" , 4, {RegisterFlags::Field("abc" , 0, 0)}).ToXML(strm); |
277 | ASSERT_EQ(strm.GetString(), "<flags id=\"Foo\" size=\"4\">\n" |
278 | " <field name=\"abc\" start=\"0\" end=\"0\"/>\n" |
279 | "</flags>\n" ); |
280 | |
281 | strm.Clear(); |
282 | // Should use the current indentation level as a starting point. |
283 | strm.IndentMore(); |
284 | RegisterFlags( |
285 | "Bar" , 5, |
286 | {RegisterFlags::Field("f1" , 25, 32), RegisterFlags::Field("f2" , 10, 24)}) |
287 | .ToXML(strm); |
288 | ASSERT_EQ(strm.GetString(), |
289 | " <flags id=\"Bar\" size=\"5\">\n" |
290 | " <field name=\"f1\" start=\"25\" end=\"32\"/>\n" |
291 | " <field name=\"f2\" start=\"10\" end=\"24\"/>\n" |
292 | " </flags>\n" ); |
293 | |
294 | strm.Clear(); |
295 | strm.IndentLess(); |
296 | // Should replace any XML unsafe characters in field names. |
297 | RegisterFlags("Safe" , 8, |
298 | {RegisterFlags::Field("A<" , 4), RegisterFlags::Field("B>" , 3), |
299 | RegisterFlags::Field("C'" , 2), RegisterFlags::Field("D\"" , 1), |
300 | RegisterFlags::Field("E&" , 0)}) |
301 | .ToXML(strm); |
302 | ASSERT_EQ(strm.GetString(), |
303 | "<flags id=\"Safe\" size=\"8\">\n" |
304 | " <field name=\"A<\" start=\"4\" end=\"4\"/>\n" |
305 | " <field name=\"B>\" start=\"3\" end=\"3\"/>\n" |
306 | " <field name=\"C'\" start=\"2\" end=\"2\"/>\n" |
307 | " <field name=\"D"\" start=\"1\" end=\"1\"/>\n" |
308 | " <field name=\"E&\" start=\"0\" end=\"0\"/>\n" |
309 | "</flags>\n" ); |
310 | } |
311 | |