diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h @@ -55,6 +55,21 @@ size_t GetFPUSize() { return sizeof(RegisterInfoPOSIX_arm64::FPU); } + bool IsSVE(unsigned reg) const; + + bool IsSVEZ(unsigned reg) const { return m_register_info_up->IsSVEZReg(reg); } + bool IsSVEP(unsigned reg) const { return m_register_info_up->IsSVEPReg(reg); } + bool IsSVEVG(unsigned reg) const { + return m_register_info_up->IsSVERegVG(reg); + } + + uint32_t GetRegNumSVEZ0() const { + return m_register_info_up->GetRegNumSVEZ0(); + } + + uint32_t GetRegNumFPCR() const { return m_register_info_up->GetRegNumFPCR(); } + uint32_t GetRegNumFPSR() const { return m_register_info_up->GetRegNumFPSR(); } + virtual bool ReadGPR() = 0; virtual bool ReadFPR() = 0; virtual bool WriteGPR() = 0; diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp @@ -39,6 +39,13 @@ return false; } +bool RegisterContextPOSIX_arm64::IsSVE(unsigned reg) const { + if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) == + RegisterInfoPOSIX_arm64::SVERegSet) + return true; + return false; +} + RegisterContextPOSIX_arm64::RegisterContextPOSIX_arm64( lldb_private::Thread &thread, std::unique_ptr register_info) @@ -79,8 +86,8 @@ RegisterContextPOSIX_arm64::GetRegisterInfoAtIndex(size_t reg) { if (reg < GetRegisterCount()) return &GetRegisterInfo()[reg]; - else - return nullptr; + + return nullptr; } size_t RegisterContextPOSIX_arm64::GetRegisterSetCount() { diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h @@ -12,11 +12,21 @@ #include "RegisterInfoAndSetInterface.h" #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" +#include + +enum class SVEState { Unknown, Disabled, FPSIMD, Full }; class RegisterInfoPOSIX_arm64 : public lldb_private::RegisterInfoAndSetInterface { public: - enum { GPRegSet = 0, FPRegSet }; + enum { GPRegSet = 0, FPRegSet, SVERegSet }; + + // AArch64 Register set FP/SIMD feature configuration + enum { + eVectorQuadwordAArch64, + eVectorQuadwordAArch64SVE, + eVectorQuadwordAArch64SVEMax = 256 + }; // based on RegisterContextDarwin_arm64.h struct GPR { @@ -73,14 +83,31 @@ size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override; + uint32_t ConfigureVectorRegisterInfos(uint32_t mode); + + bool VectorSizeIsValid(uint32_t vq) { + if (vq >= eVectorQuadwordAArch64 && vq <= eVectorQuadwordAArch64SVEMax) + return true; + return false; + } + + bool IsSVEEnabled() const { return m_vector_reg_vq > eVectorQuadwordAArch64; } + + bool IsSVEZReg(unsigned reg) const; + bool IsSVEPReg(unsigned reg) const; + bool IsSVERegVG(unsigned reg) const; + + uint32_t GetRegNumSVEZ0() const; + uint32_t GetRegNumFPCR() const; + uint32_t GetRegNumFPSR() const; + private: - uint32_t num_registers; - uint32_t num_gpr_registers; - uint32_t num_fpr_registers; + typedef std::map> + per_vq_register_infos; + + per_vq_register_infos m_per_vq_reg_infos; - uint32_t last_gpr; - uint32_t first_fpr; - uint32_t last_fpr; + uint32_t m_vector_reg_vq = eVectorQuadwordAArch64; const lldb_private::RegisterInfo *m_register_info_p; uint32_t m_register_info_count; diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp @@ -25,6 +25,24 @@ (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::FPU, reg) + \ sizeof(RegisterInfoPOSIX_arm64::GPR)) +// This information is based on AArch64 with SVE architecture reference manual. +// AArch64 with SVE has 32 Z and 16 P vector registers. There is also an FFR +// (First Fault) register and a VG (Vector Granule) pseudo register. + +// SVE 16-byte quad word is the basic unit of expansion in vector length. +#define SVE_QUAD_WORD_BYTES 16 + +// Vector length is the multiplier which decides the no of quad words, +// (multiples of 128-bits or 16-bytes) present in a Z register. Vector length +// is decided during execution and can change at runtime. SVE AArch64 register +// infos have modes one for each valid value of vector length. A change in +// vector length requires register context to update sizes of SVE Z, P and FFR. +// Also register context needs to update byte offsets of all registers affected +// by the change in vector length. +#define SVE_REGS_DEFAULT_OFFSET_LINUX sizeof(RegisterInfoPOSIX_arm64::GPR) + +#define SVE_OFFSET_VG SVE_REGS_DEFAULT_OFFSET_LINUX + #define EXC_OFFSET_NAME(reg) \ (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::EXC, reg) + \ sizeof(RegisterInfoPOSIX_arm64::GPR) + \ @@ -51,6 +69,7 @@ // Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure. #define DECLARE_REGISTER_INFOS_ARM64_STRUCT #include "RegisterInfos_arm64.h" +#include "RegisterInfos_arm64_sve.h" #undef DECLARE_REGISTER_INFOS_ARM64_STRUCT static const lldb_private::RegisterInfo * @@ -69,7 +88,8 @@ enum { k_num_gpr_registers = gpr_w28 - gpr_x0 + 1, k_num_fpr_registers = fpu_fpcr - fpu_v0 + 1, - k_num_register_sets = 2 + k_num_sve_registers = sve_ffr - sve_vg + 1, + k_num_register_sets = 3 }; // ARM64 general purpose registers. @@ -133,13 +153,38 @@ static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers, "g_fpu_regnums_arm64 has wrong number of register infos"); -// clang-format on + +// ARM64 SVE registers. +static const uint32_t g_sve_regnums_arm64[] = { + sve_vg, sve_z0, sve_z1, + sve_z2, sve_z3, sve_z4, + sve_z5, sve_z6, sve_z7, + sve_z8, sve_z9, sve_z10, + sve_z11, sve_z12, sve_z13, + sve_z14, sve_z15, sve_z16, + sve_z17, sve_z18, sve_z19, + sve_z20, sve_z21, sve_z22, + sve_z23, sve_z24, sve_z25, + sve_z26, sve_z27, sve_z28, + sve_z29, sve_z30, sve_z31, + sve_p0, sve_p1, sve_p2, + sve_p3, sve_p4, sve_p5, + sve_p6, sve_p7, sve_p8, + sve_p9, sve_p10, sve_p11, + sve_p12, sve_p13, sve_p14, + sve_p15, sve_ffr, LLDB_INVALID_REGNUM}; +static_assert(((sizeof g_sve_regnums_arm64 / sizeof g_sve_regnums_arm64[0]) - + 1) == k_num_sve_registers, + "g_sve_regnums_arm64 has wrong number of register infos"); + // Register sets for ARM64. static const lldb_private::RegisterSet g_reg_sets_arm64[k_num_register_sets] = { {"General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums_arm64}, {"Floating Point Registers", "fpu", k_num_fpr_registers, - g_fpu_regnums_arm64}}; + g_fpu_regnums_arm64}, + {"Scalable Vector Extension Registers", "sve", k_num_sve_registers, + g_sve_regnums_arm64}}; static uint32_t GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { @@ -159,25 +204,13 @@ : lldb_private::RegisterInfoAndSetInterface(target_arch), m_register_info_p(GetRegisterInfoPtr(target_arch)), m_register_info_count(GetRegisterInfoCount(target_arch)) { - - switch (target_arch.GetMachine()) { - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_32: - num_registers = k_num_gpr_registers + k_num_fpr_registers; - num_gpr_registers = k_num_gpr_registers; - num_fpr_registers = k_num_fpr_registers; - last_gpr = gpr_w28; - first_fpr = fpu_v0; - last_fpr = fpu_fpcr; - break; - default: - assert(false && "Unhandled target architecture."); - break; - } } uint32_t RegisterInfoPOSIX_arm64::GetRegisterCount() const { - return num_gpr_registers + num_fpr_registers; + if (IsSVEEnabled()) + return k_num_gpr_registers + k_num_fpr_registers + k_num_sve_registers; + + return k_num_gpr_registers + k_num_fpr_registers; } size_t RegisterInfoPOSIX_arm64::GetGPRSize() const { @@ -194,22 +227,115 @@ } size_t RegisterInfoPOSIX_arm64::GetRegisterSetCount() const { - return k_num_register_sets; + if (IsSVEEnabled()) + return k_num_register_sets; + return k_num_register_sets - 1; } size_t RegisterInfoPOSIX_arm64::GetRegisterSetFromRegisterIndex( uint32_t reg_index) const { - if (reg_index <= last_gpr) + if (reg_index <= gpr_w28) return GPRegSet; - else if (reg_index <= last_fpr) + if (reg_index <= fpu_fpcr) return FPRegSet; + if (reg_index <= sve_ffr) + return SVERegSet; return LLDB_INVALID_REGNUM; } const lldb_private::RegisterSet * RegisterInfoPOSIX_arm64::GetRegisterSet(size_t set_index) const { - if (set_index < k_num_register_sets) + if (set_index < GetRegisterSetCount()) return &g_reg_sets_arm64[set_index]; - return nullptr; } + +uint32_t +RegisterInfoPOSIX_arm64::ConfigureVectorRegisterInfos(uint32_t sve_vq) { + // sve_vq contains SVE Quad vector length in context of AArch64 SVE. + // SVE register infos if enabled cannot be disabled by selecting sve_vq = 0. + // Also if an invalid or previously set vector length is passed to this + // function then it will exit immediately with previously set vector length. + if (!VectorSizeIsValid(sve_vq) || m_vector_reg_vq == sve_vq) + return m_vector_reg_vq; + + // We cannot enable AArch64 only mode if SVE was enabled. + if (sve_vq == eVectorQuadwordAArch64 && + m_vector_reg_vq > eVectorQuadwordAArch64) + sve_vq = eVectorQuadwordAArch64SVE; + + m_vector_reg_vq = sve_vq; + + if (sve_vq == eVectorQuadwordAArch64) { + m_register_info_count = + static_cast(sizeof(g_register_infos_arm64_le) / + sizeof(g_register_infos_arm64_le[0])); + m_register_info_p = g_register_infos_arm64_le; + + return m_vector_reg_vq; + } + + m_register_info_count = + static_cast(sizeof(g_register_infos_arm64_sve_le) / + sizeof(g_register_infos_arm64_sve_le[0])); + + std::vector ®_info_ref = + m_per_vq_reg_infos[sve_vq]; + + if (reg_info_ref.empty()) { + reg_info_ref = llvm::makeArrayRef(g_register_infos_arm64_sve_le, + m_register_info_count); + + uint32_t offset = SVE_REGS_DEFAULT_OFFSET_LINUX; + + reg_info_ref[sve_vg].byte_offset = offset; + offset += reg_info_ref[sve_vg].byte_size; + + // Update Z registers size and offset + uint32_t s_reg_base = fpu_s0; + uint32_t d_reg_base = fpu_d0; + uint32_t v_reg_base = fpu_v0; + uint32_t z_reg_base = sve_z0; + + for (uint32_t index = 0; index < 32; index++) { + reg_info_ref[s_reg_base + index].byte_offset = offset; + reg_info_ref[d_reg_base + index].byte_offset = offset; + reg_info_ref[v_reg_base + index].byte_offset = offset; + reg_info_ref[z_reg_base + index].byte_offset = offset; + + reg_info_ref[z_reg_base + index].byte_size = sve_vq * SVE_QUAD_WORD_BYTES; + offset += reg_info_ref[z_reg_base + index].byte_size; + } + + // Update P registers and FFR size and offset + for (uint32_t it = sve_p0; it <= sve_ffr; it++) { + reg_info_ref[it].byte_offset = offset; + reg_info_ref[it].byte_size = sve_vq * SVE_QUAD_WORD_BYTES / 8; + offset += reg_info_ref[it].byte_size; + } + + reg_info_ref[fpu_fpsr].byte_offset = offset; + reg_info_ref[fpu_fpcr].byte_offset = offset + 4; + } + + m_register_info_p = reg_info_ref.data(); + return m_vector_reg_vq; +} + +bool RegisterInfoPOSIX_arm64::IsSVEZReg(unsigned reg) const { + return (sve_z0 <= reg && reg <= sve_z31); +} + +bool RegisterInfoPOSIX_arm64::IsSVEPReg(unsigned reg) const { + return (sve_p0 <= reg && reg <= sve_p15); +} + +bool RegisterInfoPOSIX_arm64::IsSVERegVG(unsigned reg) const { + return sve_vg == reg; +} + +uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEZ0() const { return sve_z0; } + +uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPCR() const { return fpu_fpcr; } + +uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPSR() const { return fpu_fpsr; } diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h @@ -0,0 +1,640 @@ +//===-- RegisterInfos_arm64_sve.h -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifdef DECLARE_REGISTER_INFOS_ARM64_STRUCT + +enum { + sve_fpsr = fpu_fpsr, + sve_fpcr = fpu_fpcr, + + sve_vg = exc_far, + + sve_z0, + sve_z1, + sve_z2, + sve_z3, + sve_z4, + sve_z5, + sve_z6, + sve_z7, + sve_z8, + sve_z9, + sve_z10, + sve_z11, + sve_z12, + sve_z13, + sve_z14, + sve_z15, + sve_z16, + sve_z17, + sve_z18, + sve_z19, + sve_z20, + sve_z21, + sve_z22, + sve_z23, + sve_z24, + sve_z25, + sve_z26, + sve_z27, + sve_z28, + sve_z29, + sve_z30, + sve_z31, + + sve_p0, + sve_p1, + sve_p2, + sve_p3, + sve_p4, + sve_p5, + sve_p6, + sve_p7, + sve_p8, + sve_p9, + sve_p10, + sve_p11, + sve_p12, + sve_p13, + sve_p14, + sve_p15, + + sve_ffr, +}; + +#ifndef SVE_OFFSET_VG +#error SVE_OFFSET_VG must be defined before including this header file +#endif + +static uint32_t g_sve_s0_invalidates[] = {sve_z0, fpu_v0, fpu_d0, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s1_invalidates[] = {sve_z1, fpu_v1, fpu_d1, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s2_invalidates[] = {sve_z2, fpu_v2, fpu_d2, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s3_invalidates[] = {sve_z3, fpu_v3, fpu_d3, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s4_invalidates[] = {sve_z4, fpu_v4, fpu_d4, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s5_invalidates[] = {sve_z5, fpu_v5, fpu_d5, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s6_invalidates[] = {sve_z6, fpu_v6, fpu_d6, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s7_invalidates[] = {sve_z7, fpu_v7, fpu_d7, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s8_invalidates[] = {sve_z8, fpu_v8, fpu_d8, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s9_invalidates[] = {sve_z9, fpu_v9, fpu_d9, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s10_invalidates[] = {sve_z10, fpu_v10, fpu_d10, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s11_invalidates[] = {sve_z11, fpu_v11, fpu_d11, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s12_invalidates[] = {sve_z12, fpu_v12, fpu_d12, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s13_invalidates[] = {sve_z13, fpu_v13, fpu_d13, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s14_invalidates[] = {sve_z14, fpu_v14, fpu_d14, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s15_invalidates[] = {sve_z15, fpu_v15, fpu_d15, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s16_invalidates[] = {sve_z16, fpu_v16, fpu_d16, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s17_invalidates[] = {sve_z17, fpu_v17, fpu_d17, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s18_invalidates[] = {sve_z18, fpu_v18, fpu_d18, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s19_invalidates[] = {sve_z19, fpu_v19, fpu_d19, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s20_invalidates[] = {sve_z20, fpu_v20, fpu_d20, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s21_invalidates[] = {sve_z21, fpu_v21, fpu_d21, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s22_invalidates[] = {sve_z22, fpu_v22, fpu_d22, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s23_invalidates[] = {sve_z23, fpu_v23, fpu_d23, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s24_invalidates[] = {sve_z24, fpu_v24, fpu_d24, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s25_invalidates[] = {sve_z25, fpu_v25, fpu_d25, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s26_invalidates[] = {sve_z26, fpu_v26, fpu_d26, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s27_invalidates[] = {sve_z27, fpu_v27, fpu_d27, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s28_invalidates[] = {sve_z28, fpu_v28, fpu_d28, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s29_invalidates[] = {sve_z29, fpu_v29, fpu_d29, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s30_invalidates[] = {sve_z30, fpu_v30, fpu_d30, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s31_invalidates[] = {sve_z31, fpu_v31, fpu_d31, + LLDB_INVALID_REGNUM}; + +static uint32_t g_sve_d0_invalidates[] = {sve_z0, fpu_v0, fpu_s0, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d1_invalidates[] = {sve_z1, fpu_v1, fpu_s1, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d2_invalidates[] = {sve_z2, fpu_v2, fpu_s2, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d3_invalidates[] = {sve_z3, fpu_v3, fpu_s3, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d4_invalidates[] = {sve_z4, fpu_v4, fpu_s4, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d5_invalidates[] = {sve_z5, fpu_v5, fpu_s5, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d6_invalidates[] = {sve_z6, fpu_v6, fpu_s6, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d7_invalidates[] = {sve_z7, fpu_v7, fpu_s7, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d8_invalidates[] = {sve_z8, fpu_v8, fpu_s8, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d9_invalidates[] = {sve_z9, fpu_v9, fpu_s9, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d10_invalidates[] = {sve_z10, fpu_v10, fpu_s10, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d11_invalidates[] = {sve_z11, fpu_v11, fpu_s11, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d12_invalidates[] = {sve_z12, fpu_v12, fpu_s12, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d13_invalidates[] = {sve_z13, fpu_v13, fpu_s13, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d14_invalidates[] = {sve_z14, fpu_v14, fpu_s14, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d15_invalidates[] = {sve_z15, fpu_v15, fpu_s15, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d16_invalidates[] = {sve_z16, fpu_v16, fpu_s16, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d17_invalidates[] = {sve_z17, fpu_v17, fpu_s17, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d18_invalidates[] = {sve_z18, fpu_v18, fpu_s18, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d19_invalidates[] = {sve_z19, fpu_v19, fpu_s19, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d20_invalidates[] = {sve_z20, fpu_v20, fpu_s20, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d21_invalidates[] = {sve_z21, fpu_v21, fpu_s21, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d22_invalidates[] = {sve_z22, fpu_v22, fpu_s22, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d23_invalidates[] = {sve_z23, fpu_v23, fpu_s23, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d24_invalidates[] = {sve_z24, fpu_v24, fpu_s24, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d25_invalidates[] = {sve_z25, fpu_v25, fpu_s25, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d26_invalidates[] = {sve_z26, fpu_v26, fpu_s26, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d27_invalidates[] = {sve_z27, fpu_v27, fpu_s27, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d28_invalidates[] = {sve_z28, fpu_v28, fpu_s28, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d29_invalidates[] = {sve_z29, fpu_v29, fpu_s29, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d30_invalidates[] = {sve_z30, fpu_v30, fpu_s30, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d31_invalidates[] = {sve_z31, fpu_v31, fpu_s31, + LLDB_INVALID_REGNUM}; + +static uint32_t g_sve_v0_invalidates[] = {sve_z0, fpu_d0, fpu_s0, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v1_invalidates[] = {sve_z1, fpu_d1, fpu_s1, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v2_invalidates[] = {sve_z2, fpu_d2, fpu_s2, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v3_invalidates[] = {sve_z3, fpu_d3, fpu_s3, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v4_invalidates[] = {sve_z4, fpu_d4, fpu_s4, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v5_invalidates[] = {sve_z5, fpu_d5, fpu_s5, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v6_invalidates[] = {sve_z6, fpu_d6, fpu_s6, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v7_invalidates[] = {sve_z7, fpu_d7, fpu_s7, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v8_invalidates[] = {sve_z8, fpu_d8, fpu_s8, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v9_invalidates[] = {sve_z9, fpu_d9, fpu_s9, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v10_invalidates[] = {sve_z10, fpu_d10, fpu_s10, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v11_invalidates[] = {sve_z11, fpu_d11, fpu_s11, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v12_invalidates[] = {sve_z12, fpu_d12, fpu_s12, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v13_invalidates[] = {sve_z13, fpu_d13, fpu_s13, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v14_invalidates[] = {sve_z14, fpu_d14, fpu_s14, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v15_invalidates[] = {sve_z15, fpu_d15, fpu_s15, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v16_invalidates[] = {sve_z16, fpu_d16, fpu_s16, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v17_invalidates[] = {sve_z17, fpu_d17, fpu_s17, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v18_invalidates[] = {sve_z18, fpu_d18, fpu_s18, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v19_invalidates[] = {sve_z19, fpu_d19, fpu_s19, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v20_invalidates[] = {sve_z20, fpu_d20, fpu_s20, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v21_invalidates[] = {sve_z21, fpu_d21, fpu_s21, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v22_invalidates[] = {sve_z22, fpu_d22, fpu_s22, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v23_invalidates[] = {sve_z23, fpu_d23, fpu_s23, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v24_invalidates[] = {sve_z24, fpu_d24, fpu_s24, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v25_invalidates[] = {sve_z25, fpu_d25, fpu_s25, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v26_invalidates[] = {sve_z26, fpu_d26, fpu_s26, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v27_invalidates[] = {sve_z27, fpu_d27, fpu_s27, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v28_invalidates[] = {sve_z28, fpu_d28, fpu_s28, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v29_invalidates[] = {sve_z29, fpu_d29, fpu_s29, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v30_invalidates[] = {sve_z30, fpu_d30, fpu_s30, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v31_invalidates[] = {sve_z31, fpu_d31, fpu_s31, + LLDB_INVALID_REGNUM}; + +static uint32_t g_sve_z0_invalidates[] = {fpu_v0, fpu_d0, fpu_s0, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z1_invalidates[] = {fpu_v1, fpu_d1, fpu_s1, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z2_invalidates[] = {fpu_v2, fpu_d2, fpu_s2, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z3_invalidates[] = {fpu_v3, fpu_d3, fpu_s3, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z4_invalidates[] = {fpu_v4, fpu_d4, fpu_s4, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z5_invalidates[] = {fpu_v5, fpu_d5, fpu_s5, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z6_invalidates[] = {fpu_v6, fpu_d6, fpu_s6, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z7_invalidates[] = {fpu_v7, fpu_d7, fpu_s7, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z8_invalidates[] = {fpu_v8, fpu_d8, fpu_s8, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z9_invalidates[] = {fpu_v9, fpu_d9, fpu_s9, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z10_invalidates[] = {fpu_v10, fpu_d10, fpu_s10, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z11_invalidates[] = {fpu_v11, fpu_d11, fpu_s11, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z12_invalidates[] = {fpu_v12, fpu_d12, fpu_s12, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z13_invalidates[] = {fpu_v13, fpu_d13, fpu_s13, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z14_invalidates[] = {fpu_v14, fpu_d14, fpu_s14, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z15_invalidates[] = {fpu_v15, fpu_d15, fpu_s15, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z16_invalidates[] = {fpu_v16, fpu_d16, fpu_s16, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z17_invalidates[] = {fpu_v17, fpu_d17, fpu_s17, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z18_invalidates[] = {fpu_v18, fpu_d18, fpu_s18, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z19_invalidates[] = {fpu_v19, fpu_d19, fpu_s19, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z20_invalidates[] = {fpu_v20, fpu_d20, fpu_s20, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z21_invalidates[] = {fpu_v21, fpu_d21, fpu_s21, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z22_invalidates[] = {fpu_v22, fpu_d22, fpu_s22, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z23_invalidates[] = {fpu_v23, fpu_d23, fpu_s23, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z24_invalidates[] = {fpu_v24, fpu_d24, fpu_s24, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z25_invalidates[] = {fpu_v25, fpu_d25, fpu_s25, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z26_invalidates[] = {fpu_v26, fpu_d26, fpu_s26, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z27_invalidates[] = {fpu_v27, fpu_d27, fpu_s27, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z28_invalidates[] = {fpu_v28, fpu_d28, fpu_s28, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z29_invalidates[] = {fpu_v29, fpu_d29, fpu_s29, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z30_invalidates[] = {fpu_v30, fpu_d30, fpu_s30, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_z31_invalidates[] = {fpu_v31, fpu_d31, fpu_s31, + LLDB_INVALID_REGNUM}; + +static uint32_t g_contained_z0[] = {sve_z0, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z1[] = {sve_z1, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z2[] = {sve_z2, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z3[] = {sve_z3, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z4[] = {sve_z4, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z5[] = {sve_z5, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z6[] = {sve_z6, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z7[] = {sve_z7, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z8[] = {sve_z8, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z9[] = {sve_z9, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z10[] = {sve_z10, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z11[] = {sve_z11, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z12[] = {sve_z12, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z13[] = {sve_z13, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z14[] = {sve_z14, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z15[] = {sve_z15, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z16[] = {sve_z16, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z17[] = {sve_z17, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z18[] = {sve_z18, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z19[] = {sve_z19, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z20[] = {sve_z20, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z21[] = {sve_z21, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z22[] = {sve_z22, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z23[] = {sve_z23, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z24[] = {sve_z24, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z25[] = {sve_z25, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z26[] = {sve_z26, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z27[] = {sve_z27, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z28[] = {sve_z28, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z29[] = {sve_z29, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z30[] = {sve_z30, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z31[] = {sve_z31, LLDB_INVALID_REGNUM}; + +#define VG_OFFSET_NAME(reg) SVE_OFFSET_VG + +#define SVE_REG_KIND(reg) MISC_KIND(reg, sve, LLDB_INVALID_REGNUM) +#define MISC_VG_KIND(lldb_kind) MISC_KIND(vg, sve, LLDB_INVALID_REGNUM) + +// Default offset SVE Z registers and all corresponding pseudo registers +// ( S, D and V registers) is zero and will be configured during execution. + +// Defines sve pseudo vector (V) register with 16-byte size +#define DEFINE_VREG_SVE(vreg, zreg) \ + { \ + #vreg, nullptr, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \ + VREG_KIND(vreg), g_contained_##zreg, g_sve_##vreg##_invalidates, \ + nullptr, 0 \ + } + +// Defines S and D pseudo registers mapping over corresponding vector register +#define DEFINE_FPU_PSEUDO_SVE(reg, size, zreg) \ + { \ + #reg, nullptr, size, 0, lldb::eEncodingIEEE754, lldb::eFormatFloat, \ + LLDB_KIND(fpu_##reg), g_contained_##zreg, g_sve_##reg##_invalidates, \ + nullptr, 0 \ + } + +// Defines a Z vector register with 16-byte default size +#define DEFINE_ZREG(reg) \ + { \ + #reg, nullptr, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \ + SVE_REG_KIND(reg), nullptr, g_sve_##reg##_invalidates, nullptr, 0 \ + } + +// Defines a P vector register with 2-byte default size +#define DEFINE_PREG(reg) \ + { \ + #reg, nullptr, 2, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \ + SVE_REG_KIND(reg), nullptr, nullptr, nullptr, 0 \ + } + +static lldb_private::RegisterInfo g_register_infos_arm64_sve_le[] = { + // clang-format off + // DEFINE_GPR64(name, GENERIC KIND) + DEFINE_GPR64(x0, LLDB_REGNUM_GENERIC_ARG1), + DEFINE_GPR64(x1, LLDB_REGNUM_GENERIC_ARG2), + DEFINE_GPR64(x2, LLDB_REGNUM_GENERIC_ARG3), + DEFINE_GPR64(x3, LLDB_REGNUM_GENERIC_ARG4), + DEFINE_GPR64(x4, LLDB_REGNUM_GENERIC_ARG5), + DEFINE_GPR64(x5, LLDB_REGNUM_GENERIC_ARG6), + DEFINE_GPR64(x6, LLDB_REGNUM_GENERIC_ARG7), + DEFINE_GPR64(x7, LLDB_REGNUM_GENERIC_ARG8), + DEFINE_GPR64(x8, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x9, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x10, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x11, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x12, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x13, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x14, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x15, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x16, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x17, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x18, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x19, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x20, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x21, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x22, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x23, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x24, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x25, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x26, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x27, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x28, LLDB_INVALID_REGNUM), + // DEFINE_GPR64(name, GENERIC KIND) + DEFINE_GPR64_ALT(fp, x29, LLDB_REGNUM_GENERIC_FP), + DEFINE_GPR64_ALT(lr, x30, LLDB_REGNUM_GENERIC_RA), + DEFINE_GPR64_ALT(sp, x31, LLDB_REGNUM_GENERIC_SP), + DEFINE_GPR64(pc, LLDB_REGNUM_GENERIC_PC), + + // DEFINE_MISC_REGS(name, size, TYPE, lldb kind) + DEFINE_MISC_REGS(cpsr, 4, GPR, gpr_cpsr), + + // DEFINE_GPR32(name, parent name) + DEFINE_GPR32(w0, x0), + DEFINE_GPR32(w1, x1), + DEFINE_GPR32(w2, x2), + DEFINE_GPR32(w3, x3), + DEFINE_GPR32(w4, x4), + DEFINE_GPR32(w5, x5), + DEFINE_GPR32(w6, x6), + DEFINE_GPR32(w7, x7), + DEFINE_GPR32(w8, x8), + DEFINE_GPR32(w9, x9), + DEFINE_GPR32(w10, x10), + DEFINE_GPR32(w11, x11), + DEFINE_GPR32(w12, x12), + DEFINE_GPR32(w13, x13), + DEFINE_GPR32(w14, x14), + DEFINE_GPR32(w15, x15), + DEFINE_GPR32(w16, x16), + DEFINE_GPR32(w17, x17), + DEFINE_GPR32(w18, x18), + DEFINE_GPR32(w19, x19), + DEFINE_GPR32(w20, x20), + DEFINE_GPR32(w21, x21), + DEFINE_GPR32(w22, x22), + DEFINE_GPR32(w23, x23), + DEFINE_GPR32(w24, x24), + DEFINE_GPR32(w25, x25), + DEFINE_GPR32(w26, x26), + DEFINE_GPR32(w27, x27), + DEFINE_GPR32(w28, x28), + + // DEFINE_VREG_SVE(v register, z register) + DEFINE_VREG_SVE(v0, z0), + DEFINE_VREG_SVE(v1, z1), + DEFINE_VREG_SVE(v2, z2), + DEFINE_VREG_SVE(v3, z3), + DEFINE_VREG_SVE(v4, z4), + DEFINE_VREG_SVE(v5, z5), + DEFINE_VREG_SVE(v6, z6), + DEFINE_VREG_SVE(v7, z7), + DEFINE_VREG_SVE(v8, z8), + DEFINE_VREG_SVE(v9, z9), + DEFINE_VREG_SVE(v10, z10), + DEFINE_VREG_SVE(v11, z11), + DEFINE_VREG_SVE(v12, z12), + DEFINE_VREG_SVE(v13, z13), + DEFINE_VREG_SVE(v14, z14), + DEFINE_VREG_SVE(v15, z15), + DEFINE_VREG_SVE(v16, z16), + DEFINE_VREG_SVE(v17, z17), + DEFINE_VREG_SVE(v18, z18), + DEFINE_VREG_SVE(v19, z19), + DEFINE_VREG_SVE(v20, z20), + DEFINE_VREG_SVE(v21, z21), + DEFINE_VREG_SVE(v22, z22), + DEFINE_VREG_SVE(v23, z23), + DEFINE_VREG_SVE(v24, z24), + DEFINE_VREG_SVE(v25, z25), + DEFINE_VREG_SVE(v26, z26), + DEFINE_VREG_SVE(v27, z27), + DEFINE_VREG_SVE(v28, z28), + DEFINE_VREG_SVE(v29, z29), + DEFINE_VREG_SVE(v30, z30), + DEFINE_VREG_SVE(v31, z31), + + // DEFINE_FPU_PSEUDO(name, size, ENDIAN OFFSET, parent register) + DEFINE_FPU_PSEUDO_SVE(s0, 4, z0), + DEFINE_FPU_PSEUDO_SVE(s1, 4, z1), + DEFINE_FPU_PSEUDO_SVE(s2, 4, z2), + DEFINE_FPU_PSEUDO_SVE(s3, 4, z3), + DEFINE_FPU_PSEUDO_SVE(s4, 4, z4), + DEFINE_FPU_PSEUDO_SVE(s5, 4, z5), + DEFINE_FPU_PSEUDO_SVE(s6, 4, z6), + DEFINE_FPU_PSEUDO_SVE(s7, 4, z7), + DEFINE_FPU_PSEUDO_SVE(s8, 4, z8), + DEFINE_FPU_PSEUDO_SVE(s9, 4, z9), + DEFINE_FPU_PSEUDO_SVE(s10, 4, z10), + DEFINE_FPU_PSEUDO_SVE(s11, 4, z11), + DEFINE_FPU_PSEUDO_SVE(s12, 4, z12), + DEFINE_FPU_PSEUDO_SVE(s13, 4, z13), + DEFINE_FPU_PSEUDO_SVE(s14, 4, z14), + DEFINE_FPU_PSEUDO_SVE(s15, 4, z15), + DEFINE_FPU_PSEUDO_SVE(s16, 4, z16), + DEFINE_FPU_PSEUDO_SVE(s17, 4, z17), + DEFINE_FPU_PSEUDO_SVE(s18, 4, z18), + DEFINE_FPU_PSEUDO_SVE(s19, 4, z19), + DEFINE_FPU_PSEUDO_SVE(s20, 4, z20), + DEFINE_FPU_PSEUDO_SVE(s21, 4, z21), + DEFINE_FPU_PSEUDO_SVE(s22, 4, z22), + DEFINE_FPU_PSEUDO_SVE(s23, 4, z23), + DEFINE_FPU_PSEUDO_SVE(s24, 4, z24), + DEFINE_FPU_PSEUDO_SVE(s25, 4, z25), + DEFINE_FPU_PSEUDO_SVE(s26, 4, z26), + DEFINE_FPU_PSEUDO_SVE(s27, 4, z27), + DEFINE_FPU_PSEUDO_SVE(s28, 4, z28), + DEFINE_FPU_PSEUDO_SVE(s29, 4, z29), + DEFINE_FPU_PSEUDO_SVE(s30, 4, z30), + DEFINE_FPU_PSEUDO_SVE(s31, 4, z31), + + DEFINE_FPU_PSEUDO_SVE(d0, 8, z0), + DEFINE_FPU_PSEUDO_SVE(d1, 8, z1), + DEFINE_FPU_PSEUDO_SVE(d2, 8, z2), + DEFINE_FPU_PSEUDO_SVE(d3, 8, z3), + DEFINE_FPU_PSEUDO_SVE(d4, 8, z4), + DEFINE_FPU_PSEUDO_SVE(d5, 8, z5), + DEFINE_FPU_PSEUDO_SVE(d6, 8, z6), + DEFINE_FPU_PSEUDO_SVE(d7, 8, z7), + DEFINE_FPU_PSEUDO_SVE(d8, 8, z8), + DEFINE_FPU_PSEUDO_SVE(d9, 8, z9), + DEFINE_FPU_PSEUDO_SVE(d10, 8, z10), + DEFINE_FPU_PSEUDO_SVE(d11, 8, z11), + DEFINE_FPU_PSEUDO_SVE(d12, 8, z12), + DEFINE_FPU_PSEUDO_SVE(d13, 8, z13), + DEFINE_FPU_PSEUDO_SVE(d14, 8, z14), + DEFINE_FPU_PSEUDO_SVE(d15, 8, z15), + DEFINE_FPU_PSEUDO_SVE(d16, 8, z16), + DEFINE_FPU_PSEUDO_SVE(d17, 8, z17), + DEFINE_FPU_PSEUDO_SVE(d18, 8, z18), + DEFINE_FPU_PSEUDO_SVE(d19, 8, z19), + DEFINE_FPU_PSEUDO_SVE(d20, 8, z20), + DEFINE_FPU_PSEUDO_SVE(d21, 8, z21), + DEFINE_FPU_PSEUDO_SVE(d22, 8, z22), + DEFINE_FPU_PSEUDO_SVE(d23, 8, z23), + DEFINE_FPU_PSEUDO_SVE(d24, 8, z24), + DEFINE_FPU_PSEUDO_SVE(d25, 8, z25), + DEFINE_FPU_PSEUDO_SVE(d26, 8, z26), + DEFINE_FPU_PSEUDO_SVE(d27, 8, z27), + DEFINE_FPU_PSEUDO_SVE(d28, 8, z28), + DEFINE_FPU_PSEUDO_SVE(d29, 8, z29), + DEFINE_FPU_PSEUDO_SVE(d30, 8, z30), + DEFINE_FPU_PSEUDO_SVE(d31, 8, z31), + + // DEFINE_MISC_REGS(name, size, TYPE, lldb kind) + DEFINE_MISC_REGS(fpsr, 4, FPU, fpu_fpsr), + DEFINE_MISC_REGS(fpcr, 4, FPU, fpu_fpcr), + + DEFINE_MISC_REGS(vg, 8, VG, sve_vg), + // DEFINE_ZREG(name) + DEFINE_ZREG(z0), + DEFINE_ZREG(z1), + DEFINE_ZREG(z2), + DEFINE_ZREG(z3), + DEFINE_ZREG(z4), + DEFINE_ZREG(z5), + DEFINE_ZREG(z6), + DEFINE_ZREG(z7), + DEFINE_ZREG(z8), + DEFINE_ZREG(z9), + DEFINE_ZREG(z10), + DEFINE_ZREG(z11), + DEFINE_ZREG(z12), + DEFINE_ZREG(z13), + DEFINE_ZREG(z14), + DEFINE_ZREG(z15), + DEFINE_ZREG(z16), + DEFINE_ZREG(z17), + DEFINE_ZREG(z18), + DEFINE_ZREG(z19), + DEFINE_ZREG(z20), + DEFINE_ZREG(z21), + DEFINE_ZREG(z22), + DEFINE_ZREG(z23), + DEFINE_ZREG(z24), + DEFINE_ZREG(z25), + DEFINE_ZREG(z26), + DEFINE_ZREG(z27), + DEFINE_ZREG(z28), + DEFINE_ZREG(z29), + DEFINE_ZREG(z30), + DEFINE_ZREG(z31), + + // DEFINE_PREG(name) + DEFINE_PREG(p0), + DEFINE_PREG(p1), + DEFINE_PREG(p2), + DEFINE_PREG(p3), + DEFINE_PREG(p4), + DEFINE_PREG(p5), + DEFINE_PREG(p6), + DEFINE_PREG(p7), + DEFINE_PREG(p8), + DEFINE_PREG(p9), + DEFINE_PREG(p10), + DEFINE_PREG(p11), + DEFINE_PREG(p12), + DEFINE_PREG(p13), + DEFINE_PREG(p14), + DEFINE_PREG(p15), + + // DEFINE FFR + DEFINE_PREG(ffr) + // clang-format on +}; + +#endif // DECLARE_REGISTER_INFOS_ARM64_SVE_STRUCT diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h @@ -9,7 +9,9 @@ #ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H #define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H +#include "Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h" #include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" + #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" @@ -49,6 +51,18 @@ lldb::DataBufferSP m_gpr_buffer; lldb_private::DataExtractor m_gpr; lldb_private::DataExtractor m_fpregset; + lldb_private::DataExtractor m_sveregset; + + SVEState m_sve_state; + uint16_t m_sve_vector_length = 0; + + const uint8_t *GetSVEBuffer(uint64_t offset = 0); + + void ConfigureRegisterContext(); + + uint32_t CalculateSVEOffset(const lldb_private::RegisterInfo *reg_info); + + uint64_t GetSVERegVG() { return m_sve_vector_length / 8; } }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "RegisterContextPOSIXCore_arm64.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "lldb/Target/Thread.h" @@ -27,6 +28,12 @@ m_fpregset = getRegset( notes, m_register_info_up->GetTargetArchitecture().GetTriple(), FPR_Desc); + + m_sveregset = + getRegset(notes, m_register_info_up->GetTargetArchitecture().GetTriple(), + AARCH64_SVE_Desc); + + ConfigureRegisterContext(); } RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() {} @@ -45,9 +52,55 @@ return false; } +const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) { + return m_sveregset.GetDataStart() + offset; +} + +void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() { + if (m_sveregset.GetByteSize() > sizeof(user_sve_header)) { + uint64_t sve_header_field_offset = 8; + m_sve_vector_length = m_sveregset.GetU16(&sve_header_field_offset); + sve_header_field_offset = 12; + uint16_t sve_header_flags_field = + m_sveregset.GetU16(&sve_header_field_offset); + if ((sve_header_flags_field & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD) + m_sve_state = SVEState::FPSIMD; + else if ((sve_header_flags_field & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE) + m_sve_state = SVEState::Full; + + if (sve_vl_valid(m_sve_vector_length)) + m_register_info_up->ConfigureVectorRegisterInfos( + sve_vq_from_vl(m_sve_vector_length)); + else { + m_sve_state = SVEState::Disabled; + m_sve_vector_length = 0; + } + } else + m_sve_state = SVEState::Disabled; +} + +uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset( + const RegisterInfo *reg_info) { + // Start of Z0 data is after GPRs plus 8 bytes of vg register + uint32_t sve_reg_offset = LLDB_INVALID_INDEX32; + if (m_sve_state == SVEState::FPSIMD) { + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + sve_reg_offset = SVE_PT_FPSIMD_OFFSET + (reg - GetRegNumSVEZ0()) * 16; + } else if (m_sve_state == SVEState::Full) { + uint32_t sve_z0_offset = GetGPRSize() + 8; + sve_reg_offset = + SVE_SIG_REGS_OFFSET + reg_info->byte_offset - sve_z0_offset; + } + + return sve_reg_offset; +} + bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) { - lldb::offset_t offset = reg_info->byte_offset; + Status error; + lldb::offset_t offset; + + offset = reg_info->byte_offset; if (offset + reg_info->byte_size <= GetGPRSize()) { uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); if (offset == reg_info->byte_offset + reg_info->byte_size) { @@ -60,15 +113,86 @@ if (reg == LLDB_INVALID_REGNUM) return false; - offset -= GetGPRSize(); - if (IsFPR(reg) && offset + reg_info->byte_size <= GetFPUSize()) { - Status error; - value.SetFromMemoryData(reg_info, m_fpregset.GetDataStart() + offset, - reg_info->byte_size, lldb::eByteOrderLittle, error); - return error.Success(); - } + if (IsFPR(reg)) { + if (m_sve_state == SVEState::Disabled) { + // SVE is disabled take legacy route for FPU register access + offset -= GetGPRSize(); + if (offset < m_fpregset.GetByteSize()) { + value.SetFromMemoryData(reg_info, m_fpregset.GetDataStart() + offset, + reg_info->byte_size, lldb::eByteOrderLittle, + error); + return error.Success(); + } + } else { + // FPSR and FPCR will be located right after Z registers in + // SVEState::FPSIMD while in SVEState::Full they will be located at the + // end of register data after an alignment correction based on currently + // selected vector length. + uint32_t sve_reg_num = LLDB_INVALID_REGNUM; + if (reg == GetRegNumFPSR()) { + sve_reg_num = reg; + if (m_sve_state == SVEState::Full) + offset = SVE_PT_SVE_FPSR_OFFSET(sve_vq_from_vl(m_sve_vector_length)); + else if (m_sve_state == SVEState::FPSIMD) + offset = SVE_PT_FPSIMD_OFFSET + (32 * 16); + } else if (reg == GetRegNumFPCR()) { + sve_reg_num = reg; + if (m_sve_state == SVEState::Full) + offset = SVE_PT_SVE_FPCR_OFFSET(sve_vq_from_vl(m_sve_vector_length)); + else if (m_sve_state == SVEState::FPSIMD) + offset = SVE_PT_FPSIMD_OFFSET + (32 * 16) + 4; + } else { + // Extract SVE Z register value register number for this reg_info + if (reg_info->value_regs && + reg_info->value_regs[0] != LLDB_INVALID_REGNUM) + sve_reg_num = reg_info->value_regs[0]; + offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num)); + } + + assert(sve_reg_num != LLDB_INVALID_REGNUM); + assert(offset < m_sveregset.GetByteSize()); + value.SetFromMemoryData(reg_info, GetSVEBuffer(offset), + reg_info->byte_size, lldb::eByteOrderLittle, + error); + } + } else if (IsSVE(reg)) { + if (IsSVEVG(reg)) { + value = GetSVERegVG(); + return true; + } - return false; + switch (m_sve_state) { + case SVEState::FPSIMD: { + // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so just + // copy 16 bytes of v register to the start of z register. All other + // SVE register will be set to zero. + uint64_t byte_size = 1; + uint8_t zeros = 0; + const uint8_t *src = &zeros; + if (IsSVEZ(reg)) { + byte_size = 16; + offset = CalculateSVEOffset(reg_info); + assert(offset < m_sveregset.GetByteSize()); + src = GetSVEBuffer(offset); + } + value.SetFromMemoryData(reg_info, src, byte_size, lldb::eByteOrderLittle, + error); + } break; + case SVEState::Full: + offset = CalculateSVEOffset(reg_info); + assert(offset < m_sveregset.GetByteSize()); + value.SetFromMemoryData(reg_info, GetSVEBuffer(offset), + reg_info->byte_size, lldb::eByteOrderLittle, + error); + break; + case SVEState::Disabled: + default: + return false; + } + } else + return false; + + return error.Success(); } bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues( diff --git a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h --- a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h @@ -107,6 +107,10 @@ {llvm::Triple::OpenBSD, llvm::Triple::UnknownArch, OPENBSD::NT_FPREGS}, }; +constexpr RegsetDesc AARCH64_SVE_Desc[] = { + {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_SVE}, +}; + constexpr RegsetDesc PPC_VMX_Desc[] = { {llvm::Triple::FreeBSD, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX}, {llvm::Triple::Linux, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX}, diff --git a/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py b/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py --- a/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py +++ b/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py @@ -35,69 +35,69 @@ _mips_regions = 5 _ppc64le_regions = 2 - @skipIf(triple='^mips') @skipIfLLVMTargetMissing("AArch64") - @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. + @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. def test_aarch64(self): """Test that lldb can read the process information from an aarch64 linux core file.""" - self.do_test("linux-aarch64", self._aarch64_pid, self._aarch64_regions, "a.out") + self.do_test("linux-aarch64", self._aarch64_pid, + self._aarch64_regions, "a.out") @skipIf(triple='^mips') @skipIfLLVMTargetMissing("X86") - @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. + @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. def test_i386(self): """Test that lldb can read the process information from an i386 linux core file.""" self.do_test("linux-i386", self._i386_pid, self._i386_regions, "a.out") @skipIfLLVMTargetMissing("Mips") - @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. + @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. def test_mips_o32(self): """Test that lldb can read the process information from an MIPS O32 linux core file.""" self.do_test("linux-mipsel-gnuabio32", self._mips_o32_pid, - self._mips_regions, "linux-mipsel-gn") + self._mips_regions, "linux-mipsel-gn") @skipIfLLVMTargetMissing("Mips") - @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. + @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. def test_mips_n32(self): """Test that lldb can read the process information from an MIPS N32 linux core file """ self.do_test("linux-mips64el-gnuabin32", self._mips64_n32_pid, - self._mips_regions, "linux-mips64el-") + self._mips_regions, "linux-mips64el-") @skipIfLLVMTargetMissing("Mips") - @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. + @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. def test_mips_n64(self): """Test that lldb can read the process information from an MIPS N64 linux core file """ self.do_test("linux-mips64el-gnuabi64", self._mips64_n64_pid, - self._mips_regions, "linux-mips64el-") + self._mips_regions, "linux-mips64el-") @skipIf(triple='^mips') @skipIfLLVMTargetMissing("PowerPC") - @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. + @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. def test_ppc64le(self): """Test that lldb can read the process information from an ppc64le linux core file.""" self.do_test("linux-ppc64le", self._ppc64le_pid, self._ppc64le_regions, - "linux-ppc64le.ou") + "linux-ppc64le.ou") @skipIf(triple='^mips') @skipIfLLVMTargetMissing("X86") - @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. + @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. def test_x86_64(self): """Test that lldb can read the process information from an x86_64 linux core file.""" self.do_test("linux-x86_64", self._x86_64_pid, self._x86_64_regions, - "a.out") + "a.out") @skipIf(triple='^mips') @skipIfLLVMTargetMissing("SystemZ") - @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. + @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. def test_s390x(self): """Test that lldb can read the process information from an s390x linux core file.""" self.do_test("linux-s390x", self._s390x_pid, self._s390x_regions, - "a.out") + "a.out") @skipIf(triple='^mips') @skipIfLLVMTargetMissing("X86") - @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. + @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented. def test_same_pid_running(self): """Test that we read the information from the core correctly even if we have a running process with the same PID around""" @@ -122,11 +122,11 @@ f.seek(pid_offset) f.write(struct.pack("