omjavaid updated this revision to Diff 296811.
omjavaid added a comment.

This is an update after addressing comments from @jasonmolenda


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82863/new/

https://reviews.llvm.org/D82863

Files:
  lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
  lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
  lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
  lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h

Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -38,6 +38,8 @@
 
 #include "llvm/ADT/DenseMap.h"
 
+#include "Utility/ARM64_DWARF_Registers.h"
+
 namespace lldb_private {
 namespace repro {
 class Loader;
Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -1761,6 +1761,27 @@
         gdb_thread->PrivateSetRegisterValue(pair.first, buffer_sp->GetData());
       }
 
+      // Code below is specific to AArch64 target in SVE state
+      // If expedited register set contains vector granule (vg) register
+      // then thread's register context reconfiguration is triggered by
+      // calling UpdateARM64SVERegistersInfos.
+      const ArchSpec &arch = GetTarget().GetArchitecture();
+      if (arch.IsValid() && (arch.GetMachine() == llvm::Triple::aarch64 ||
+                             arch.GetMachine() == llvm::Triple::aarch64_be)) {
+        uint8_t arm64_sve_vg_dwarf_regnum = arm64_dwarf::vg;
+        GDBRemoteRegisterContext *reg_ctx_sp =
+            static_cast<GDBRemoteRegisterContext *>(
+                gdb_thread->GetRegisterContext().get());
+
+        if (reg_ctx_sp) {
+          uint32_t vg_regnum = reg_ctx_sp->ConvertRegisterKindToRegisterNumber(
+              eRegisterKindDWARF, arm64_sve_vg_dwarf_regnum);
+          if (expedited_register_map.count(vg_regnum)) {
+            reg_ctx_sp->AArch64SVEReconfigure();
+          }
+        }
+      }
+
       thread_sp->SetName(thread_name.empty() ? nullptr : thread_name.c_str());
 
       gdb_thread->SetThreadDispatchQAddr(thread_dispatch_qaddr);
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -40,6 +40,8 @@
 
   void HardcodeARMRegisters(bool from_scratch);
 
+  bool UpdateARM64SVERegistersInfos(uint64_t vg, uint32_t &end_reg_offset);
+
   void CloneFrom(GDBRemoteDynamicRegisterInfoSP process_reginfo);
 };
 
@@ -79,6 +81,8 @@
   uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
                                                uint32_t num) override;
 
+  bool AArch64SVEReconfigure();
+
 protected:
   friend class ThreadGDBRemote;
 
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -343,6 +343,17 @@
   if (dst == nullptr)
     return false;
 
+  // Code below is specific to AArch64 target in SVE state
+  // If vector granule (vg) register is being written then thread's
+  // register context reconfiguration is triggered on success.
+  bool do_reconfigure_arm64_sve = false;
+  const ArchSpec &arch = process->GetTarget().GetArchitecture();
+  if (arch.IsValid() && (arch.GetMachine() == llvm::Triple::aarch64 ||
+                         arch.GetMachine() == llvm::Triple::aarch64_be)) {
+    if (reg_info->kinds[eRegisterKindDWARF] == arm64_dwarf::vg)
+      do_reconfigure_arm64_sve = true;
+  }
+
   if (data.CopyByteOrderedData(data_offset,                // src offset
                                reg_info->byte_size,        // src length
                                dst,                        // dst
@@ -362,6 +373,11 @@
 
         {
           SetAllRegisterValid(false);
+
+          if (do_reconfigure_arm64_sve &&
+              GetPrimordialRegister(reg_info, gdb_comm))
+            AArch64SVEReconfigure();
+
           return true;
         }
       } else {
@@ -390,6 +406,10 @@
         } else {
           // This is an actual register, write it
           success = SetPrimordialRegister(reg_info, gdb_comm);
+
+          if (success && do_reconfigure_arm64_sve &&
+              GetPrimordialRegister(reg_info, gdb_comm))
+            AArch64SVEReconfigure();
         }
 
         // Check if writing this register will invalidate any other register
@@ -712,6 +732,110 @@
   return m_reg_info_sp->ConvertRegisterKindToRegisterNumber(kind, num);
 }
 
+bool GDBRemoteRegisterContext::AArch64SVEReconfigure(void) {
+  if (!m_reg_info_sp)
+    return false;
+
+  uint64_t fail_value = LLDB_INVALID_ADDRESS;
+  uint32_t vg_reg_num =
+      ConvertRegisterKindToRegisterNumber(eRegisterKindDWARF, arm64_dwarf::vg);
+  uint64_t vg_reg_value = ReadRegisterAsUnsigned(vg_reg_num, fail_value);
+
+  if (vg_reg_value != fail_value && vg_reg_value <= 32) {
+    uint32_t end_reg_offset = 0;
+    if (m_reg_info_sp->UpdateARM64SVERegistersInfos(vg_reg_value,
+                                                    end_reg_offset)) {
+      uint64_t bytes_to_copy = m_reg_data.GetByteSize();
+      if (end_reg_offset < bytes_to_copy)
+        bytes_to_copy = end_reg_offset;
+
+      // Make a heap based buffer that is big enough to store all registers
+      DataBufferSP reg_data_sp(new DataBufferHeap(end_reg_offset, 0));
+      m_reg_data.CopyData(0, bytes_to_copy, reg_data_sp->GetBytes());
+      m_reg_data.Clear();
+      m_reg_data.SetData(reg_data_sp);
+      m_reg_data.SetByteOrder(GetByteOrder());
+
+      // Invalidate all register except GPRs and VG. GPRs will retain their
+      // state.
+      uint32_t v0_reg_num =
+          ConvertRegisterKindToRegisterNumber(eRegisterKindDWARF, arm64_dwarf::v0);
+      for (uint16_t i = v0_reg_num; i < vg_reg_num; i++)
+        m_reg_valid[i] = false;
+
+      for (uint16_t i = vg_reg_num + 1; i < m_reg_valid.size(); i++)
+        m_reg_valid[i] = false;
+
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool GDBRemoteDynamicRegisterInfo::UpdateARM64SVERegistersInfos(
+    uint64_t vg, uint32_t &end_reg_offset) {
+  uint32_t z0_reg_num =
+      ConvertRegisterKindToRegisterNumber(eRegisterKindDWARF, arm64_dwarf::z0);
+  RegisterInfo *reg_info = GetRegisterInfoAtIndex(z0_reg_num);
+  uint64_t vg_reg_value_old = reg_info->byte_size / 8;
+
+  if (vg_reg_value_old != vg) {
+    uint32_t s_reg_offset = reg_info->byte_offset;
+    uint32_t d_reg_offset = reg_info->byte_offset;
+    uint32_t v_reg_offset = reg_info->byte_offset;
+    uint32_t z_reg_offset = reg_info->byte_offset;
+
+    // SVE Z register size is vg x 8 bytes.
+    uint32_t z_reg_byte_size = vg * 8;
+
+    // To calculate fpsr and fpcr offset we skip over 32 Z regs
+    // 16 P regs and ffr register to reach end of SVE regs data.
+    uint32_t fpsr_offset =
+        z_reg_offset + (z_reg_byte_size * 32) + (vg * 16) + vg;
+    uint32_t fpcr_offset = fpsr_offset + 4;
+
+    // We iterate over register infos assuming register infos will be indexed
+    // according to lldb register numbers defined in RegisterInfos_arm64_sve.h
+    for (auto &reg : m_regs) {
+      if (reg.name[0] == 'v' && isdigit(reg.name[1])) {
+        reg.byte_offset = v_reg_offset;
+        v_reg_offset += z_reg_byte_size;
+      } else if (reg.name[0] == 's' && isdigit(reg.name[1])) {
+        reg.byte_offset = s_reg_offset;
+        s_reg_offset += z_reg_byte_size;
+      } else if (reg.name[0] == 'd' && isdigit(reg.name[1])) {
+        reg.byte_offset = d_reg_offset;
+        d_reg_offset += z_reg_byte_size;
+      } else if (strcmp(reg.name, "fpsr") == 0) {
+        reg.byte_offset = fpsr_offset;
+      } else if (strcmp(reg.name, "fpcr") == 0) {
+        reg.byte_offset = fpcr_offset;
+      } else if (reg.name[0] == 'z' && isdigit(reg.name[1])) {
+        reg.byte_size = z_reg_byte_size;
+        reg.byte_offset = z_reg_offset;
+        z_reg_offset += z_reg_byte_size;
+      } else if (reg.name[0] == 'p' && isdigit(reg.name[1])) {
+        reg.byte_size = vg;
+        reg.byte_offset = z_reg_offset;
+        z_reg_offset += vg;
+      } else if (strcmp(reg.name, "ffr") == 0) {
+        reg.byte_size = vg;
+        reg.byte_offset = z_reg_offset;
+        z_reg_offset += vg;
+      }
+
+      uint32_t new_end_reg_offset = reg.byte_offset + reg.byte_size;
+      if (end_reg_offset < new_end_reg_offset)
+        end_reg_offset = new_end_reg_offset;
+    }
+
+    return true;
+  }
+
+  return false;
+}
+
 void GDBRemoteDynamicRegisterInfo::CloneFrom(
     GDBRemoteDynamicRegisterInfoSP proc_reginfo) {
   m_regs = proc_reginfo->m_regs;
Index: lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
===================================================================
--- lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
+++ lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
@@ -533,6 +533,17 @@
     }
   }
 
+  // Create per thread reginfo to support AArch64 SVE dynamic register sizes.
+  if (arch.GetMachine() == llvm::Triple::aarch64 ||
+      arch.GetMachine() == llvm::Triple::aarch64_be) {
+    for (const auto &reg : m_regs) {
+      if (strcmp(reg.name, "vg") == 0) {
+        m_per_thread_reginfo = true;
+        break;
+      }
+    }
+  }
+
   if (!generic_regs_specified) {
     switch (arch.GetMachine()) {
     case llvm::Triple::aarch64:
@@ -684,6 +695,7 @@
   m_invalidate_regs_map.clear();
   m_dynamic_reg_size_map.clear();
   m_reg_data_byte_size = 0;
+  m_per_thread_reginfo = false;
   m_finalized = false;
 }
 
Index: lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -299,14 +299,31 @@
     if (m_sve_state == SVEState::Disabled || m_sve_state == SVEState::Unknown)
       return Status("SVE disabled or not supported");
     else {
-      if (GetRegisterInfo().IsSVERegVG(reg))
-        return Status("SVE state change operation not supported");
-
       // Target has SVE enabled, we will read and cache SVE ptrace data
       error = ReadAllSVE();
       if (error.Fail())
         return error;
 
+      if (GetRegisterInfo().IsSVERegVG(reg)) {
+        uint64_t vg_value = reg_value.GetAsUInt64();
+
+        if (sve_vl_valid(vg_value * 8)) {
+          if (m_sve_header_is_valid && vg_value == GetSVERegVG())
+            return error;
+
+          SetSVERegVG(vg_value);
+
+          error = WriteSVEHeader();
+          if (error.Success())
+            ConfigureRegisterContext();
+
+          if (m_sve_header_is_valid && vg_value == GetSVERegVG())
+            return error;
+        }
+
+        return Status("SVE vector length update failed.");
+      }
+
       // If target supports SVE but currently in FPSIMD mode.
       if (m_sve_state == SVEState::FPSIMD) {
         // Here we will check if writing this SVE register enables
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to