diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index 1338d16a9171e2..6ff8e17030b10b 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -1379,6 +1379,17 @@ def isAArch64Windows(self): return arch in ["aarch64", "arm64", "arm64e"] return False + def isLoongArch(self): + """Returns true if the architecture is LoongArch.""" + arch = self.getArchitecture().lower() + return arch in ["loongarch64", "loongarch32"] + + def isLoongArchLSX(self): + return self.isLoongArch() and "lsx" in self.getCPUInfo() + + def isLoongArchLASX(self): + return self.isLoongArch() and "lasx" in self.getCPUInfo() + def getArchitecture(self): """Returns the architecture in effect the test suite is running with.""" return lldbplatformutil.getArchitecture() diff --git a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules b/lldb/packages/Python/lldbsuite/test/make/Makefile.rules index d0045ac9f91a77..2da6ff226b615c 100644 --- a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules +++ b/lldb/packages/Python/lldbsuite/test/make/Makefile.rules @@ -210,6 +210,10 @@ else ifeq "$(findstring mips,$(ARCH))" "mips" override ARCHFLAG := - endif + ifeq "$(findstring loongarch,$(ARCH))" "loongarch" + override ARCH := + override ARCHFLAG := + endif ifeq "$(SPLIT_DEBUG_SYMBOLS)" "YES" DSYM = $(EXE).debug diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp index 9ffc8ada920cb8..b04018ee243fd7 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp @@ -27,7 +27,17 @@ // struct iovec definition #include -#define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize()) +#ifndef NT_LOONGARCH_LSX +#define NT_LOONGARCH_LSX 0xa02 /* LoongArch SIMD eXtension registers */ +#endif + +#ifndef NT_LOONGARCH_LASX +#define NT_LOONGARCH_LASX \ + 0xa03 /* LoongArch Advanced SIMD eXtension registers */ +#endif + +#define REG_CONTEXT_SIZE \ + (GetGPRSize() + GetFPRSize() + sizeof(m_lsx) + sizeof(m_lasx)) using namespace lldb; using namespace lldb_private; @@ -62,6 +72,8 @@ NativeRegisterContextLinux_loongarch64::NativeRegisterContextLinux_loongarch64( NativeRegisterContextLinux(native_thread) { ::memset(&m_fpr, 0, sizeof(m_fpr)); ::memset(&m_gpr, 0, sizeof(m_gpr)); + ::memset(&m_lsx, 0, sizeof(m_lsx)); + ::memset(&m_lasx, 0, sizeof(m_lasx)); ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs)); @@ -75,6 +87,8 @@ NativeRegisterContextLinux_loongarch64::NativeRegisterContextLinux_loongarch64( m_gpr_is_valid = false; m_fpu_is_valid = false; + m_lsx_is_valid = false; + m_lasx_is_valid = false; } const RegisterInfoPOSIX_loongarch64 & @@ -135,6 +149,22 @@ Status NativeRegisterContextLinux_loongarch64::ReadRegister( offset = CalculateFprOffset(reg_info); assert(offset < GetFPRSize()); src = (uint8_t *)GetFPRBuffer() + offset; + } else if (IsLSX(reg)) { + error = ReadLSX(); + if (error.Fail()) + return error; + + offset = CalculateLsxOffset(reg_info); + assert(offset < sizeof(m_lsx)); + src = (uint8_t *)&m_lsx + offset; + } else if (IsLASX(reg)) { + error = ReadLASX(); + if (error.Fail()) + return error; + + offset = CalculateLasxOffset(reg_info); + assert(offset < sizeof(m_lasx)); + src = (uint8_t *)&m_lasx + offset; } else return Status::FromErrorString( "failed - register wasn't recognized to be a GPR or an FPR, " @@ -184,6 +214,28 @@ Status NativeRegisterContextLinux_loongarch64::WriteRegister( ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); return WriteFPR(); + } else if (IsLSX(reg)) { + error = ReadLSX(); + if (error.Fail()) + return error; + + offset = CalculateLsxOffset(reg_info); + assert(offset < sizeof(m_lsx)); + dst = (uint8_t *)&m_lsx + offset; + ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); + + return WriteLSX(); + } else if (IsLASX(reg)) { + error = ReadLASX(); + if (error.Fail()) + return error; + + offset = CalculateLasxOffset(reg_info); + assert(offset < sizeof(m_lasx)); + dst = (uint8_t *)&m_lasx + offset; + ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); + + return WriteLASX(); } return Status::FromErrorString("Failed to write register value"); @@ -203,10 +255,22 @@ Status NativeRegisterContextLinux_loongarch64::ReadAllRegisterValues( if (error.Fail()) return error; + error = ReadLSX(); + if (error.Fail()) + return error; + + error = ReadLASX(); + if (error.Fail()) + return error; + uint8_t *dst = data_sp->GetBytes(); ::memcpy(dst, GetGPRBuffer(), GetGPRSize()); dst += GetGPRSize(); ::memcpy(dst, GetFPRBuffer(), GetFPRSize()); + dst += GetFPRSize(); + ::memcpy(dst, &m_lsx, sizeof(m_lsx)); + dst += sizeof(m_lsx); + ::memcpy(dst, &m_lasx, sizeof(m_lasx)); return error; } @@ -247,11 +311,27 @@ Status NativeRegisterContextLinux_loongarch64::WriteAllRegisterValues( src += GetRegisterInfoInterface().GetGPRSize(); ::memcpy(GetFPRBuffer(), src, GetFPRSize()); - + m_fpu_is_valid = true; error = WriteFPR(); if (error.Fail()) return error; + // Currently, we assume that LoongArch always support LASX. + // TODO: check whether LSX/LASX exists. + src += GetFPRSize(); + ::memcpy(&m_lsx, src, sizeof(m_lsx)); + m_lsx_is_valid = true; + error = WriteLSX(); + if (error.Fail()) + return error; + + src += sizeof(m_lsx); + ::memcpy(&m_lasx, src, sizeof(m_lasx)); + m_lasx_is_valid = true; + error = WriteLASX(); + if (error.Fail()) + return error; + return error; } @@ -265,6 +345,16 @@ bool NativeRegisterContextLinux_loongarch64::IsFPR(unsigned reg) const { RegisterInfoPOSIX_loongarch64::FPRegSet; } +bool NativeRegisterContextLinux_loongarch64::IsLSX(unsigned reg) const { + return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) == + RegisterInfoPOSIX_loongarch64::LSXRegSet; +} + +bool NativeRegisterContextLinux_loongarch64::IsLASX(unsigned reg) const { + return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) == + RegisterInfoPOSIX_loongarch64::LASXRegSet; +} + Status NativeRegisterContextLinux_loongarch64::ReadGPR() { Status error; @@ -325,13 +415,85 @@ Status NativeRegisterContextLinux_loongarch64::WriteFPR() { ioVec.iov_len = GetFPRSize(); m_fpu_is_valid = false; + m_lsx_is_valid = false; + m_lasx_is_valid = false; return WriteRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET); } +Status NativeRegisterContextLinux_loongarch64::ReadLSX() { + Status error; + + if (m_lsx_is_valid) + return error; + + struct iovec ioVec; + ioVec.iov_base = &m_lsx; + ioVec.iov_len = sizeof(m_lsx); + + error = ReadRegisterSet(&ioVec, sizeof(m_lsx), NT_LOONGARCH_LSX); + + if (error.Success()) + m_lsx_is_valid = true; + + return error; +} + +Status NativeRegisterContextLinux_loongarch64::WriteLSX() { + Status error = ReadLSX(); + if (error.Fail()) + return error; + + struct iovec ioVec; + ioVec.iov_base = &m_lsx; + ioVec.iov_len = sizeof(m_lsx); + + m_fpu_is_valid = false; + m_lsx_is_valid = false; + m_lasx_is_valid = false; + + return WriteRegisterSet(&ioVec, sizeof(m_lsx), NT_LOONGARCH_LSX); +} + +Status NativeRegisterContextLinux_loongarch64::ReadLASX() { + Status error; + + if (m_lasx_is_valid) + return error; + + struct iovec ioVec; + ioVec.iov_base = &m_lasx; + ioVec.iov_len = sizeof(m_lasx); + + error = ReadRegisterSet(&ioVec, sizeof(m_lasx), NT_LOONGARCH_LASX); + + if (error.Success()) + m_lasx_is_valid = true; + + return error; +} + +Status NativeRegisterContextLinux_loongarch64::WriteLASX() { + Status error = ReadLASX(); + if (error.Fail()) + return error; + + struct iovec ioVec; + ioVec.iov_base = &m_lasx; + ioVec.iov_len = sizeof(m_lasx); + + m_fpu_is_valid = false; + m_lsx_is_valid = false; + m_lasx_is_valid = false; + + return WriteRegisterSet(&ioVec, sizeof(m_lasx), NT_LOONGARCH_LASX); +} + void NativeRegisterContextLinux_loongarch64::InvalidateAllRegisters() { m_gpr_is_valid = false; m_fpu_is_valid = false; + m_lsx_is_valid = false; + m_lasx_is_valid = false; } uint32_t NativeRegisterContextLinux_loongarch64::CalculateFprOffset( @@ -339,6 +501,16 @@ uint32_t NativeRegisterContextLinux_loongarch64::CalculateFprOffset( return reg_info->byte_offset - GetGPRSize(); } +uint32_t NativeRegisterContextLinux_loongarch64::CalculateLsxOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - GetGPRSize() - sizeof(m_fpr); +} + +uint32_t NativeRegisterContextLinux_loongarch64::CalculateLasxOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - GetGPRSize() - sizeof(m_fpr) - sizeof(m_lsx); +} + std::vector NativeRegisterContextLinux_loongarch64::GetExpeditedRegisters( ExpeditedRegs expType) const { diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h index 633b26fa970de1..2b2bb7d29d82f1 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h @@ -62,6 +62,14 @@ class NativeRegisterContextLinux_loongarch64 Status WriteFPR() override; + Status ReadLSX(); + + Status WriteLSX(); + + Status ReadLASX(); + + Status WriteLASX(); + void *GetGPRBuffer() override { return &m_gpr; } void *GetFPRBuffer() override { return &m_fpr; } @@ -73,18 +81,29 @@ class NativeRegisterContextLinux_loongarch64 private: bool m_gpr_is_valid; bool m_fpu_is_valid; + bool m_lsx_is_valid; + bool m_lasx_is_valid; bool m_refresh_hwdebug_info; RegisterInfoPOSIX_loongarch64::GPR m_gpr; - RegisterInfoPOSIX_loongarch64::FPR m_fpr; + RegisterInfoPOSIX_loongarch64::LSX m_lsx; + RegisterInfoPOSIX_loongarch64::LASX m_lasx; bool IsGPR(unsigned reg) const; bool IsFPR(unsigned reg) const; + bool IsLSX(unsigned reg) const; + + bool IsLASX(unsigned reg) const; + uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const; + uint32_t CalculateLsxOffset(const RegisterInfo *reg_info) const; + + uint32_t CalculateLasxOffset(const RegisterInfo *reg_info) const; + const RegisterInfoPOSIX_loongarch64 &GetRegisterInfo() const; llvm::Error ReadHardwareDebugInfo() override; diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.cpp index 49f371fb949b7b..3306fb20dae9b8 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.cpp @@ -80,3 +80,13 @@ bool RegisterContextPOSIX_loongarch64::IsFPR(unsigned int reg) { return m_register_info_up->GetRegisterSetFromRegisterIndex(reg) == RegisterInfoPOSIX_loongarch64::FPRegSet; } + +bool RegisterContextPOSIX_loongarch64::IsLSX(unsigned int reg) { + return m_register_info_up->GetRegisterSetFromRegisterIndex(reg) == + RegisterInfoPOSIX_loongarch64::LSXRegSet; +} + +bool RegisterContextPOSIX_loongarch64::IsLASX(unsigned int reg) { + return m_register_info_up->GetRegisterSetFromRegisterIndex(reg) == + RegisterInfoPOSIX_loongarch64::LASXRegSet; +} diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.h index 95f93bb41f015d..dca24e4b585bf4 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.h @@ -50,14 +50,22 @@ class RegisterContextPOSIX_loongarch64 : public lldb_private::RegisterContext { bool IsFPR(unsigned reg); + bool IsLSX(unsigned reg); + + bool IsLASX(unsigned reg); + size_t GetFPRSize() { return sizeof(RegisterInfoPOSIX_loongarch64::FPR); } uint32_t GetRegNumFCSR() const { return fpr_fcsr_loongarch; } virtual bool ReadGPR() = 0; virtual bool ReadFPR() = 0; + virtual bool ReadLSX() { return false; } + virtual bool ReadLASX() { return false; } virtual bool WriteGPR() = 0; virtual bool WriteFPR() = 0; + virtual bool WriteLSX() { return false; } + virtual bool WriteLASX() { return false; } }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_LOONGARCH64_H diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.cpp index 6c723afe4b6948..61cd40ddcfc841 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.cpp @@ -19,10 +19,19 @@ #define FPR_OFFSET(idx) ((idx)*8 + sizeof(RegisterInfoPOSIX_loongarch64::GPR)) #define FCC_OFFSET(idx) ((idx)*1 + 32 * 8 + sizeof(RegisterInfoPOSIX_loongarch64::GPR)) #define FCSR_OFFSET (8 * 1 + 32 * 8 + sizeof(RegisterInfoPOSIX_loongarch64::GPR)) +#define LSX_OFFSET(idx) \ + ((idx) * 16 + sizeof(RegisterInfoPOSIX_loongarch64::GPR) + \ + sizeof(RegisterInfoPOSIX_loongarch64::FPR)) +#define LASX_OFFSET(idx) \ + ((idx) * 32 + sizeof(RegisterInfoPOSIX_loongarch64::GPR) + \ + sizeof(RegisterInfoPOSIX_loongarch64::FPR) + \ + sizeof(RegisterInfoPOSIX_loongarch64::LSX)) #define REG_CONTEXT_SIZE \ (sizeof(RegisterInfoPOSIX_loongarch64::GPR) + \ - sizeof(RegisterInfoPOSIX_loongarch64::FPR)) + sizeof(RegisterInfoPOSIX_loongarch64::FPR) + \ + sizeof(RegisterInfoPOSIX_loongarch64::LSX) + \ + sizeof(RegisterInfoPOSIX_loongarch64::LASX)) #define DECLARE_REGISTER_INFOS_LOONGARCH64_STRUCT #include "RegisterInfos_loongarch64.h" @@ -56,7 +65,9 @@ uint32_t RegisterInfoPOSIX_loongarch64::GetRegisterInfoCount( enum { k_num_gpr_registers = gpr_last_loongarch - gpr_first_loongarch + 1, k_num_fpr_registers = fpr_last_loongarch - fpr_first_loongarch + 1, - k_num_register_sets = 2 + k_num_lsx_registers = lsx_last_loongarch - lsx_first_loongarch + 1, + k_num_lasx_registers = lasx_last_loongarch - lasx_first_loongarch + 1, + k_num_register_sets = 4 }; // LoongArch64 general purpose registers. @@ -105,13 +116,55 @@ static_assert(((sizeof g_fpr_regnums_loongarch64 / 1) == k_num_fpr_registers, "g_fpr_regnums_loongarch64 has wrong number of register infos"); +// LoongArch64 lsx vector registers. +static const uint32_t g_lsx_regnums_loongarch64[] = { + lsx_vr0_loongarch, lsx_vr1_loongarch, lsx_vr2_loongarch, + lsx_vr3_loongarch, lsx_vr4_loongarch, lsx_vr5_loongarch, + lsx_vr6_loongarch, lsx_vr7_loongarch, lsx_vr8_loongarch, + lsx_vr9_loongarch, lsx_vr10_loongarch, lsx_vr11_loongarch, + lsx_vr12_loongarch, lsx_vr13_loongarch, lsx_vr14_loongarch, + lsx_vr15_loongarch, lsx_vr16_loongarch, lsx_vr17_loongarch, + lsx_vr18_loongarch, lsx_vr19_loongarch, lsx_vr20_loongarch, + lsx_vr21_loongarch, lsx_vr22_loongarch, lsx_vr23_loongarch, + lsx_vr24_loongarch, lsx_vr25_loongarch, lsx_vr26_loongarch, + lsx_vr27_loongarch, lsx_vr28_loongarch, lsx_vr29_loongarch, + lsx_vr30_loongarch, lsx_vr31_loongarch, LLDB_INVALID_REGNUM}; + +static_assert(((sizeof g_lsx_regnums_loongarch64 / + sizeof g_lsx_regnums_loongarch64[0]) - + 1) == k_num_lsx_registers, + "g_lsx_regnums_loongarch64 has wrong number of register infos"); + +// LoongArch64 lasx vector registers. +static const uint32_t g_lasx_regnums_loongarch64[] = { + lasx_xr0_loongarch, lasx_xr1_loongarch, lasx_xr2_loongarch, + lasx_xr3_loongarch, lasx_xr4_loongarch, lasx_xr5_loongarch, + lasx_xr6_loongarch, lasx_xr7_loongarch, lasx_xr8_loongarch, + lasx_xr9_loongarch, lasx_xr10_loongarch, lasx_xr11_loongarch, + lasx_xr12_loongarch, lasx_xr13_loongarch, lasx_xr14_loongarch, + lasx_xr15_loongarch, lasx_xr16_loongarch, lasx_xr17_loongarch, + lasx_xr18_loongarch, lasx_xr19_loongarch, lasx_xr20_loongarch, + lasx_xr21_loongarch, lasx_xr22_loongarch, lasx_xr23_loongarch, + lasx_xr24_loongarch, lasx_xr25_loongarch, lasx_xr26_loongarch, + lasx_xr27_loongarch, lasx_xr28_loongarch, lasx_xr29_loongarch, + lasx_xr30_loongarch, lasx_xr31_loongarch, LLDB_INVALID_REGNUM}; + +static_assert(((sizeof g_lasx_regnums_loongarch64 / + sizeof g_lasx_regnums_loongarch64[0]) - + 1) == k_num_lasx_registers, + "g_lasx_regnums_loongarch64 has wrong number of register infos"); + // Register sets for LoongArch64. static const lldb_private::RegisterSet g_reg_sets_loongarch64[k_num_register_sets] = { {"General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums_loongarch64}, {"Floating Point Registers", "fpr", k_num_fpr_registers, - g_fpr_regnums_loongarch64}}; + g_fpr_regnums_loongarch64}, + {"LSX Vector Registers", "lsx", k_num_lsx_registers, + g_lsx_regnums_loongarch64}, + {"LASX Vector Registers", "lasx", k_num_lasx_registers, + g_lasx_regnums_loongarch64}}; RegisterInfoPOSIX_loongarch64::RegisterInfoPOSIX_loongarch64( const lldb_private::ArchSpec &target_arch, lldb_private::Flags flags) @@ -147,6 +200,10 @@ size_t RegisterInfoPOSIX_loongarch64::GetRegisterSetFromRegisterIndex( return GPRegSet; if (reg_index >= fpr_first_loongarch && reg_index <= fpr_last_loongarch) return FPRegSet; + if (reg_index >= lsx_first_loongarch && reg_index <= lsx_last_loongarch) + return LSXRegSet; + if (reg_index >= lasx_first_loongarch && reg_index <= lasx_last_loongarch) + return LASXRegSet; return LLDB_INVALID_REGNUM; } diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.h b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.h index a3338acbbc97bd..0ff08bb8c0e92a 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.h @@ -26,6 +26,8 @@ class RegisterInfoPOSIX_loongarch64 enum RegSetKind { GPRegSet, FPRegSet, + LSXRegSet, + LASXRegSet, }; struct GPR { @@ -43,6 +45,16 @@ class RegisterInfoPOSIX_loongarch64 uint32_t fcsr; }; + /* 32 registers, 128 bits width per register. */ + struct LSX { + uint64_t vr[32 * 2]; + }; + + /* 32 registers, 256 bits width per register. */ + struct LASX { + uint64_t xr[32 * 4]; + }; + RegisterInfoPOSIX_loongarch64(const lldb_private::ArchSpec &target_arch, lldb_private::Flags flags); diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_loongarch64.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_loongarch64.h index 3fb1e6a5fbef2e..ff8fe5990ce118 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfos_loongarch64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_loongarch64.h @@ -25,6 +25,14 @@ #error FPR_OFFSET must be defined before including this header file #endif +#ifndef LSX_OFFSET +#error LSX_OFFSET must be defined before including this header file +#endif + +#ifndef LASX_OFFSET +#error LASX_OFFSET must be defined before including this header file +#endif + using namespace loongarch_dwarf; // clang-format off @@ -74,6 +82,21 @@ using namespace loongarch_dwarf; FPR64_KIND(fpr_##reg, generic_kind), nullptr, nullptr, nullptr, \ } +#define DEFINE_LSX(reg, generic_kind) \ + { \ + #reg, nullptr, 16, LSX_OFFSET(lsx_##reg##_loongarch - lsx_first_loongarch),\ + lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \ + KIND_HELPER(lsx_##reg, generic_kind), nullptr, nullptr, nullptr, \ + } + +#define DEFINE_LASX(reg, generic_kind) \ + { \ + #reg, nullptr, 32, \ + LASX_OFFSET(lasx_##reg##_loongarch - lasx_first_loongarch), \ + lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \ + KIND_HELPER(lasx_##reg, generic_kind), nullptr, nullptr, nullptr, \ + } + // clang-format on static lldb_private::RegisterInfo g_register_infos_loongarch64[] = { @@ -166,6 +189,72 @@ static lldb_private::RegisterInfo g_register_infos_loongarch64[] = { DEFINE_FCC(fcc6, LLDB_INVALID_REGNUM), DEFINE_FCC(fcc7, LLDB_INVALID_REGNUM), DEFINE_FCSR(fcsr, LLDB_INVALID_REGNUM), + + DEFINE_LSX(vr0, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr1, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr2, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr3, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr4, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr5, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr6, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr7, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr8, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr9, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr10, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr11, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr12, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr13, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr14, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr15, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr16, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr17, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr18, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr19, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr20, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr21, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr22, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr23, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr24, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr25, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr26, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr27, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr28, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr29, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr30, LLDB_INVALID_REGNUM), + DEFINE_LSX(vr31, LLDB_INVALID_REGNUM), + + DEFINE_LASX(xr0, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr1, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr2, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr3, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr4, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr5, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr6, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr7, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr8, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr9, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr10, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr11, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr12, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr13, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr14, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr15, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr16, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr17, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr18, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr19, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr20, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr21, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr22, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr23, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr24, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr25, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr26, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr27, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr28, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr29, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr30, LLDB_INVALID_REGNUM), + DEFINE_LASX(xr31, LLDB_INVALID_REGNUM), }; #endif // DECLARE_REGISTER_INFOS_LOONGARCH64_STRUCT diff --git a/lldb/source/Plugins/Process/Utility/lldb-loongarch-register-enums.h b/lldb/source/Plugins/Process/Utility/lldb-loongarch-register-enums.h index f55c807f86c00e..accd53048f93e2 100644 --- a/lldb/source/Plugins/Process/Utility/lldb-loongarch-register-enums.h +++ b/lldb/source/Plugins/Process/Utility/lldb-loongarch-register-enums.h @@ -172,6 +172,76 @@ enum { fpr_fs6_loongarch = fpr_f30_loongarch, fpr_fs7_loongarch = fpr_f31_loongarch, + lsx_first_loongarch = fpr_last_loongarch + 1, + lsx_vr0_loongarch = lsx_first_loongarch, + lsx_vr1_loongarch, + lsx_vr2_loongarch, + lsx_vr3_loongarch, + lsx_vr4_loongarch, + lsx_vr5_loongarch, + lsx_vr6_loongarch, + lsx_vr7_loongarch, + lsx_vr8_loongarch, + lsx_vr9_loongarch, + lsx_vr10_loongarch, + lsx_vr11_loongarch, + lsx_vr12_loongarch, + lsx_vr13_loongarch, + lsx_vr14_loongarch, + lsx_vr15_loongarch, + lsx_vr16_loongarch, + lsx_vr17_loongarch, + lsx_vr18_loongarch, + lsx_vr19_loongarch, + lsx_vr20_loongarch, + lsx_vr21_loongarch, + lsx_vr22_loongarch, + lsx_vr23_loongarch, + lsx_vr24_loongarch, + lsx_vr25_loongarch, + lsx_vr26_loongarch, + lsx_vr27_loongarch, + lsx_vr28_loongarch, + lsx_vr29_loongarch, + lsx_vr30_loongarch, + lsx_vr31_loongarch, + lsx_last_loongarch = lsx_vr31_loongarch, + + lasx_first_loongarch = lsx_last_loongarch + 1, + lasx_xr0_loongarch = lasx_first_loongarch, + lasx_xr1_loongarch, + lasx_xr2_loongarch, + lasx_xr3_loongarch, + lasx_xr4_loongarch, + lasx_xr5_loongarch, + lasx_xr6_loongarch, + lasx_xr7_loongarch, + lasx_xr8_loongarch, + lasx_xr9_loongarch, + lasx_xr10_loongarch, + lasx_xr11_loongarch, + lasx_xr12_loongarch, + lasx_xr13_loongarch, + lasx_xr14_loongarch, + lasx_xr15_loongarch, + lasx_xr16_loongarch, + lasx_xr17_loongarch, + lasx_xr18_loongarch, + lasx_xr19_loongarch, + lasx_xr20_loongarch, + lasx_xr21_loongarch, + lasx_xr22_loongarch, + lasx_xr23_loongarch, + lasx_xr24_loongarch, + lasx_xr25_loongarch, + lasx_xr26_loongarch, + lasx_xr27_loongarch, + lasx_xr28_loongarch, + lasx_xr29_loongarch, + lasx_xr30_loongarch, + lasx_xr31_loongarch, + lasx_last_loongarch = lasx_xr31_loongarch, + k_num_registers_loongarch }; diff --git a/lldb/source/Utility/LoongArch_DWARF_Registers.h b/lldb/source/Utility/LoongArch_DWARF_Registers.h index 596806348ee245..264f329d71e079 100644 --- a/lldb/source/Utility/LoongArch_DWARF_Registers.h +++ b/lldb/source/Utility/LoongArch_DWARF_Registers.h @@ -90,6 +90,72 @@ enum { dwarf_fpr_fcc7, dwarf_fpr_fcsr, + dwarf_lsx_vr0, + dwarf_lsx_vr1, + dwarf_lsx_vr2, + dwarf_lsx_vr3, + dwarf_lsx_vr4, + dwarf_lsx_vr5, + dwarf_lsx_vr6, + dwarf_lsx_vr7, + dwarf_lsx_vr8, + dwarf_lsx_vr9, + dwarf_lsx_vr10, + dwarf_lsx_vr11, + dwarf_lsx_vr12, + dwarf_lsx_vr13, + dwarf_lsx_vr14, + dwarf_lsx_vr15, + dwarf_lsx_vr16, + dwarf_lsx_vr17, + dwarf_lsx_vr18, + dwarf_lsx_vr19, + dwarf_lsx_vr20, + dwarf_lsx_vr21, + dwarf_lsx_vr22, + dwarf_lsx_vr23, + dwarf_lsx_vr24, + dwarf_lsx_vr25, + dwarf_lsx_vr26, + dwarf_lsx_vr27, + dwarf_lsx_vr28, + dwarf_lsx_vr29, + dwarf_lsx_vr30, + dwarf_lsx_vr31, + + dwarf_lasx_xr0, + dwarf_lasx_xr1, + dwarf_lasx_xr2, + dwarf_lasx_xr3, + dwarf_lasx_xr4, + dwarf_lasx_xr5, + dwarf_lasx_xr6, + dwarf_lasx_xr7, + dwarf_lasx_xr8, + dwarf_lasx_xr9, + dwarf_lasx_xr10, + dwarf_lasx_xr11, + dwarf_lasx_xr12, + dwarf_lasx_xr13, + dwarf_lasx_xr14, + dwarf_lasx_xr15, + dwarf_lasx_xr16, + dwarf_lasx_xr17, + dwarf_lasx_xr18, + dwarf_lasx_xr19, + dwarf_lasx_xr20, + dwarf_lasx_xr21, + dwarf_lasx_xr22, + dwarf_lasx_xr23, + dwarf_lasx_xr24, + dwarf_lasx_xr25, + dwarf_lasx_xr26, + dwarf_lasx_xr27, + dwarf_lasx_xr28, + dwarf_lasx_xr29, + dwarf_lasx_xr30, + dwarf_lasx_xr31, + // register name alias dwarf_gpr_zero = dwarf_gpr_r0, dwarf_gpr_ra = dwarf_gpr_r1, diff --git a/lldb/test/API/linux/loongarch64/simd_registers/Makefile b/lldb/test/API/linux/loongarch64/simd_registers/Makefile new file mode 100644 index 00000000000000..10495940055b63 --- /dev/null +++ b/lldb/test/API/linux/loongarch64/simd_registers/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/linux/loongarch64/simd_registers/TestLoongArch64LinuxSIMDRegisters.py b/lldb/test/API/linux/loongarch64/simd_registers/TestLoongArch64LinuxSIMDRegisters.py new file mode 100644 index 00000000000000..03e1cc734b708f --- /dev/null +++ b/lldb/test/API/linux/loongarch64/simd_registers/TestLoongArch64LinuxSIMDRegisters.py @@ -0,0 +1,93 @@ +""" +Test lldb's ability to read and write the LoongArch SIMD registers. +""" + +from enum import Enum +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class Mode(Enum): + LSX = 0 + LASX = 1 + + +class LoongArch64LinuxRegisters(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + def get_build_flags(self, mode): + cflags = "-march=la464" + if mode == Mode.LASX: + cflags += " -DLASX" + + return {"CFLAGS_EXTRAS": cflags} + + def make_simd_value(self, n, mode): + count = 32 if mode == Mode.LASX else 16 + return "{" + " ".join(["0x{:02x}".format(n)] * count) + "}" + + def check_simd_values(self, value_offset, mode): + reg_prefix = "xr" if mode == Mode.LASX else "vr" + for i in range(32): + self.expect( + "register read {}{}".format(reg_prefix, i), + substrs=[self.make_simd_value(i + value_offset, mode)], + ) + + def simd_registers_impl(self, mode): + self.build(dictionary=self.get_build_flags(mode)) + self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_file_and_line( + self, + "main.c", + line_number("main.c", "// Set break point at this line."), + num_expected_locations=1, + ) + + self.runCmd("run", RUN_SUCCEEDED) + + if self.process().GetState() == lldb.eStateExited: + self.fail("Test program failed to run.") + + self.expect( + "thread list", + STOPPED_DUE_TO_BREAKPOINT, + substrs=["stopped", "stop reason = breakpoint"], + ) + + self.check_simd_values(0, mode) + self.runCmd("expression write_simd_regs(1)") + self.check_simd_values(0, mode) + + reg_prefix = "xr" if mode == Mode.LASX else "vr" + for i in range(32): + self.runCmd( + 'register write {}{} "{}"'.format( + reg_prefix, i, self.make_simd_value(i + 1, mode) + ) + ) + + # Should be visible within lldb. + self.check_simd_values(1, mode) + + # The program should agree with lldb. + self.expect("continue", substrs=["exited with status = 0"]) + + @skipUnlessArch("loongarch64") + @skipUnlessPlatform(["linux"]) + def test_lsx(self): + """Test read/write of LSX registers.""" + if not self.isLoongArchLSX(): + self.skipTest("LSX must be present.") + self.simd_registers_impl(Mode.LSX) + + @skipUnlessArch("loongarch64") + @skipUnlessPlatform(["linux"]) + def test_lasx(self): + """Test read/write of LASX registers.""" + if not self.isLoongArchLASX(): + self.skipTest("LASX must be present.") + self.simd_registers_impl(Mode.LASX) diff --git a/lldb/test/API/linux/loongarch64/simd_registers/main.c b/lldb/test/API/linux/loongarch64/simd_registers/main.c new file mode 100644 index 00000000000000..a19a13f1d30825 --- /dev/null +++ b/lldb/test/API/linux/loongarch64/simd_registers/main.c @@ -0,0 +1,108 @@ +#include + +#ifdef LASX +#define ELEM_COUNT 32 +#define REPLGR2VR_B "xvreplgr2vr.b $xr" +#define ST "xvst $xr" +#else +#define ELEM_COUNT 16 +#define REPLGR2VR_B "vreplgr2vr.b $vr" +#define ST "vst $vr" +#endif + +// base is added to each value. If base = 2, then +// assume the vector element type is char: +// $reg0 = { 0x02 * $ELEM_COUNT } +// $reg1 = { 0x03 * $ELEM_COUNT } etc. +void write_simd_regs(unsigned base) { +#define WRITE_SIMD(NUM) \ + asm volatile(REPLGR2VR_B #NUM ", %0\n\t" ::"r"(base + NUM)) + WRITE_SIMD(0); + WRITE_SIMD(1); + WRITE_SIMD(2); + WRITE_SIMD(3); + WRITE_SIMD(4); + WRITE_SIMD(5); + WRITE_SIMD(6); + WRITE_SIMD(7); + WRITE_SIMD(8); + WRITE_SIMD(9); + WRITE_SIMD(10); + WRITE_SIMD(11); + WRITE_SIMD(12); + WRITE_SIMD(13); + WRITE_SIMD(14); + WRITE_SIMD(15); + WRITE_SIMD(16); + WRITE_SIMD(17); + WRITE_SIMD(18); + WRITE_SIMD(19); + WRITE_SIMD(20); + WRITE_SIMD(21); + WRITE_SIMD(22); + WRITE_SIMD(23); + WRITE_SIMD(24); + WRITE_SIMD(25); + WRITE_SIMD(26); + WRITE_SIMD(27); + WRITE_SIMD(28); + WRITE_SIMD(29); + WRITE_SIMD(30); + WRITE_SIMD(31); +} + +unsigned verify_simd_regs() { + uint8_t simd_reg[ELEM_COUNT]; + uint8_t target = 0; + +#define VERIFY_SIMD(NUM) \ + do { \ + for (int i = 0; i < ELEM_COUNT; ++i) \ + simd_reg[i] = 0; \ + asm volatile(ST #NUM ", %0\n\t" ::"m"(simd_reg)); \ + target = NUM + 1; \ + for (int i = 0; i < ELEM_COUNT; ++i) \ + if (simd_reg[i] != target) \ + return 1; \ + } while (0) + + VERIFY_SIMD(0); + VERIFY_SIMD(1); + VERIFY_SIMD(2); + VERIFY_SIMD(3); + VERIFY_SIMD(4); + VERIFY_SIMD(5); + VERIFY_SIMD(6); + VERIFY_SIMD(7); + VERIFY_SIMD(8); + VERIFY_SIMD(9); + VERIFY_SIMD(10); + VERIFY_SIMD(11); + VERIFY_SIMD(12); + VERIFY_SIMD(13); + VERIFY_SIMD(14); + VERIFY_SIMD(15); + VERIFY_SIMD(16); + VERIFY_SIMD(17); + VERIFY_SIMD(18); + VERIFY_SIMD(19); + VERIFY_SIMD(20); + VERIFY_SIMD(21); + VERIFY_SIMD(22); + VERIFY_SIMD(23); + VERIFY_SIMD(24); + VERIFY_SIMD(25); + VERIFY_SIMD(26); + VERIFY_SIMD(27); + VERIFY_SIMD(28); + VERIFY_SIMD(29); + VERIFY_SIMD(30); + VERIFY_SIMD(31); + + return 0; +} +int main(int argc, char *argv[]) { + write_simd_regs(0); + + return verify_simd_regs(); // Set break point at this line. +}