================
@@ -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 &reg_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

Reply via email to