Skip to content

Commit

Permalink
[LLDB][LoongArch] Add LSX and LASX register definitions and operations
Browse files Browse the repository at this point in the history
With this patch, vector registers can be read and written when debugging a live process.

Note: We currently assume that all LoongArch64 processors include the
LSX and LASX extensions.

To add test cases, the following modifications were also made:
lldb/packages/Python/lldbsuite/test/lldbtest.py
lldb/packages/Python/lldbsuite/test/make/Makefile.rules

Reviewed By: DavidSpickett, SixWeining

Pull Request: llvm#120664
  • Loading branch information
wangleiat authored Jan 14, 2025
1 parent 1908c41 commit 5ea1c87
Show file tree
Hide file tree
Showing 14 changed files with 728 additions and 6 deletions.
11 changes: 11 additions & 0 deletions lldb/packages/Python/lldbsuite/test/lldbtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
4 changes: 4 additions & 0 deletions lldb/packages/Python/lldbsuite/test/make/Makefile.rules
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,17 @@
// struct iovec definition
#include <sys/uio.h>

#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;
Expand Down Expand Up @@ -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));
Expand All @@ -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 &
Expand Down Expand Up @@ -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, "
Expand Down Expand Up @@ -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");
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;

Expand Down Expand Up @@ -325,20 +415,102 @@ 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(
const RegisterInfo *reg_info) const {
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<uint32_t>
NativeRegisterContextLinux_loongarch64::GetExpeditedRegisters(
ExpeditedRegs expType) const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading

0 comments on commit 5ea1c87

Please sign in to comment.