Skip to content

[LLDB][LoongArch] Add LSX and LASX register definitions and operations #120664

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

wangleiat
Copy link
Contributor

@wangleiat wangleiat commented Dec 20, 2024

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

Created using spr 1.3.5-bogner
@llvmbot
Copy link
Member

llvmbot commented Dec 20, 2024

@llvm/pr-subscribers-testing-tools

@llvm/pr-subscribers-lldb

Author: wanglei (wangleiat)

Changes

With this patch, vector registers can be read and written.


Patch is 27.59 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/120664.diff

11 Files Affected:

  • (modified) lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp (+168)
  • (modified) lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h (+20-1)
  • (modified) lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.cpp (+10)
  • (modified) lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.h (+8)
  • (modified) lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.cpp (+60-3)
  • (modified) lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.h (+12)
  • (modified) lldb/source/Plugins/Process/Utility/RegisterInfos_loongarch64.h (+89)
  • (modified) lldb/source/Plugins/Process/Utility/lldb-loongarch-register-enums.h (+70)
  • (modified) lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_loongarch64.cpp (+14)
  • (modified) lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_loongarch64.h (+8)
  • (modified) lldb/source/Utility/LoongArch_DWARF_Registers.h (+66)
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp
index 9ffc8ada920cb8..2eeea46f7f6836 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp
@@ -27,6 +27,14 @@
 // struct iovec definition
 #include <sys/uio.h>
 
+#ifndef NT_LARCH_LSX
+#define NT_LARCH_LSX 0xa02 /* LoongArch SIMD eXtension registers */
+#endif
+
+#ifndef NT_LARCH_LASX
+#define NT_LARCH_LASX 0xa03 /* LoongArch Advanced SIMD eXtension registers */
+#endif
+
 #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
 
 using namespace lldb;
@@ -62,6 +70,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 +85,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 +147,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 +212,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 +253,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;
 }
@@ -252,6 +314,20 @@ Status NativeRegisterContextLinux_loongarch64::WriteAllRegisterValues(
   if (error.Fail())
     return error;
 
+  src += GetFPRSize();
+  ::memcpy(&m_lsx, src, sizeof(m_lsx));
+
+  error = WriteLSX();
+  if (error.Fail())
+    return error;
+
+  src += sizeof(m_lsx);
+  ::memcpy(&m_lasx, src, sizeof(m_lasx));
+
+  error = WriteLASX();
+  if (error.Fail())
+    return error;
+
   return error;
 }
 
@@ -265,6 +341,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 +411,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_LARCH_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_LARCH_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_LARCH_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_lsx), NT_LARCH_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 +497,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<uint32_t>
 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..8804eb79f8d74d 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() = 0;
+  virtual bool ReadLASX() = 0;
   virtual bool WriteGPR() = 0;
   virtual bool WriteFPR() = 0;
+  virtual bool WriteLSX() = 0;
+  virtual bool WriteLASX() = 0;
 };
 
 #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...
[truncated]

Copy link
Contributor

@SixWeining SixWeining left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add some tests in lldb/test/Shell/Register/ ?

Copy link
Collaborator

@DavidSpickett DavidSpickett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note in the PR description that this is for live processes and core files (at least it looks like it is). I would also like to see test cases for both scenarios.

Are your vector registers ever absent?

Because in AArch64's case we assume we always have Neon (which is these days not 100% true but is pretty safe for any Linux) but we have to check whether SVE exists. I don't know if you'll have to do the same thing here.

That said, if the devices without them are unsupported from your point of view, I wouldn't object to you assuming the vector registers exist, or doing so for the time being. As long as you make that clear in the PR's description.

The code looks fine, a lot of boilerplate :) I've been looking at reducing this for AArch64, so one day we might have a better, data driven way to add registers.

Note: this is my last day at work this year, back second week of January.

Once this is in, that completes #112693. So I would like to know what the state of the test suite on LoongArch is at that point. It would be good to release note the major improvements for lldb 20.

Created using spr 1.3.5-bogner
@wangleiat wangleiat changed the title [LLDB][LoongArch] Add LSX and LASX register definitions and operations [LLDB][Process] Add LSX and LASX register definitions and operations on the LoongArch64 Dec 27, 2024
Created using spr 1.3.5-bogner
Copy link
Collaborator

@DavidSpickett DavidSpickett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should have said this before you wrote out all these tests, so apologies for this up front, but -

There's no reason these tests need to be native, host only, tests. Cross compiling them is not a problem. So I'd like to see these as API tests instead, using Python. The nice thing about that is you can merge a lot of it into one file.

I think it makes sense to add a LoongArch folder next to the AArch64 one in test/API/linux, and write a test like: https://github.com/llvm/llvm-project/tree/main/lldb/test/API/linux/aarch64/tls_registers

You can then have one program file with functions to write in each of the ways you need. You will have to pass some argument to the program to tell it what to do, as calling these functions via expressions will not change anything because lldb will ("helpfully" :) ) restore these registers afterwards.

You can also set breakpoints wherever you want, without having to manually skip breakpoints already in the code.

You can add something like isAArch64SME to look for the CPU features you need in /proc/cpuinfo, same thing for skipping if it's not LoongArch.

The program code and the values you check for are fine as is, the setup just needs to be a bit more flexible.

@DavidSpickett
Copy link
Collaborator

Making the tests remote compatible also makes the changes to lit cpu id unnecessary.

@wangleiat
Copy link
Contributor Author

Thank you very much for your feedback. I am not familiar with the LLDB testing framework. I will refer to the AArch64 test cases to complete the LoongArch tests.

Created using spr 1.3.5-bogner
Copy link

github-actions bot commented Jan 9, 2025

✅ With the latest revision this PR passed the Python code formatter.

Created using spr 1.3.5-bogner
Copy link
Collaborator

@DavidSpickett DavidSpickett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like the tests could be merged into one file, but I'll think about that again once we address the register restore issue. Leave them as 2 test files for now.

Created using spr 1.3.5-bogner
@DavidSpickett DavidSpickett changed the title [LLDB][Process] Add LSX and LASX register definitions and operations on the LoongArch64 [LLDB][LoongArch] Add LSX and LASX register definitions and operations Jan 13, 2025
Copy link
Collaborator

@DavidSpickett DavidSpickett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests are excellent, thanks!

This all LGTM, assuming @SixWeining agrees.

Copy link
Contributor

@SixWeining SixWeining left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@wangleiat wangleiat merged commit 5ea1c87 into main Jan 14, 2025
7 checks passed
@wangleiat wangleiat deleted the users/wangleiat/spr/lldbloongarch-add-lsx-and-lasx-register-definitions-and-operations branch January 14, 2025 01:16
github-actions bot pushed a commit to arm/arm-toolchain that referenced this pull request Jan 14, 2025
…d operations

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/llvm-project#120664
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants