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(16, 31), make_field(0, 15)}; 103 test_padding(fields, fields); 104 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)}); 111 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)}); 116 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)}); 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({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)}); 128 } 129 130 TEST(RegisterFieldsTest, ReverseFieldOrder) { 131 // Unchanged 132 RegisterFlags rf("", 4, {make_field(0, 31)}); 133 ASSERT_EQ(0x12345678ULL, (unsigned long long)rf.ReverseFieldOrder(0x12345678)); 134 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)); 138 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)); 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(0, 31)}); 149 ASSERT_EQ("| 31-0 |\n" 150 "|------|\n" 151 "| |", 152 anon_field.AsTable(100)); 153 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)); 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(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(RegisterFlagsTest, DumpEnums) { 264 ASSERT_EQ(RegisterFlags("", 8, {RegisterFlags::Field{"A", 0}}).DumpEnums(80), 265 ""); 266 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"); 271 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"); 276 277 // Multiple 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"); 291 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"); 302 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"); 312 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"); 328 329 // Having fields without enumerators shouldn't produce any extra newlines. 330 ASSERT_EQ(RegisterFlags("", 8, 331 { 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}, 337 }) 338 .DumpEnums(80), 339 "B: 0 = an_enumerator, 1 = another_enumerator\n" 340 "\n" 341 "D: 0 = an_enumerator, 1 = another_enumerator"); 342 } 343 344 TEST(RegisterFieldsTest, FlagsToXML) { 345 StreamString strm; 346 347 // RegisterFlags requires that some fields be given, so no testing of empty 348 // input. 349 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"); 355 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"); 361 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"); 374 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<\" start=\"4\" end=\"4\"/>\n" 386 " <field name=\"B>\" start=\"3\" end=\"3\"/>\n" 387 " <field name=\"C'\" start=\"2\" end=\"2\"/>\n" 388 " <field name=\"D"\" start=\"1\" end=\"1\"/>\n" 389 " <field name=\"E&\" start=\"0\" end=\"0\"/>\n" 390 "</flags>\n"); 391 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"); 405 } 406 407 TEST(RegisterFlagsTest, EnumeratorToXML) { 408 StreamString strm; 409 410 FieldEnum::Enumerator(1234, "test").ToXML(strm); 411 ASSERT_EQ(strm.GetString(), "<evalue name=\"test\" value=\"1234\"/>"); 412 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<\" value=\"0\"/>"), 417 std::make_pair(FieldEnum::Enumerator(1, "B>"), 418 "<evalue name=\"B>\" value=\"1\"/>"), 419 std::make_pair(FieldEnum::Enumerator(2, "C'"), 420 "<evalue name=\"C'\" value=\"2\"/>"), 421 std::make_pair(FieldEnum::Enumerator(3, "D\""), 422 "<evalue name=\"D"\" value=\"3\"/>"), 423 std::make_pair(FieldEnum::Enumerator(4, "E&"), 424 "<evalue name=\"E&\" value=\"4\"/>"), 425 }; 426 427 for (const auto &[enumerator, expected] : special_names) { 428 strm.Clear(); 429 enumerator.ToXML(strm); 430 ASSERT_EQ(strm.GetString(), expected); 431 } 432 } 433 434 TEST(RegisterFlagsTest, EnumToXML) { 435 StreamString strm; 436 437 FieldEnum("empty_enum", {}).ToXML(strm, 4); 438 ASSERT_EQ(strm.GetString(), "<enum id=\"empty_enum\" size=\"4\"/>\n"); 439 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"); 446 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"); 455 } 456 457 TEST(RegisterFlagsTest, EnumsToXML) { 458 // This method should output all the enums used by the register flag set, 459 // only once. 460 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"); 468 469 RegisterFlags("Test", 4, 470 { 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), 475 }) 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"); 483 }