1 //===-- DynamicRegisterInfoTest.cpp ---------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "gmock/gmock.h"
10 #include "gtest/gtest.h"
12 #include "lldb/Target/DynamicRegisterInfo.h"
13 #include "lldb/Utility/ArchSpec.h"
17 using namespace lldb_private
;
19 static std::vector
<uint32_t> regs_to_vector(uint32_t *regs
) {
20 std::vector
<uint32_t> ret
;
22 while (*regs
!= LLDB_INVALID_REGNUM
)
23 ret
.push_back(*regs
++);
28 class DynamicRegisterInfoRegisterTest
: public ::testing::Test
{
30 std::vector
<DynamicRegisterInfo::Register
> m_regs
;
31 DynamicRegisterInfo m_dyninfo
;
33 uint32_t AddTestRegister(
34 const char *name
, const char *group
, uint32_t byte_size
,
35 std::function
<void(const DynamicRegisterInfo::Register
&)> adder
,
36 std::vector
<uint32_t> value_regs
= {},
37 std::vector
<uint32_t> invalidate_regs
= {}) {
38 DynamicRegisterInfo::Register new_reg
{ConstString(name
),
44 lldb::eFormatUnsigned
,
48 static_cast<uint32_t>(m_regs
.size()),
52 return m_regs
.size() - 1;
55 void ExpectInRegs(uint32_t reg_num
, const char *reg_name
,
56 std::vector
<uint32_t> value_regs
,
57 std::vector
<uint32_t> invalidate_regs
) {
58 ASSERT_GT(m_regs
.size(), reg_num
);
60 const DynamicRegisterInfo::Register
®
= m_regs
[reg_num
];
61 ConstString expected_reg_name
{reg_name
};
62 EXPECT_EQ(reg
.name
, expected_reg_name
);
63 EXPECT_EQ(reg
.value_regs
, value_regs
);
64 EXPECT_EQ(reg
.invalidate_regs
, invalidate_regs
);
67 void ExpectInDynInfo(uint32_t reg_num
, const char *reg_name
,
69 std::vector
<uint32_t> value_regs
= {},
70 std::vector
<uint32_t> invalidate_regs
= {}) {
71 const RegisterInfo
*reg
= m_dyninfo
.GetRegisterInfoAtIndex(reg_num
);
72 ASSERT_NE(reg
, nullptr);
73 EXPECT_STREQ(reg
->name
, reg_name
);
74 EXPECT_EQ(reg
->byte_offset
, byte_offset
);
75 EXPECT_THAT(regs_to_vector(reg
->value_regs
), value_regs
);
76 EXPECT_THAT(regs_to_vector(reg
->invalidate_regs
), invalidate_regs
);
80 #define EXPECT_IN_REGS(reg, ...) \
82 SCOPED_TRACE("at register " #reg); \
83 ExpectInRegs(reg, #reg, __VA_ARGS__); \
86 #define EXPECT_IN_DYNINFO(reg, ...) \
88 SCOPED_TRACE("at register " #reg); \
89 ExpectInDynInfo(reg, #reg, __VA_ARGS__); \
92 TEST_F(DynamicRegisterInfoRegisterTest
, addSupplementaryRegister
) {
93 // Add a base register
94 uint32_t rax
= AddTestRegister(
96 [this](const DynamicRegisterInfo::Register
&r
) { m_regs
.push_back(r
); });
98 // Add supplementary registers
99 auto suppl_adder
= [this](const DynamicRegisterInfo::Register
&r
) {
100 addSupplementaryRegister(m_regs
, r
);
102 uint32_t eax
= AddTestRegister("eax", "supplementary", 4, suppl_adder
, {rax
});
103 uint32_t ax
= AddTestRegister("ax", "supplementary", 2, suppl_adder
, {rax
});
104 uint32_t ah
= AddTestRegister("ah", "supplementary", 1, suppl_adder
, {rax
});
105 uint32_t al
= AddTestRegister("al", "supplementary", 1, suppl_adder
, {rax
});
106 m_regs
[ah
].value_reg_offset
= 1;
108 EXPECT_IN_REGS(rax
, {}, {eax
, ax
, ah
, al
});
109 EXPECT_IN_REGS(eax
, {rax
}, {rax
, ax
, ah
, al
});
110 EXPECT_IN_REGS(ax
, {rax
}, {rax
, eax
, ah
, al
});
111 EXPECT_IN_REGS(ah
, {rax
}, {rax
, eax
, ax
, al
});
112 EXPECT_IN_REGS(al
, {rax
}, {rax
, eax
, ax
, ah
});
114 EXPECT_EQ(m_dyninfo
.SetRegisterInfo(std::move(m_regs
), ArchSpec()),
116 EXPECT_IN_DYNINFO(rax
, 0, {}, {eax
, ax
, ah
, al
});
117 EXPECT_IN_DYNINFO(eax
, 0, {rax
}, {rax
, ax
, ah
, al
});
118 EXPECT_IN_DYNINFO(ax
, 0, {rax
}, {rax
, eax
, ah
, al
});
119 EXPECT_IN_DYNINFO(ah
, 1, {rax
}, {rax
, eax
, ax
, al
});
120 EXPECT_IN_DYNINFO(al
, 0, {rax
}, {rax
, eax
, ax
, ah
});
123 TEST_F(DynamicRegisterInfoRegisterTest
, SetRegisterInfo
) {
124 auto adder
= [this](const DynamicRegisterInfo::Register
&r
) {
127 // Add regular registers
128 uint32_t b1
= AddTestRegister("b1", "base", 8, adder
);
129 uint32_t b2
= AddTestRegister("b2", "other", 8, adder
);
131 // Add a few sub-registers
132 uint32_t s1
= AddTestRegister("s1", "base", 4, adder
, {b1
});
133 uint32_t s2
= AddTestRegister("s2", "other", 4, adder
, {b2
});
135 // Add a register with invalidate_regs
136 uint32_t i1
= AddTestRegister("i1", "third", 8, adder
, {}, {b1
});
138 // Add a register with indirect invalidate regs to be expanded
139 // TODO: why is it done conditionally to value_regs?
140 uint32_t i2
= AddTestRegister("i2", "third", 4, adder
, {b2
}, {i1
});
142 EXPECT_EQ(m_dyninfo
.SetRegisterInfo(std::move(m_regs
), ArchSpec()),
144 EXPECT_IN_DYNINFO(b1
, 0, {}, {});
145 EXPECT_IN_DYNINFO(b2
, 8, {}, {});
146 EXPECT_IN_DYNINFO(s1
, 0, {b1
}, {});
147 EXPECT_IN_DYNINFO(s2
, 8, {b2
}, {});
148 EXPECT_IN_DYNINFO(i1
, 16, {}, {b1
});
149 EXPECT_IN_DYNINFO(i2
, 8, {b2
}, {b1
, i1
});