[sanitizer][NFCI] Add Options parameter to LowerAllowCheckPass (#122765)
[llvm-project.git] / lldb / unittests / Target / RegisterFlagsTest.cpp
blobf2c61c4988b038f561258742a083c8e5556820a3
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 //===----------------------------------------------------------------------===//
9 #include "lldb/Target/RegisterFlags.h"
10 #include "lldb/Utility/StreamString.h"
11 #include "gmock/gmock.h"
12 #include "gtest/gtest.h"
14 using namespace lldb_private;
15 using namespace lldb;
17 TEST(RegisterFlagsTest, Field) {
18 // We assume that start <= end is always true, so that is not tested here.
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);
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);
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);
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);
51 static RegisterFlags::Field make_field(unsigned start, unsigned end) {
52 return RegisterFlags::Field("", start, end);
55 static RegisterFlags::Field make_field(unsigned bit) {
56 return RegisterFlags::Field("", bit);
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)));
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)));
70 ASSERT_FALSE(make_field(1, 5).Overlaps(make_field(10, 20)));
71 ASSERT_FALSE(make_field(15, 30).Overlaps(make_field(7, 12)));
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.
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);
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()));
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.
100 // Needs no padding
101 auto fields =
102 std::vector<RegisterFlags::Field>{make_field(16, 31), make_field(0, 15)};
103 test_padding(fields, fields);
105 // Needs padding in between the fields, single bit.
106 test_padding({make_field(17, 31), make_field(0, 15)},
107 {make_field(17, 31), make_field(16), make_field(0, 15)});
108 // Multiple bits of padding.
109 test_padding({make_field(17, 31), make_field(0, 14)},
110 {make_field(17, 31), make_field(15, 16), make_field(0, 14)});
112 // Padding before first field, single bit.
113 test_padding({make_field(0, 30)}, {make_field(31), make_field(0, 30)});
114 // Multiple bits.
115 test_padding({make_field(0, 15)}, {make_field(16, 31), make_field(0, 15)});
117 // Padding after last field, single bit.
118 test_padding({make_field(1, 31)}, {make_field(1, 31), make_field(0)});
119 // Multiple bits.
120 test_padding({make_field(2, 31)}, {make_field(2, 31), make_field(0, 1)});
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({make_field(24, 27), make_field(20, 21), make_field(8, 11)},
125 {make_field(28, 31), make_field(24, 27), make_field(22, 23),
126 make_field(20, 21), make_field(12, 19), make_field(8, 11),
127 make_field(0, 7)});
130 TEST(RegisterFieldsTest, ReverseFieldOrder) {
131 // Unchanged
132 RegisterFlags rf("", 4, {make_field(0, 31)});
133 ASSERT_EQ(0x12345678ULL, (unsigned long long)rf.ReverseFieldOrder(0x12345678));
135 // Swap the two halves around.
136 RegisterFlags rf2("", 4, {make_field(16, 31), make_field(0, 15)});
137 ASSERT_EQ(0x56781234ULL, (unsigned long long)rf2.ReverseFieldOrder(0x12345678));
139 // Many small fields.
140 RegisterFlags rf3(
141 "", 4, {make_field(31), make_field(30), make_field(29), make_field(28)});
142 ASSERT_EQ(0x00000005ULL, rf3.ReverseFieldOrder(0xA0000000));
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(0, 31)});
149 ASSERT_EQ("| 31-0 |\n"
150 "|------|\n"
151 "| |",
152 anon_field.AsTable(100));
154 RegisterFlags anon_with_pad("", 4, {make_field(16, 31)});
155 ASSERT_EQ("| 31-16 | 15-0 |\n"
156 "|-------|------|\n"
157 "| | |",
158 anon_with_pad.AsTable(100));
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));
173 // Single bit fields don't need to show start and end, just one of them.
174 RegisterFlags single_bit("", 4, {make_field(31)});
175 ASSERT_EQ("| 31 | 30-0 |\n"
176 "|----|------|\n"
177 "| | |",
178 single_bit.AsTable(100));
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));
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));
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));
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));
263 TEST(RegisterFlagsTest, DumpEnums) {
264 ASSERT_EQ(RegisterFlags("", 8, {RegisterFlags::Field{"A", 0}}).DumpEnums(80),
265 "");
267 FieldEnum basic_enum("test", {{0, "an_enumerator"}});
268 ASSERT_EQ(RegisterFlags("", 8, {RegisterFlags::Field{"A", 0, 0, &basic_enum}})
269 .DumpEnums(80),
270 "A: 0 = an_enumerator");
272 // If width is smaller than the enumerator name, print it anyway.
273 ASSERT_EQ(RegisterFlags("", 8, {RegisterFlags::Field{"A", 0, 0, &basic_enum}})
274 .DumpEnums(5),
275 "A: 0 = an_enumerator");
277 // Mutliple values can go on the same line, up to the width.
278 FieldEnum more_enum("long_enum",
279 {{0, "an_enumerator"},
280 {1, "another_enumerator"},
281 {2, "a_very_very_long_enumerator_has_its_own_line"},
282 {3, "small"},
283 {4, "small2"}});
284 ASSERT_EQ(RegisterFlags("", 8, {RegisterFlags::Field{"A", 0, 2, &more_enum}})
285 // Width is chosen to be exactly enough to allow 0 and 1
286 // enumerators on the first line.
287 .DumpEnums(45),
288 "A: 0 = an_enumerator, 1 = another_enumerator,\n"
289 " 2 = a_very_very_long_enumerator_has_its_own_line,\n"
290 " 3 = small, 4 = small2");
292 // If they all exceed width, one per line.
293 FieldEnum another_enum("another_enum", {{0, "an_enumerator"},
294 {1, "another_enumerator"},
295 {2, "a_longer_enumerator"}});
296 ASSERT_EQ(
297 RegisterFlags("", 8, {RegisterFlags::Field{"A", 0, 1, &another_enum}})
298 .DumpEnums(5),
299 "A: 0 = an_enumerator,\n"
300 " 1 = another_enumerator,\n"
301 " 2 = a_longer_enumerator");
303 // If the name is already > the width, put one value per line.
304 FieldEnum short_enum("short_enum", {{0, "a"}, {1, "b"}, {2, "c"}});
305 ASSERT_EQ(RegisterFlags("", 8,
306 {RegisterFlags::Field{"AReallyLongFieldName", 0, 1,
307 &short_enum}})
308 .DumpEnums(10),
309 "AReallyLongFieldName: 0 = a,\n"
310 " 1 = b,\n"
311 " 2 = c");
313 // Fields are separated by a blank line. Indentation of lines split by width
314 // is set by the size of the fields name (as opposed to some max of all field
315 // names).
316 FieldEnum enum_1("enum_1", {{0, "an_enumerator"}, {1, "another_enumerator"}});
317 FieldEnum enum_2("enum_2",
318 {{0, "Cdef_enumerator_1"}, {1, "Cdef_enumerator_2"}});
319 ASSERT_EQ(RegisterFlags("", 8,
320 {RegisterFlags::Field{"Ab", 1, 1, &enum_1},
321 RegisterFlags::Field{"Cdef", 0, 0, &enum_2}})
322 .DumpEnums(10),
323 "Ab: 0 = an_enumerator,\n"
324 " 1 = another_enumerator\n"
325 "\n"
326 "Cdef: 0 = Cdef_enumerator_1,\n"
327 " 1 = Cdef_enumerator_2");
329 // Having fields without enumerators shouldn't produce any extra newlines.
330 ASSERT_EQ(RegisterFlags("", 8,
332 RegisterFlags::Field{"A", 4, 4},
333 RegisterFlags::Field{"B", 3, 3, &enum_1},
334 RegisterFlags::Field{"C", 2, 2},
335 RegisterFlags::Field{"D", 1, 1, &enum_1},
336 RegisterFlags::Field{"E", 0, 0},
338 .DumpEnums(80),
339 "B: 0 = an_enumerator, 1 = another_enumerator\n"
340 "\n"
341 "D: 0 = an_enumerator, 1 = another_enumerator");
344 TEST(RegisterFieldsTest, FlagsToXML) {
345 StreamString strm;
347 // RegisterFlags requires that some fields be given, so no testing of empty
348 // input.
350 // Unnamed fields are padding that are ignored. This applies to fields passed
351 // in, and those generated to fill the other bits (31-1 here).
352 RegisterFlags("Foo", 4, {RegisterFlags::Field("", 0, 0)}).ToXML(strm);
353 ASSERT_EQ(strm.GetString(), "<flags id=\"Foo\" size=\"4\">\n"
354 "</flags>\n");
356 strm.Clear();
357 RegisterFlags("Foo", 4, {RegisterFlags::Field("abc", 0, 0)}).ToXML(strm);
358 ASSERT_EQ(strm.GetString(), "<flags id=\"Foo\" size=\"4\">\n"
359 " <field name=\"abc\" start=\"0\" end=\"0\"/>\n"
360 "</flags>\n");
362 strm.Clear();
363 // Should use the current indentation level as a starting point.
364 strm.IndentMore();
365 RegisterFlags(
366 "Bar", 5,
367 {RegisterFlags::Field("f1", 25, 32), RegisterFlags::Field("f2", 10, 24)})
368 .ToXML(strm);
369 ASSERT_EQ(strm.GetString(),
370 " <flags id=\"Bar\" size=\"5\">\n"
371 " <field name=\"f1\" start=\"25\" end=\"32\"/>\n"
372 " <field name=\"f2\" start=\"10\" end=\"24\"/>\n"
373 " </flags>\n");
375 strm.Clear();
376 strm.IndentLess();
377 // Should replace any XML unsafe characters in field names.
378 RegisterFlags("Safe", 8,
379 {RegisterFlags::Field("A<", 4), RegisterFlags::Field("B>", 3),
380 RegisterFlags::Field("C'", 2), RegisterFlags::Field("D\"", 1),
381 RegisterFlags::Field("E&", 0)})
382 .ToXML(strm);
383 ASSERT_EQ(strm.GetString(),
384 "<flags id=\"Safe\" size=\"8\">\n"
385 " <field name=\"A&lt;\" start=\"4\" end=\"4\"/>\n"
386 " <field name=\"B&gt;\" start=\"3\" end=\"3\"/>\n"
387 " <field name=\"C&apos;\" start=\"2\" end=\"2\"/>\n"
388 " <field name=\"D&quot;\" start=\"1\" end=\"1\"/>\n"
389 " <field name=\"E&amp;\" start=\"0\" end=\"0\"/>\n"
390 "</flags>\n");
392 // Should include enumerators as the "type".
393 strm.Clear();
394 FieldEnum enum_single("enum_single", {{0, "a"}});
395 RegisterFlags("Enumerators", 8,
396 {RegisterFlags::Field("NoEnumerators", 4),
397 RegisterFlags::Field("OneEnumerator", 3, 3, &enum_single)})
398 .ToXML(strm);
399 ASSERT_EQ(strm.GetString(),
400 "<flags id=\"Enumerators\" size=\"8\">\n"
401 " <field name=\"NoEnumerators\" start=\"4\" end=\"4\"/>\n"
402 " <field name=\"OneEnumerator\" start=\"3\" end=\"3\" "
403 "type=\"enum_single\"/>\n"
404 "</flags>\n");
407 TEST(RegisterFlagsTest, EnumeratorToXML) {
408 StreamString strm;
410 FieldEnum::Enumerator(1234, "test").ToXML(strm);
411 ASSERT_EQ(strm.GetString(), "<evalue name=\"test\" value=\"1234\"/>");
413 // Special XML chars in names must be escaped.
414 std::array special_names = {
415 std::make_pair(FieldEnum::Enumerator(0, "A<"),
416 "<evalue name=\"A&lt;\" value=\"0\"/>"),
417 std::make_pair(FieldEnum::Enumerator(1, "B>"),
418 "<evalue name=\"B&gt;\" value=\"1\"/>"),
419 std::make_pair(FieldEnum::Enumerator(2, "C'"),
420 "<evalue name=\"C&apos;\" value=\"2\"/>"),
421 std::make_pair(FieldEnum::Enumerator(3, "D\""),
422 "<evalue name=\"D&quot;\" value=\"3\"/>"),
423 std::make_pair(FieldEnum::Enumerator(4, "E&"),
424 "<evalue name=\"E&amp;\" value=\"4\"/>"),
427 for (const auto &[enumerator, expected] : special_names) {
428 strm.Clear();
429 enumerator.ToXML(strm);
430 ASSERT_EQ(strm.GetString(), expected);
434 TEST(RegisterFlagsTest, EnumToXML) {
435 StreamString strm;
437 FieldEnum("empty_enum", {}).ToXML(strm, 4);
438 ASSERT_EQ(strm.GetString(), "<enum id=\"empty_enum\" size=\"4\"/>\n");
440 strm.Clear();
441 FieldEnum("single_enumerator", {FieldEnum::Enumerator(0, "zero")})
442 .ToXML(strm, 5);
443 ASSERT_EQ(strm.GetString(), "<enum id=\"single_enumerator\" size=\"5\">\n"
444 " <evalue name=\"zero\" value=\"0\"/>\n"
445 "</enum>\n");
447 strm.Clear();
448 FieldEnum("multiple_enumerator",
449 {FieldEnum::Enumerator(0, "zero"), FieldEnum::Enumerator(1, "one")})
450 .ToXML(strm, 8);
451 ASSERT_EQ(strm.GetString(), "<enum id=\"multiple_enumerator\" size=\"8\">\n"
452 " <evalue name=\"zero\" value=\"0\"/>\n"
453 " <evalue name=\"one\" value=\"1\"/>\n"
454 "</enum>\n");
457 TEST(RegisterFlagsTest, EnumsToXML) {
458 // This method should output all the enums used by the register flag set,
459 // only once.
461 StreamString strm;
462 FieldEnum enum_a("enum_a", {FieldEnum::Enumerator(0, "zero")});
463 FieldEnum enum_b("enum_b", {FieldEnum::Enumerator(1, "one")});
464 FieldEnum enum_c("enum_c", {FieldEnum::Enumerator(2, "two")});
465 llvm::StringSet<> seen;
466 // Pretend that enum_c was already emitted for a different flag set.
467 seen.insert("enum_c");
469 RegisterFlags("Test", 4,
471 RegisterFlags::Field("f1", 31, 31, &enum_a),
472 RegisterFlags::Field("f2", 30, 30, &enum_a),
473 RegisterFlags::Field("f3", 29, 29, &enum_b),
474 RegisterFlags::Field("f4", 27, 28, &enum_c),
476 .EnumsToXML(strm, seen);
477 ASSERT_EQ(strm.GetString(), "<enum id=\"enum_a\" size=\"4\">\n"
478 " <evalue name=\"zero\" value=\"0\"/>\n"
479 "</enum>\n"
480 "<enum id=\"enum_b\" size=\"4\">\n"
481 " <evalue name=\"one\" value=\"1\"/>\n"
482 "</enum>\n");