1 //===-- DynamicRegisterInfoTest.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 "gmock/gmock.h" 10 #include "gtest/gtest.h" 11 12 #include "lldb/Target/DynamicRegisterInfo.h" 13 #include "lldb/Utility/ArchSpec.h" 14 15 #include <functional> 16 17 using namespace lldb_private; 18 19 static std::vector<uint32_t> regs_to_vector(uint32_t *regs) { 20 std::vector<uint32_t> ret; 21 if (regs) { 22 while (*regs != LLDB_INVALID_REGNUM) 23 ret.push_back(*regs++); 24 } 25 return ret; 26 } 27 28 class DynamicRegisterInfoTest : public ::testing::Test { 29 protected: 30 DynamicRegisterInfo info; 31 uint32_t next_regnum = 0; 32 ConstString group{"group"}; 33 34 uint32_t AddTestRegister(const char *name, uint32_t byte_size, 35 std::vector<uint32_t> value_regs = {}, 36 std::vector<uint32_t> invalidate_regs = {}) { 37 struct RegisterInfo new_reg { 38 name, nullptr, byte_size, LLDB_INVALID_INDEX32, lldb::eEncodingUint, 39 lldb::eFormatUnsigned, 40 {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 41 next_regnum, next_regnum}, 42 nullptr, nullptr 43 }; 44 45 if (!value_regs.empty()) { 46 value_regs.push_back(LLDB_INVALID_REGNUM); 47 new_reg.value_regs = value_regs.data(); 48 } 49 if (!invalidate_regs.empty()) { 50 invalidate_regs.push_back(LLDB_INVALID_REGNUM); 51 new_reg.invalidate_regs = invalidate_regs.data(); 52 } 53 54 info.AddRegister(new_reg, group); 55 return next_regnum++; 56 } 57 58 void AssertRegisterInfo(uint32_t reg_num, const char *reg_name, 59 uint32_t byte_offset, 60 std::vector<uint32_t> value_regs = {}, 61 std::vector<uint32_t> invalidate_regs = {}) { 62 const RegisterInfo *reg = info.GetRegisterInfoAtIndex(reg_num); 63 EXPECT_NE(reg, nullptr); 64 if (!reg) 65 return; 66 67 EXPECT_STREQ(reg->name, reg_name); 68 EXPECT_EQ(reg->byte_offset, byte_offset); 69 EXPECT_THAT(regs_to_vector(reg->value_regs), value_regs); 70 EXPECT_THAT(regs_to_vector(reg->invalidate_regs), invalidate_regs); 71 } 72 }; 73 74 #define ASSERT_REG(reg, ...) \ 75 { \ 76 SCOPED_TRACE("at register " #reg); \ 77 AssertRegisterInfo(reg, #reg, __VA_ARGS__); \ 78 } 79 80 TEST_F(DynamicRegisterInfoTest, finalize_regs) { 81 // Add regular registers 82 uint32_t b1 = AddTestRegister("b1", 8); 83 uint32_t b2 = AddTestRegister("b2", 8); 84 85 // Add a few sub-registers 86 uint32_t s1 = AddTestRegister("s1", 4, {b1}); 87 uint32_t s2 = AddTestRegister("s2", 4, {b2}); 88 89 // Add a register with invalidate_regs 90 uint32_t i1 = AddTestRegister("i1", 8, {}, {b1}); 91 92 // Add a register with indirect invalidate regs to be expanded 93 // TODO: why is it done conditionally to value_regs? 94 uint32_t i2 = AddTestRegister("i2", 4, {b2}, {i1}); 95 96 info.Finalize(lldb_private::ArchSpec()); 97 98 ASSERT_REG(b1, 0); 99 ASSERT_REG(b2, 8); 100 ASSERT_REG(s1, 0, {b1}); 101 ASSERT_REG(s2, 8, {b2}); 102 ASSERT_REG(i1, 16, {}, {b1}); 103 ASSERT_REG(i2, 8, {b2}, {b1, i1}); 104 } 105 106 TEST_F(DynamicRegisterInfoTest, no_finalize_regs) { 107 // Add regular registers 108 uint32_t b1 = AddTestRegister("b1", 8); 109 uint32_t b2 = AddTestRegister("b2", 8); 110 111 // Add a few sub-registers 112 uint32_t s1 = AddTestRegister("s1", 4, {b1}); 113 uint32_t s2 = AddTestRegister("s2", 4, {b2}); 114 115 // Add a register with invalidate_regs 116 uint32_t i1 = AddTestRegister("i1", 8, {}, {b1}); 117 118 // Add a register with indirect invalidate regs to be expanded 119 // TODO: why is it done conditionally to value_regs? 120 uint32_t i2 = AddTestRegister("i2", 4, {b2}, {i1}); 121 122 ASSERT_REG(b1, LLDB_INVALID_INDEX32); 123 ASSERT_REG(b2, LLDB_INVALID_INDEX32); 124 ASSERT_REG(s1, LLDB_INVALID_INDEX32); 125 ASSERT_REG(s2, LLDB_INVALID_INDEX32); 126 ASSERT_REG(i1, LLDB_INVALID_INDEX32); 127 ASSERT_REG(i2, LLDB_INVALID_INDEX32); 128 } 129 130 class DynamicRegisterInfoRegisterTest : public ::testing::Test { 131 protected: 132 std::vector<DynamicRegisterInfo::Register> m_regs; 133 134 uint32_t AddTestRegister( 135 const char *name, const char *group, uint32_t byte_size, 136 std::function<void(const DynamicRegisterInfo::Register &)> adder, 137 std::vector<uint32_t> value_regs = {}, 138 std::vector<uint32_t> invalidate_regs = {}) { 139 DynamicRegisterInfo::Register new_reg{ 140 ConstString(name), ConstString(), 141 ConstString(group), byte_size, 142 LLDB_INVALID_INDEX32, lldb::eEncodingUint, 143 lldb::eFormatUnsigned, LLDB_INVALID_REGNUM, 144 LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 145 LLDB_INVALID_REGNUM, value_regs, 146 invalidate_regs}; 147 adder(new_reg); 148 return m_regs.size() - 1; 149 } 150 151 void ExpectInRegs(uint32_t reg_num, const char *reg_name, 152 std::vector<uint32_t> value_regs, 153 std::vector<uint32_t> invalidate_regs) { 154 ASSERT_GT(m_regs.size(), reg_num); 155 156 const DynamicRegisterInfo::Register ® = m_regs[reg_num]; 157 ConstString expected_reg_name{reg_name}; 158 EXPECT_EQ(reg.name, expected_reg_name); 159 EXPECT_EQ(reg.value_regs, value_regs); 160 EXPECT_EQ(reg.invalidate_regs, invalidate_regs); 161 } 162 }; 163 164 #define EXPECT_IN_REGS(reg, ...) \ 165 { \ 166 SCOPED_TRACE("at register " #reg); \ 167 ExpectInRegs(reg, #reg, __VA_ARGS__); \ 168 } 169 170 TEST_F(DynamicRegisterInfoRegisterTest, addSupplementaryRegister) { 171 // Add a base register 172 uint32_t rax = AddTestRegister( 173 "rax", "group", 8, 174 [this](const DynamicRegisterInfo::Register &r) { m_regs.push_back(r); }); 175 176 // Add supplementary registers 177 auto suppl_adder = [this](const DynamicRegisterInfo::Register &r) { 178 addSupplementaryRegister(m_regs, r); 179 }; 180 uint32_t eax = AddTestRegister("eax", "supplementary", 4, suppl_adder, {rax}); 181 uint32_t ax = AddTestRegister("ax", "supplementary", 2, suppl_adder, {rax}); 182 uint32_t al = AddTestRegister("al", "supplementary", 1, suppl_adder, {rax}); 183 184 EXPECT_IN_REGS(rax, {}, {eax, ax, al}); 185 EXPECT_IN_REGS(eax, {rax}, {rax, ax, al}); 186 EXPECT_IN_REGS(ax, {rax}, {rax, eax, al}); 187 EXPECT_IN_REGS(al, {rax}, {rax, eax, ax}); 188 } 189