1214054f7SMichał Górny //===-- DynamicRegisterInfoTest.cpp ---------------------------------------===//
2214054f7SMichał Górny //
3214054f7SMichał Górny // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4214054f7SMichał Górny // See https://llvm.org/LICENSE.txt for license information.
5214054f7SMichał Górny // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6214054f7SMichał Górny //
7214054f7SMichał Górny //===----------------------------------------------------------------------===//
8214054f7SMichał Górny
9214054f7SMichał Górny #include "gmock/gmock.h"
10214054f7SMichał Górny #include "gtest/gtest.h"
11214054f7SMichał Górny
12214054f7SMichał Górny #include "lldb/Target/DynamicRegisterInfo.h"
13214054f7SMichał Górny #include "lldb/Utility/ArchSpec.h"
14214054f7SMichał Górny
151afda54fSMichał Górny #include <functional>
161afda54fSMichał Górny
17214054f7SMichał Górny using namespace lldb_private;
18214054f7SMichał Górny
regs_to_vector(uint32_t * regs)19214054f7SMichał Górny static std::vector<uint32_t> regs_to_vector(uint32_t *regs) {
20214054f7SMichał Górny std::vector<uint32_t> ret;
21214054f7SMichał Górny if (regs) {
22214054f7SMichał Górny while (*regs != LLDB_INVALID_REGNUM)
23214054f7SMichał Górny ret.push_back(*regs++);
24214054f7SMichał Górny }
25214054f7SMichał Górny return ret;
26214054f7SMichał Górny }
27214054f7SMichał Górny
281afda54fSMichał Górny class DynamicRegisterInfoRegisterTest : public ::testing::Test {
291afda54fSMichał Górny protected:
301afda54fSMichał Górny std::vector<DynamicRegisterInfo::Register> m_regs;
3166063277SMichał Górny DynamicRegisterInfo m_dyninfo;
321afda54fSMichał Górny
AddTestRegister(const char * name,const char * group,uint32_t byte_size,std::function<void (const DynamicRegisterInfo::Register &)> adder,std::vector<uint32_t> value_regs={},std::vector<uint32_t> invalidate_regs={})331afda54fSMichał Górny uint32_t AddTestRegister(
341afda54fSMichał Górny const char *name, const char *group, uint32_t byte_size,
351afda54fSMichał Górny std::function<void(const DynamicRegisterInfo::Register &)> adder,
361afda54fSMichał Górny std::vector<uint32_t> value_regs = {},
371afda54fSMichał Górny std::vector<uint32_t> invalidate_regs = {}) {
3866063277SMichał Górny DynamicRegisterInfo::Register new_reg{ConstString(name),
3966063277SMichał Górny ConstString(),
4066063277SMichał Górny ConstString(group),
4166063277SMichał Górny byte_size,
4266063277SMichał Górny LLDB_INVALID_INDEX32,
4366063277SMichał Górny lldb::eEncodingUint,
4466063277SMichał Górny lldb::eFormatUnsigned,
4566063277SMichał Górny LLDB_INVALID_REGNUM,
4666063277SMichał Górny LLDB_INVALID_REGNUM,
4766063277SMichał Górny LLDB_INVALID_REGNUM,
4866063277SMichał Górny static_cast<uint32_t>(m_regs.size()),
4966063277SMichał Górny value_regs,
501afda54fSMichał Górny invalidate_regs};
511afda54fSMichał Górny adder(new_reg);
521afda54fSMichał Górny return m_regs.size() - 1;
531afda54fSMichał Górny }
541afda54fSMichał Górny
ExpectInRegs(uint32_t reg_num,const char * reg_name,std::vector<uint32_t> value_regs,std::vector<uint32_t> invalidate_regs)551afda54fSMichał Górny void ExpectInRegs(uint32_t reg_num, const char *reg_name,
561afda54fSMichał Górny std::vector<uint32_t> value_regs,
571afda54fSMichał Górny std::vector<uint32_t> invalidate_regs) {
581afda54fSMichał Górny ASSERT_GT(m_regs.size(), reg_num);
591afda54fSMichał Górny
601afda54fSMichał Górny const DynamicRegisterInfo::Register ® = m_regs[reg_num];
611afda54fSMichał Górny ConstString expected_reg_name{reg_name};
621afda54fSMichał Górny EXPECT_EQ(reg.name, expected_reg_name);
631afda54fSMichał Górny EXPECT_EQ(reg.value_regs, value_regs);
641afda54fSMichał Górny EXPECT_EQ(reg.invalidate_regs, invalidate_regs);
651afda54fSMichał Górny }
6666063277SMichał Górny
ExpectInDynInfo(uint32_t reg_num,const char * reg_name,uint32_t byte_offset,std::vector<uint32_t> value_regs={},std::vector<uint32_t> invalidate_regs={})6766063277SMichał Górny void ExpectInDynInfo(uint32_t reg_num, const char *reg_name,
6866063277SMichał Górny uint32_t byte_offset,
6966063277SMichał Górny std::vector<uint32_t> value_regs = {},
7066063277SMichał Górny std::vector<uint32_t> invalidate_regs = {}) {
7166063277SMichał Górny const RegisterInfo *reg = m_dyninfo.GetRegisterInfoAtIndex(reg_num);
7266063277SMichał Górny ASSERT_NE(reg, nullptr);
7366063277SMichał Górny EXPECT_STREQ(reg->name, reg_name);
7466063277SMichał Górny EXPECT_EQ(reg->byte_offset, byte_offset);
7566063277SMichał Górny EXPECT_THAT(regs_to_vector(reg->value_regs), value_regs);
7666063277SMichał Górny EXPECT_THAT(regs_to_vector(reg->invalidate_regs), invalidate_regs);
7766063277SMichał Górny }
781afda54fSMichał Górny };
791afda54fSMichał Górny
801afda54fSMichał Górny #define EXPECT_IN_REGS(reg, ...) \
811afda54fSMichał Górny { \
821afda54fSMichał Górny SCOPED_TRACE("at register " #reg); \
831afda54fSMichał Górny ExpectInRegs(reg, #reg, __VA_ARGS__); \
841afda54fSMichał Górny }
851afda54fSMichał Górny
8666063277SMichał Górny #define EXPECT_IN_DYNINFO(reg, ...) \
8766063277SMichał Górny { \
8866063277SMichał Górny SCOPED_TRACE("at register " #reg); \
8966063277SMichał Górny ExpectInDynInfo(reg, #reg, __VA_ARGS__); \
9066063277SMichał Górny }
9166063277SMichał Górny
TEST_F(DynamicRegisterInfoRegisterTest,addSupplementaryRegister)921afda54fSMichał Górny TEST_F(DynamicRegisterInfoRegisterTest, addSupplementaryRegister) {
93214054f7SMichał Górny // Add a base register
941afda54fSMichał Górny uint32_t rax = AddTestRegister(
951afda54fSMichał Górny "rax", "group", 8,
961afda54fSMichał Górny [this](const DynamicRegisterInfo::Register &r) { m_regs.push_back(r); });
97214054f7SMichał Górny
981afda54fSMichał Górny // Add supplementary registers
991afda54fSMichał Górny auto suppl_adder = [this](const DynamicRegisterInfo::Register &r) {
1001afda54fSMichał Górny addSupplementaryRegister(m_regs, r);
101214054f7SMichał Górny };
1021afda54fSMichał Górny uint32_t eax = AddTestRegister("eax", "supplementary", 4, suppl_adder, {rax});
1031afda54fSMichał Górny uint32_t ax = AddTestRegister("ax", "supplementary", 2, suppl_adder, {rax});
104*0d1705a9SMichał Górny uint32_t ah = AddTestRegister("ah", "supplementary", 1, suppl_adder, {rax});
1051afda54fSMichał Górny uint32_t al = AddTestRegister("al", "supplementary", 1, suppl_adder, {rax});
106*0d1705a9SMichał Górny m_regs[ah].value_reg_offset = 1;
107214054f7SMichał Górny
108*0d1705a9SMichał Górny EXPECT_IN_REGS(rax, {}, {eax, ax, ah, al});
109*0d1705a9SMichał Górny EXPECT_IN_REGS(eax, {rax}, {rax, ax, ah, al});
110*0d1705a9SMichał Górny EXPECT_IN_REGS(ax, {rax}, {rax, eax, ah, al});
111*0d1705a9SMichał Górny EXPECT_IN_REGS(ah, {rax}, {rax, eax, ax, al});
112*0d1705a9SMichał Górny EXPECT_IN_REGS(al, {rax}, {rax, eax, ax, ah});
113*0d1705a9SMichał Górny
114*0d1705a9SMichał Górny EXPECT_EQ(m_dyninfo.SetRegisterInfo(std::move(m_regs), ArchSpec()),
115*0d1705a9SMichał Górny m_regs.size());
116*0d1705a9SMichał Górny EXPECT_IN_DYNINFO(rax, 0, {}, {eax, ax, ah, al});
117*0d1705a9SMichał Górny EXPECT_IN_DYNINFO(eax, 0, {rax}, {rax, ax, ah, al});
118*0d1705a9SMichał Górny EXPECT_IN_DYNINFO(ax, 0, {rax}, {rax, eax, ah, al});
119*0d1705a9SMichał Górny EXPECT_IN_DYNINFO(ah, 1, {rax}, {rax, eax, ax, al});
120*0d1705a9SMichał Górny EXPECT_IN_DYNINFO(al, 0, {rax}, {rax, eax, ax, ah});
121214054f7SMichał Górny }
12266063277SMichał Górny
TEST_F(DynamicRegisterInfoRegisterTest,SetRegisterInfo)12366063277SMichał Górny TEST_F(DynamicRegisterInfoRegisterTest, SetRegisterInfo) {
12466063277SMichał Górny auto adder = [this](const DynamicRegisterInfo::Register &r) {
12566063277SMichał Górny m_regs.push_back(r);
12666063277SMichał Górny };
12766063277SMichał Górny // Add regular registers
12866063277SMichał Górny uint32_t b1 = AddTestRegister("b1", "base", 8, adder);
12966063277SMichał Górny uint32_t b2 = AddTestRegister("b2", "other", 8, adder);
13066063277SMichał Górny
13166063277SMichał Górny // Add a few sub-registers
13266063277SMichał Górny uint32_t s1 = AddTestRegister("s1", "base", 4, adder, {b1});
13366063277SMichał Górny uint32_t s2 = AddTestRegister("s2", "other", 4, adder, {b2});
13466063277SMichał Górny
13566063277SMichał Górny // Add a register with invalidate_regs
13666063277SMichał Górny uint32_t i1 = AddTestRegister("i1", "third", 8, adder, {}, {b1});
13766063277SMichał Górny
13866063277SMichał Górny // Add a register with indirect invalidate regs to be expanded
13966063277SMichał Górny // TODO: why is it done conditionally to value_regs?
14066063277SMichał Górny uint32_t i2 = AddTestRegister("i2", "third", 4, adder, {b2}, {i1});
14166063277SMichał Górny
14266063277SMichał Górny EXPECT_EQ(m_dyninfo.SetRegisterInfo(std::move(m_regs), ArchSpec()),
14366063277SMichał Górny m_regs.size());
14466063277SMichał Górny EXPECT_IN_DYNINFO(b1, 0, {}, {});
14566063277SMichał Górny EXPECT_IN_DYNINFO(b2, 8, {}, {});
14666063277SMichał Górny EXPECT_IN_DYNINFO(s1, 0, {b1}, {});
14766063277SMichał Górny EXPECT_IN_DYNINFO(s2, 8, {b2}, {});
14866063277SMichał Górny EXPECT_IN_DYNINFO(i1, 16, {}, {b1});
14966063277SMichał Górny EXPECT_IN_DYNINFO(i2, 8, {b2}, {b1, i1});
15066063277SMichał Górny }
151