================
@@ -821,27 +842,424 @@
NativeRegisterContextWindows_arm64::WriteHardwareDebugRegs(DREGType hwbType) {
void NativeRegisterContextWindows_arm64::InvalidateAllRegisters() {
m_context = nullptr;
m_context_buffer.reset();
+#if defined(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)
+ m_sve_header = nullptr;
+ m_sve_header_is_valid = false;
+ m_sve_z_buffer.reset();
+ m_sve_z_buffer_is_valid = false;
+
+ // Update SVE registers in case there is any change in the configuration.
+ ConfigureRegisterContext();
+#endif
}
Status NativeRegisterContextWindows_arm64::CacheAllRegisterValues() {
Status error;
DWORD context_flags = CONTEXT_ALL;
+#if defined(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)
+ std::optional<DWORD64> xstate_features_mask = std::nullopt;
+ const bool sve_present = GetRegisterInfo().IsSVEPresent();
+
+ if (sve_present) {
+ context_flags |= CONTEXT_XSTATE;
+ xstate_features_mask = XSTATE_MASK_ARM64_SVE;
+ }
+#endif
+
if (m_context && (m_context->ContextFlags & context_flags) == context_flags)
- return error;
+#if defined(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)
+ {
+ if (!sve_present)
+#endif
+ return error;
+
+#if defined(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)
+ if (m_sve_header_is_valid && m_sve_z_buffer_is_valid)
+ return error;
+ }
+ m_sve_header = nullptr;
+ m_sve_header_is_valid = false;
+ m_sve_z_buffer_is_valid = false;
+#endif
m_context = nullptr;
+ auto cleanup = llvm::make_scope_exit([&]() {
+ if (error.Fail()) {
+ m_context = nullptr;
+#if defined(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)
+ m_sve_header = nullptr;
+ m_sve_header_is_valid = false;
+ m_sve_z_buffer_is_valid = false;
+ if (sve_present)
+ m_sve_state = SVEState::Unknown;
+ else
+ m_sve_state = SVEState::Disabled;
+#endif
+ }
+ });
+
if (!m_context_buffer)
m_context_buffer = std::make_shared<DataBufferHeap>();
error = GetThreadContextHelper(GetThreadHandle(), context_flags, m_context,
- m_context_buffer.get());
+ m_context_buffer.get()
+#if defined(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)
+ ,
+ xstate_features_mask
+#endif
+ );
+ if (error.Fail())
+ return error;
+
+#if defined(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)
+ if (sve_present) {
+ error = ReadSVEHeader();
+ if (error.Fail())
+ return error;
+
+ error = CacheSVEZRegisters();
+ if (error.Fail())
+ return error;
+ } else {
+ m_sve_state = SVEState::Disabled;
+ }
+#endif
+
+ return error;
+}
+
+RegisterInfoPOSIX_arm64 &
+NativeRegisterContextWindows_arm64::GetRegisterInfo() const {
+ return static_cast<RegisterInfoPOSIX_arm64 &>(*m_register_info_interface_up);
+}
+
+#if defined(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)
+bool NativeRegisterContextWindows_arm64::IsSVE(uint32_t reg_index) const {
+ return GetRegisterInfo().IsSVEReg(reg_index);
+}
+
+void NativeRegisterContextWindows_arm64::ConfigureRegisterContext() {
+ // ConfigureRegisterContext gets called from InvalidateAllRegisters
+ // on every stop and configures the SVE vector length.
+
+ Log *log = GetLog(WindowsLog::Registers);
+
+ // If m_sve_state is found to be set to SVEState::Disabled on the first stop,
+ // then ConfigureRegisterContext is deemed non-operational for the lifetime
of
+ // the current process.
+ if (!m_sve_header_is_valid && m_sve_state != SVEState::Disabled) {
+ Status error = CacheAllRegisterValues();
+ if (error.Fail())
+ LLDB_LOG(log, "failed to cache all register values: {0}", error);
+
+ if (!m_sve_header_is_valid)
+ LLDB_LOG(log, "failed to read SVE header: {0}", error);
+
+ if (m_sve_header_is_valid && m_sve_state == SVEState::Full) {
+ uint32_t vq = RegisterInfoPOSIX_arm64::eVectorQuadwordAArch64SVE;
+
+ if (sve::vl_valid(m_sve_header->VectorLength))
+ vq = sve::vq_from_vl(m_sve_header->VectorLength);
+
+ GetRegisterInfo().ConfigureVectorLengthSVE(vq);
+ }
+ }
+}
+
+Status NativeRegisterContextWindows_arm64::ReadSVEHeader() {
+ Log *log = GetLog(WindowsLog::Registers);
+ Status error;
+
+ if (m_sve_header_is_valid)
+ return error;
+
+ if (m_sve_state == SVEState::Disabled) {
+ error = Status::FromErrorString("SVE is either unsupported or disabled");
+ LLDB_LOG(log, "{0}", error);
+ return error;
+ }
+
+ if (!m_context) {
+ error = Status::FromErrorString("register context is not cached");
+ LLDB_LOG(log, "{0}", error);
+ return error;
+ }
+
+ DWORD64 feature_mask = 0;
+ DWORD sve_feature_area_length = 0;
+
+ if (!GetXStateFeaturesMask(m_context, &feature_mask)) {
+ error = Status(GetLastError(), eErrorTypeWin32);
+ LLDB_LOG(log, "GetXStateFeaturesMask failed with error {0}", error);
+ return error;
+ }
+
+ // If the SVE bit is unset, then SVE is in a processor-specific INITIALIZED
+ // state and the contents of the SVE feature area retrieved by
+ // LocateXStateFeature are documented as undefined. We deliberately do not
+ // synthesize values in this case since the values implied by the INITIALIZED
+ // state for SVE aren't documented. Queries pertaining to SVE registers
become
+ // serviceable on the first stop where the SVE feature-mask bit is reported
to
+ // be set.
+ if ((feature_mask & XSTATE_MASK_ARM64_SVE) == 0) {
+ error = Status::FromErrorString(
+ "SVE is in a processor-specific INITIALIZED state and the contents of "
+ "the SVE feature area are undefined");
+ LLDB_LOG(log, "{0}", error);
+ return error;
+ }
+
+ m_sve_header = static_cast<XSAVE_ARM64_SVE_HEADER *>(LocateXStateFeature(
+ m_context, XSTATE_ARM64_SVE, &sve_feature_area_length));
+
+ if (!m_sve_header) {
+ error = Status::FromErrorString("failed to locate SVE feature area");
+ LLDB_LOG(log, "{0}", error);
+ return error;
+ }
+
+ if (sve_feature_area_length < sizeof(XSAVE_ARM64_SVE_HEADER)) {
+ error = Status::FromErrorString("SVE feature area too small");
+ LLDB_LOG(log, "expected at least {0} bytes, got {1}",
+ sizeof(XSAVE_ARM64_SVE_HEADER), sve_feature_area_length);
+ return error;
+ }
+
+ m_sve_header_is_valid = true;
+ m_sve_state = SVEState::Full;
+
+ return error;
+}
+
+Status NativeRegisterContextWindows_arm64::SVERead(const uint32_t reg,
+ RegisterValue ®_value) {
+ Log *log = GetLog(WindowsLog::Registers);
+ Status error = CacheAllRegisterValues();
if (error.Fail())
- m_context = nullptr;
+ return error;
+
+ if (!m_sve_header_is_valid) {
+ error = Status::FromErrorString("SVE header is unavailable");
+ LLDB_LOG(log, "{0}", error);
+ return error;
+ }
+
+ if (GetRegisterInfo().IsSVERegVG(reg)) {
+ reg_value.SetUInt64(GetSVERegVG());
+ return error;
+ }
+
+ if (GetRegisterInfo().IsSVEZReg(reg)) {
+ // For VL == sizeof(ARM64_NT_NEON128), Z[i] has no architectural high bits
+ // beyond V[i]. So, route through FPRRead to avoid touching the SVE feature
+ // area.
+ if (m_sve_header->VectorLength == sizeof(ARM64_NT_NEON128))
+ return FPRRead(reg - GetRegisterInfo().GetRegNumSVEZ0() +
+ k_first_fpr_arm64,
+ reg_value);
+
+ if (!m_sve_z_buffer_is_valid || !m_sve_z_buffer) {
+ error = Status::FromErrorString("SVE Z register cache is unavailable");
+ LLDB_LOG(log, "{0}", error);
+ return error;
+ }
+
+ const uint32_t vl = m_sve_header->VectorLength;
+ const uint32_t offset = (reg - GetRegisterInfo().GetRegNumSVEZ0()) * vl;
+
+ reg_value.SetBytes(m_sve_z_buffer->GetBytes() + offset, vl,
+ endian::InlHostByteOrder());
+ return error;
+ }
+
+ if (GetRegisterInfo().IsSVEPReg(reg) ||
+ reg == GetRegisterInfo().GetRegNumSVEFFR()) {
+ const uint32_t pl = m_sve_header->VectorLength / 8;
+ const uint8_t *src = reinterpret_cast<const uint8_t *>(m_sve_header) +
+ m_sve_header->PredicateRegisterOffset;
+ const uint32_t offset = (reg - GetRegisterInfo().GetRegNumSVEP0()) * pl;
+ reg_value.SetBytes(src + offset, pl, endian::InlHostByteOrder());
+ return error;
+ }
+
+ return Status::FromErrorString("unsupported SVE register");
+}
+
+Status NativeRegisterContextWindows_arm64::CacheSVEZRegisters() {
+ Log *log = GetLog(WindowsLog::Registers);
+
+ Status error;
+
+ if (m_sve_z_buffer_is_valid)
+ return error;
+
+ if (!m_context) {
+ error = Status::FromErrorString("register context is not cached");
+ LLDB_LOG(log, "{0}", error);
+ return error;
+ }
+
+ if (!m_sve_header_is_valid)
+ error = ReadSVEHeader();
+
+ if (error.Fail())
+ return error;
+
+ const uint32_t vl = m_sve_header->VectorLength;
+
+ if (vl < k_z_low_bits_size) {
+ error = Status::FromErrorString("invalid SVE vector length");
+ LLDB_LOG(log, "{0}", error);
+ return error;
+ }
+
+ const uint32_t num_z_regs =
+ GetRegisterInfo().GetRegNumSVEP0() - GetRegisterInfo().GetRegNumSVEZ0();
+
+ if (m_sve_z_buffer)
+ m_sve_z_buffer->SetByteSize(vl * num_z_regs);
+ else
+ m_sve_z_buffer = std::make_shared<DataBufferHeap>(vl * num_z_regs, 0);
+
+ if (!m_sve_z_buffer) {
+ error = Status::FromErrorString("failed to allocate SVE Z buffer");
----------------
efriedma-quic wrote:
std::make_shared can't return null.
https://github.com/llvm/llvm-project/pull/205906
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits