[Lldb-commits] [lldb] [lldb][AArch64][Linux] Add function to get regset dependencies (PR #212476)
David Spickett via lldb-commits
lldb-commits at lists.llvm.org
Tue Jul 28 07:01:49 PDT 2026
https://github.com/DavidSpickett updated https://github.com/llvm/llvm-project/pull/212476
>From 3830947eb91c647c21824c0e0d27fc33912e7d84 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Wed, 22 Jul 2026 12:43:33 +0000
Subject: [PATCH 1/4] [lldb][AArch64][Linux] Add function to get regset
dependencies
This function encodes relations between sets so that you
don't have to remember all the dependencies.
There are some places where we do:
if some condition:
Invalidate(some set);
I've chosen not to put that logic in this new function so
that it can be a simple switch case.
The few places we need extra state to make the decision
are also all SVE/SME related. This code will likely remain
bespoke anyway.
Whereas the simple paths will all get collapsed into
a generic handler later.
I have kept Invalidate() variadic as there might be some
situations where explicitly invalidating many things
helps readers understand the code.
---
.../NativeRegisterContextLinux_arm64.cpp | 29 +++++++++++++++++++
.../Linux/NativeRegisterContextLinux_arm64.h | 12 +++++++-
2 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
index 82d6f8658c30b..d14426c6e586d 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -59,6 +59,35 @@ using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_linux;
+NativeRegisterContextLinux_arm64::RegisterSetType
+NativeRegisterContextLinux_arm64::GetInvalidationMask(
+ const RegisterSetType set) const {
+ switch (set) {
+ case RegisterSetType::FPMR:
+ case RegisterSetType::GPR:
+ case RegisterSetType::GCS:
+ case RegisterSetType::MTE:
+ case RegisterSetType::PAC:
+ case RegisterSetType::POE:
+ case RegisterSetType::TLS:
+ return set;
+ case RegisterSetType::SVE_HEADER:
+ case RegisterSetType::SVE:
+ case RegisterSetType::FPR:
+ return RegisterSetType::SVE_HEADER | RegisterSetType::SVE |
+ // SVE registers overlap FP registers in hardware.
+ RegisterSetType::FPR;
+ case RegisterSetType::ZA_HEADER:
+ case RegisterSetType::ZA:
+ case RegisterSetType::ZT:
+ // In the Linux ptrace ABI, writes that enable ZA or ZT result in
+ // both ZA and ZT being enabled.
+ return RegisterSetType::ZA_HEADER | RegisterSetType::ZA |
+ RegisterSetType::ZT;
+ llvm_unreachable("Unhandled register set");
+ }
+}
+
// A NativeRegisterContext is constructed per thread, but all threads' registers
// will contain the same fields. Therefore this mutex prevents each instance
// competing with the other, and subsequent instances from having to detect the
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
index 0414e5b6e612d..a9f34399f2a34 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
@@ -123,9 +123,19 @@ class NativeRegisterContextLinux_arm64
return any(m_validity & set);
}
+ /// Returns the mask of sets that would be invalidated if the given set was
+ /// invalidated. That is, the set itself and any sets that depend on it.
+ ///
+ /// If you need anything more complex such as only invalidating during certain
+ /// modes, put that logic in the function that calls Invalidate().
+ RegisterSetType GetInvalidationMask(const RegisterSetType set) const;
+
+ /// Invalidate our saved copies of the given register sets and any sets that
+ /// depend on those sets.
template <typename... Ts> void Invalidate(RegisterSetType first, Ts... rest) {
static_assert((std::is_same_v<Ts, RegisterSetType> && ...));
- m_validity &= ~(first | ... | rest);
+ m_validity &=
+ ~(GetInvalidationMask(first) | ... | GetInvalidationMask(rest));
}
Status RestoreRegisters(void *buffer, const uint8_t **src, size_t len,
>From 1a594700a5dca26010953888821193bd36d02856 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Wed, 22 Jul 2026 14:20:38 +0000
Subject: [PATCH 2/4] convert multiple invalidates into single invalidates
---
.../NativeRegisterContextLinux_arm64.cpp | 32 ++++++-------------
1 file changed, 10 insertions(+), 22 deletions(-)
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
index d14426c6e586d..453d1cfbe699d 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -1111,7 +1111,7 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
std::bind(&NativeRegisterContextLinux_arm64::WriteAllSVE, this));
break;
case RegisterSetType::FPR: {
- Invalidate(RegisterSetType::SVE_HEADER, RegisterSetType::SVE);
+ Invalidate(RegisterSetType::SVE_HEADER);
m_sve_state = SVEState::Unknown;
ConfigureRegisterContext();
@@ -1161,10 +1161,7 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
src += GetFPRSize();
if (error.Success()) {
- // Wrote FPU, and SVE overlaps FPU.
- Invalidate(RegisterSetType::FPR, RegisterSetType::SVE_HEADER,
- RegisterSetType::SVE);
-
+ Invalidate(RegisterSetType::FPR);
m_sve_state = SVEState::Unknown;
ConfigureRegisterContext();
}
@@ -1356,9 +1353,7 @@ Status NativeRegisterContextLinux_arm64::WriteFPR() {
ioVec.iov_base = GetFPRBuffer();
ioVec.iov_len = GetFPRSize();
- // SVE Z registers overlap the FP registers.
- Invalidate(RegisterSetType::FPR, RegisterSetType::SVE_HEADER,
- RegisterSetType::SVE);
+ Invalidate(RegisterSetType::FPR);
return WriteRegisterSet(&ioVec, GetFPRSize(), llvm::ELF::NT_FPREGSET);
}
@@ -1427,8 +1422,7 @@ Status NativeRegisterContextLinux_arm64::WriteSVEHeader() {
ioVec.iov_base = GetSVEHeader();
ioVec.iov_len = GetSVEHeaderSize();
- Invalidate(RegisterSetType::FPR, RegisterSetType::SVE_HEADER,
- RegisterSetType::SVE);
+ Invalidate(RegisterSetType::SVE_HEADER);
return WriteRegisterSet(&ioVec, GetSVEHeaderSize(), GetSVERegSet());
}
@@ -1462,8 +1456,7 @@ Status NativeRegisterContextLinux_arm64::WriteAllSVE() {
ioVec.iov_base = GetSVEBuffer();
ioVec.iov_len = GetSVEBufferSize();
- Invalidate(RegisterSetType::FPR, RegisterSetType::SVE_HEADER,
- RegisterSetType::SVE);
+ Invalidate(RegisterSetType::SVE);
return WriteRegisterSet(&ioVec, GetSVEBufferSize(), GetSVERegSet());
}
@@ -1640,9 +1633,7 @@ Status NativeRegisterContextLinux_arm64::WriteZA() {
ioVec.iov_base = GetZABuffer();
ioVec.iov_len = GetZABufferSize();
- Invalidate(RegisterSetType::ZA_HEADER, RegisterSetType::ZA,
- // Writing to ZA may enable ZA, which means ZT0 may change too.
- RegisterSetType::ZT);
+ Invalidate(RegisterSetType::ZA);
return WriteRegisterSet(&ioVec, GetZABufferSize(), llvm::ELF::NT_ARM_ZA);
}
@@ -1675,10 +1666,7 @@ Status NativeRegisterContextLinux_arm64::WriteZT() {
ioVec.iov_base = GetZTBuffer();
ioVec.iov_len = GetZTBufferSize();
- Invalidate(RegisterSetType::ZT,
- // Writing to an inactive ZT0 will enable ZA as well,
- // which invalidates our current copy of it.
- RegisterSetType::ZA_HEADER, RegisterSetType::ZA);
+ Invalidate(RegisterSetType::ZT);
return WriteRegisterSet(&ioVec, GetZTBufferSize(), llvm::ELF::NT_ARM_ZT);
}
@@ -1764,7 +1752,7 @@ void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() {
// only the active mode will return valid register data.
// Check for SME.
- Invalidate(RegisterSetType::SVE_HEADER, RegisterSetType::SVE);
+ Invalidate(RegisterSetType::SVE_HEADER);
m_sve_state = SVEState::Streaming;
Status error = ReadSVEHeader();
@@ -1774,7 +1762,7 @@ void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() {
((m_sve_header.flags & sve::ptrace_regs_mask) == sve::ptrace_regs_sve);
// Check for SVE.
- Invalidate(RegisterSetType::SVE_HEADER, RegisterSetType::SVE);
+ Invalidate(RegisterSetType::SVE_HEADER);
m_sve_state = SVEState::Full;
error = ReadSVEHeader();
@@ -1803,7 +1791,7 @@ void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() {
if (m_sve_state == SVEState::Full || m_sve_state == SVEState::FPSIMD ||
m_sve_state == SVEState::Streaming ||
m_sve_state == SVEState::StreamingFPSIMD) {
- Invalidate(RegisterSetType::SVE_HEADER, RegisterSetType::SVE);
+ Invalidate(RegisterSetType::SVE_HEADER);
error = ReadSVEHeader();
// On every stop we configure SVE vector length by calling
>From 8a405ef0cfb5bab04c8a827a2ebe712e0b319382 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Tue, 28 Jul 2026 11:50:47 +0000
Subject: [PATCH 3/4] missing default
---
.../Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
index 453d1cfbe699d..4d317bd794079 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -84,7 +84,8 @@ NativeRegisterContextLinux_arm64::GetInvalidationMask(
// both ZA and ZT being enabled.
return RegisterSetType::ZA_HEADER | RegisterSetType::ZA |
RegisterSetType::ZT;
- llvm_unreachable("Unhandled register set");
+ default:
+ llvm_unreachable("Unhandled register set");
}
}
>From 2002de5465f214057a2110701e7c781092cbeb11 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Tue, 28 Jul 2026 14:01:19 +0000
Subject: [PATCH 4/4] will be caught by compiler anyway
---
.../Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
index 4d317bd794079..6d732bbfe1315 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -84,8 +84,6 @@ NativeRegisterContextLinux_arm64::GetInvalidationMask(
// both ZA and ZT being enabled.
return RegisterSetType::ZA_HEADER | RegisterSetType::ZA |
RegisterSetType::ZT;
- default:
- llvm_unreachable("Unhandled register set");
}
}
More information about the lldb-commits
mailing list