Index: lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h =================================================================== --- lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h +++ lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h @@ -38,6 +38,11 @@ void AddRegister(lldb_private::RegisterInfo reg_info, lldb_private::ConstString &set_name); + // Add a new register and cross-link it via invalidate_regs with other + // registers sharing its value_regs. + void AddSupplementaryRegister(lldb_private::RegisterInfo reg_info, + lldb_private::ConstString &set_name); + void Finalize(const lldb_private::ArchSpec &arch); size_t GetNumRegisters() const; Index: lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp =================================================================== --- lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp +++ lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp @@ -464,6 +464,53 @@ m_set_reg_nums[set].push_back(reg_num); } +void DynamicRegisterInfo::AddSupplementaryRegister(RegisterInfo new_reg_info, + ConstString &set_name) { + assert(new_reg_info.value_regs != nullptr); + const uint32_t reg_num = m_regs.size(); + AddRegister(new_reg_info, set_name); + + reg_to_regs_map to_add; + for (uint32_t value_reg : m_value_regs_map[reg_num]) { + if (value_reg == LLDB_INVALID_REGNUM) + break; + + // copy value_regs to invalidate_regs + to_add[reg_num].push_back(value_reg); + + // copy invalidate_regs from the parent register + llvm::append_range(to_add[reg_num], m_invalidate_regs_map[value_reg]); + + // add reverse invalidate entries + for (uint32_t x : to_add[reg_num]) { + if (x == LLDB_INVALID_REGNUM) + continue; + to_add[x].push_back(new_reg_info.kinds[eRegisterKindLLDB]); + } + } + + for (reg_to_regs_map::value_type &x : to_add) { + reg_num_collection ®nums = m_invalidate_regs_map[x.first]; + // if the list is empty, add the terminator; otherwise, it's already there + if (regnums.empty()) + regnums.push_back(LLDB_INVALID_REGNUM); + assert(regnums.back() == LLDB_INVALID_REGNUM); + + // insert the requested elements sorted, if they're not there yet + for (uint32_t new_reg : x.second) { + // the new regnums can copy terminators from other invalidate_regs + if (new_reg == LLDB_INVALID_REGNUM) + continue; + reg_num_collection::iterator it = llvm::lower_bound(regnums, new_reg); + if (it != regnums.end() && *it != new_reg) + regnums.insert(it, new_reg); + } + + // update the pointer + m_regs[x.first].invalidate_regs = regnums.data(); + } +} + void DynamicRegisterInfo::Finalize(const ArchSpec &arch) { if (m_finalized) return; Index: lldb/unittests/Process/Utility/DynamicRegisterInfoTest.cpp =================================================================== --- lldb/unittests/Process/Utility/DynamicRegisterInfoTest.cpp +++ lldb/unittests/Process/Utility/DynamicRegisterInfoTest.cpp @@ -134,3 +134,104 @@ EXPECT_EQ(added_reg->invalidate_regs[1], i1); EXPECT_EQ(added_reg->invalidate_regs[2], LLDB_INVALID_REGNUM); } + +TEST(DynamicRegisterInfoTest, add_supplementary_register) { + DynamicRegisterInfo info; + + // Add a base register + uint32_t rax = AddRegister(info, "rax", 8); + + // Register numbers + uint32_t eax = 1; + uint32_t ax = 2; + uint32_t ah = 3; + uint32_t al = 4; + + ConstString group{"supplementary registers"}; + uint32_t value_regs[2] = {rax, LLDB_INVALID_REGNUM}; + struct RegisterInfo eax_reg { + "eax", nullptr, 4, LLDB_INVALID_INDEX32, lldb::eEncodingUint, + lldb::eFormatUnsigned, + {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, eax, + eax}, + value_regs, nullptr, nullptr, 0 + }; + info.AddSupplementaryRegister(eax_reg, group); + + struct RegisterInfo ax_reg { + "ax", nullptr, 2, LLDB_INVALID_INDEX32, lldb::eEncodingUint, + lldb::eFormatUnsigned, + {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, ax, ax}, + value_regs, nullptr, nullptr, 0 + }; + info.AddSupplementaryRegister(ax_reg, group); + + struct RegisterInfo ah_reg { + "ah", nullptr, 1, LLDB_INVALID_INDEX32, lldb::eEncodingUint, + lldb::eFormatUnsigned, + {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, ah, ah}, + value_regs, nullptr, nullptr, 0 + }; + info.AddSupplementaryRegister(ah_reg, group); + + struct RegisterInfo al_reg { + "al", nullptr, 1, LLDB_INVALID_INDEX32, lldb::eEncodingUint, + lldb::eFormatUnsigned, + {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, al, al}, + value_regs, nullptr, nullptr, 0 + }; + info.AddSupplementaryRegister(al_reg, group); + + const RegisterInfo *added_reg = info.GetRegisterInfoAtIndex(0); + ASSERT_NE(added_reg, nullptr); + ASSERT_NE(added_reg->invalidate_regs, nullptr); + EXPECT_EQ(added_reg->invalidate_regs[0], eax); + EXPECT_EQ(added_reg->invalidate_regs[1], ax); + EXPECT_EQ(added_reg->invalidate_regs[2], ah); + EXPECT_EQ(added_reg->invalidate_regs[3], al); + EXPECT_EQ(added_reg->invalidate_regs[4], LLDB_INVALID_REGNUM); + + added_reg = info.GetRegisterInfoAtIndex(1); + ASSERT_NE(added_reg, nullptr); + EXPECT_EQ(added_reg->value_regs[0], rax); + EXPECT_EQ(added_reg->value_regs[1], LLDB_INVALID_REGNUM); + ASSERT_NE(added_reg->invalidate_regs, nullptr); + EXPECT_EQ(added_reg->invalidate_regs[0], rax); + EXPECT_EQ(added_reg->invalidate_regs[1], ax); + EXPECT_EQ(added_reg->invalidate_regs[2], ah); + EXPECT_EQ(added_reg->invalidate_regs[3], al); + EXPECT_EQ(added_reg->invalidate_regs[4], LLDB_INVALID_REGNUM); + + added_reg = info.GetRegisterInfoAtIndex(2); + ASSERT_NE(added_reg, nullptr); + EXPECT_EQ(added_reg->value_regs[0], rax); + EXPECT_EQ(added_reg->value_regs[1], LLDB_INVALID_REGNUM); + ASSERT_NE(added_reg->invalidate_regs, nullptr); + EXPECT_EQ(added_reg->invalidate_regs[0], rax); + EXPECT_EQ(added_reg->invalidate_regs[1], eax); + EXPECT_EQ(added_reg->invalidate_regs[2], ah); + EXPECT_EQ(added_reg->invalidate_regs[3], al); + EXPECT_EQ(added_reg->invalidate_regs[4], LLDB_INVALID_REGNUM); + + added_reg = info.GetRegisterInfoAtIndex(3); + ASSERT_NE(added_reg, nullptr); + EXPECT_EQ(added_reg->value_regs[0], rax); + EXPECT_EQ(added_reg->value_regs[1], LLDB_INVALID_REGNUM); + ASSERT_NE(added_reg->invalidate_regs, nullptr); + EXPECT_EQ(added_reg->invalidate_regs[0], rax); + EXPECT_EQ(added_reg->invalidate_regs[1], eax); + EXPECT_EQ(added_reg->invalidate_regs[2], ax); + EXPECT_EQ(added_reg->invalidate_regs[3], al); + EXPECT_EQ(added_reg->invalidate_regs[4], LLDB_INVALID_REGNUM); + + added_reg = info.GetRegisterInfoAtIndex(4); + ASSERT_NE(added_reg, nullptr); + EXPECT_EQ(added_reg->value_regs[0], rax); + EXPECT_EQ(added_reg->value_regs[1], LLDB_INVALID_REGNUM); + ASSERT_NE(added_reg->invalidate_regs, nullptr); + EXPECT_EQ(added_reg->invalidate_regs[0], rax); + EXPECT_EQ(added_reg->invalidate_regs[1], eax); + EXPECT_EQ(added_reg->invalidate_regs[2], ax); + EXPECT_EQ(added_reg->invalidate_regs[3], ah); + EXPECT_EQ(added_reg->invalidate_regs[4], LLDB_INVALID_REGNUM); +}