brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.0 KiB · ecffdd0 Raw
483 lines · cpp
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-exception6//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 14using namespace lldb_private;15using namespace lldb;16 17TEST(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 129  // 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/down37  // 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 51static RegisterFlags::Field make_field(unsigned start, unsigned end) {52  return RegisterFlags::Field("", start, end);53}54 55static RegisterFlags::Field make_field(unsigned bit) {56  return RegisterFlags::Field("", bit);57}58 59TEST(RegisterFlagsTest, FieldOverlaps) {60  // Single bit fields61  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 74TEST(RegisterFlagsTest, PaddingDistance) {75  // We assume that this method is always called with a more significant76  // (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 88static 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 94TEST(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 padding101  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 130TEST(RegisterFieldsTest, ReverseFieldOrder) {131  // Unchanged132  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 145TEST(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 user207  // 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 263TEST(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 1286                // 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 width314  // is set by the size of the fields name (as opposed to some max of all field315  // 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 344TEST(RegisterFieldsTest, FlagsToXML) {345  StreamString strm;346 347  // RegisterFlags requires that some fields be given, so no testing of empty348  // input.349 350  // Unnamed fields are padding that are ignored. This applies to fields passed351  // 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&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");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 407TEST(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&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\"/>"),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 434TEST(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 457TEST(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}