https://github.com/barsolo2000 created 
https://github.com/llvm/llvm-project/pull/220707

This is adding GDB remote vector register support.

- Build exact Clang types from parsed vector metadata.
- Use native Clang vectors where valid and arrays where required to preserve 
exact layouts.
- Support nested, pointer, boolean, and non-power-of-two vectors.
- Expose vector lanes through `SBValue` children and expression paths.
- Handle typed vector data correctly across target byte orders.
- Add builder, SB API, layout, cache, and big-endian tests.

Example:
```
vector = frame.FindRegister("v0")
vector.GetNumChildren()                              # 4
vector.GetChildAtIndex(2).GetValue()                 # "3.5"
vector.GetValueForExpressionPath("[2]").GetValue()   # "3.5"

v = frame.FindRegister("v0")
print([v.GetChildAtIndex(i).GetValue()
       for i in range(v.GetNumChildren())])
# ['1.5', '2.5', '3.5', '4.5']
```
Structured `register read` output is added separately in patch 5.

>From ae964c820ccfd96b48af351a8cf71c086efc9cea Mon Sep 17 00:00:00 2001
From: Bar Soloveychik <[email protected]>
Date: Mon, 24 Aug 2026 12:04:53 -0700
Subject: [PATCH] [lldb][4/5] Expose vector registers through SBValue

---
 lldb/include/lldb/Utility/RegisterValue.h     |   5 +
 lldb/source/Core/Value.cpp                    |  12 +-
 .../RegisterTypeBuilderClang.cpp              |  77 ++++++-
 .../RegisterTypeBuilderClang.h                |   4 +
 lldb/source/Utility/RegisterValue.cpp         |  33 +++
 .../ValueObject/ValueObjectRegister.cpp       |  53 +++--
 .../TestXMLRegisterVector.py                  | 205 +++++++++++++++++-
 .../Target/RegisterTypeBuilderClangTest.cpp   | 116 ++++++++++
 lldb/unittests/Utility/RegisterValueTest.cpp  |  93 ++++++++
 9 files changed, 566 insertions(+), 32 deletions(-)

diff --git a/lldb/include/lldb/Utility/RegisterValue.h 
b/lldb/include/lldb/Utility/RegisterValue.h
index e4a2de35559fa..d53b316fa2c97 100644
--- a/lldb/include/lldb/Utility/RegisterValue.h
+++ b/lldb/include/lldb/Utility/RegisterValue.h
@@ -99,6 +99,11 @@ class RegisterValue {
 
   bool GetData(DataExtractor &data) const;
 
+  /// Copy this value into \p data using \p byte_order and the byte size from
+  /// \p reg_info.
+  bool GetData(DataExtractor &data, const RegisterInfo &reg_info,
+               lldb::ByteOrder byte_order) const;
+
   // Copy the register value from this object into a buffer in "dst" and obey
   // the "dst_byte_order" when copying the data. Also watch out in case
   // "dst_len" is longer or shorter than the register value described by
diff --git a/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp
index f9e65d397f05f..0a7610e62ed4a 100644
--- a/lldb/source/Core/Value.cpp
+++ b/lldb/source/Core/Value.cpp
@@ -492,10 +492,14 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, 
DataExtractor &data,
     address_type = eAddressTypeHost;
     if (exe_ctx) {
       if (Target *target = exe_ctx->GetTargetPtr()) {
-        // Registers are always stored in host endian.
-        data.SetByteOrder(m_context_type == ContextType::RegisterInfo
-                              ? endian::InlHostByteOrder()
-                              : target->GetArchitecture().GetByteOrder());
+        ByteOrder byte_order = target->GetArchitecture().GetByteOrder();
+        // ValueObjectRegister stores typed vectors in target byte order and
+        // all other register buffers in host byte order.
+        if (m_context_type == ContextType::RegisterInfo &&
+            !llvm::isa_and_present<RegisterTypeVector>(
+                GetRegisterInfo()->register_type))
+          byte_order = endian::InlHostByteOrder();
+        data.SetByteOrder(byte_order);
         
data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
         break;
       }
diff --git 
a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp 
b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
index 91f53975e5255..16cf0e0e6284a 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
@@ -12,6 +12,7 @@
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Utility/RegisterType.h"
 #include "lldb/lldb-enumerations.h"
+#include "llvm/ADT/bit.h"
 
 using namespace lldb_private;
 
@@ -141,6 +142,78 @@ CompilerType RegisterTypeBuilderClang::BuildFlagsType(
   return flags_type;
 }
 
+CompilerType
+RegisterTypeBuilderClang::BuildVectorType(const RegisterTypeVector 
*vector_type,
+                                          uint32_t expected_byte_size,
+                                          lldb::TypeSystemClangSP type_system) 
{
+  if (!expected_byte_size)
+    return {};
+  if (auto type = GetExistingCompilerType(vector_type, expected_byte_size))
+    return *type;
+
+  std::optional<uint64_t> element_size =
+      vector_type->GetElementType()->GetByteSize();
+  if (!element_size) {
+    if (expected_byte_size % vector_type->GetCount())
+      return {};
+    element_size = expected_byte_size / vector_type->GetCount();
+  }
+  if (*element_size > UINT32_MAX ||
+      expected_byte_size % vector_type->GetCount() ||
+      *element_size != expected_byte_size / vector_type->GetCount())
+    return {};
+
+  CompilerType element_type;
+  const RegisterType *element_register_type = vector_type->GetElementType();
+  switch (element_register_type->getKind()) {
+  case RegisterType::eRegisterTypeKindBuiltin:
+    element_type =
+        
BuildBuiltinType(llvm::cast<RegisterTypeBuiltin>(element_register_type),
+                         *element_size, type_system);
+    break;
+  case RegisterType::eRegisterTypeKindVector:
+    element_type =
+        BuildVectorType(llvm::cast<RegisterTypeVector>(element_register_type),
+                        *element_size, type_system);
+    break;
+  case RegisterType::eRegisterTypeKindEnum:
+  case RegisterType::eRegisterTypeKindFlags:
+    return {};
+  }
+  if (!element_type.IsValid())
+    return {};
+
+  const auto *builtin_element =
+      llvm::dyn_cast<RegisterTypeBuiltin>(element_register_type);
+  bool pointer_element =
+      builtin_element && (builtin_element->GetID() == "data_ptr" ||
+                          builtin_element->GetID() == "code_ptr");
+  // Clang vectors can pad non-power-of-two element counts. Pointer, boolean
+  // and nested elements also need array layout to match the XML exactly.
+  bool use_vector = builtin_element && !pointer_element &&
+                    builtin_element->GetID() != "bool" &&
+                    llvm::has_single_bit(vector_type->GetCount());
+  CompilerType compiler_type = type_system->CreateArrayType(
+      element_type, vector_type->GetCount(), use_vector);
+
+  auto compiler_size =
+      llvm::expectedToOptional(compiler_type.GetByteSize(nullptr));
+  // Target ABI rules can still pad a Clang vector. Prefer an array when that
+  // gives the exact byte size described by the register XML.
+  if (compiler_size != expected_byte_size) {
+    compiler_type = type_system->CreateArrayType(
+        element_type, vector_type->GetCount(), /*is_vector=*/false);
+    compiler_size =
+        llvm::expectedToOptional(compiler_type.GetByteSize(nullptr));
+  }
+  if (compiler_size != expected_byte_size)
+    return {};
+
+  m_type_cache.try_emplace(
+      std::make_pair(vector_type->GetUID(), expected_byte_size), 
compiler_type);
+  return compiler_type;
+}
+
 CompilerType
 RegisterTypeBuilderClang::GetRegisterType(const RegisterInfo &reg_info) {
   lldb::TypeSystemClangSP type_system =
@@ -173,7 +246,9 @@ RegisterTypeBuilderClang::GetRegisterType(const 
RegisterInfo &reg_info) {
         llvm::dyn_cast<RegisterTypeEnum>(reg_info.register_type),
         reg_info.byte_size, type_system);
   case RegisterType::eRegisterTypeKindVector:
-    return {};
+    return BuildVectorType(
+        llvm::cast<RegisterTypeVector>(reg_info.register_type),
+        reg_info.byte_size, type_system);
   }
 }
 
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h 
b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
index e4734a85269d4..ab069b5642225 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
@@ -45,6 +45,10 @@ class RegisterTypeBuilderClang : public RegisterTypeBuilder {
                               uint32_t register_byte_size,
                               lldb::TypeSystemClangSP type_system);
 
+  CompilerType BuildVectorType(const RegisterTypeVector *vector_type,
+                               uint32_t expected_byte_size,
+                               lldb::TypeSystemClangSP type_system);
+
   Target &m_target;
 
   // A cache of previously created types. We do not cache by element ID because
diff --git a/lldb/source/Utility/RegisterValue.cpp 
b/lldb/source/Utility/RegisterValue.cpp
index 4d762dc80e7f5..4db3ebf0cd44a 100644
--- a/lldb/source/Utility/RegisterValue.cpp
+++ b/lldb/source/Utility/RegisterValue.cpp
@@ -8,6 +8,7 @@
 
 #include "lldb/Utility/RegisterValue.h"
 
+#include "lldb/Utility/DataBufferHeap.h"
 #include "lldb/Utility/DataExtractor.h"
 #include "lldb/Utility/Scalar.h"
 #include "lldb/Utility/Status.h"
@@ -19,7 +20,9 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 
+#include <algorithm>
 #include <cstdint>
+#include <memory>
 #include <string>
 #include <tuple>
 #include <vector>
@@ -35,6 +38,36 @@ bool RegisterValue::GetData(DataExtractor &data) const {
   return data.SetData(GetBytes(), GetByteSize(), GetByteOrder()) > 0;
 }
 
+bool RegisterValue::GetData(DataExtractor &data, const RegisterInfo &reg_info,
+                            lldb::ByteOrder byte_order) const {
+  DataExtractor source;
+  if (!GetData(source) || source.GetByteSize() < reg_info.byte_size)
+    return false;
+
+  const lldb::ByteOrder source_byte_order = source.GetByteOrder();
+  if ((source_byte_order != lldb::eByteOrderBig &&
+       source_byte_order != lldb::eByteOrderLittle) ||
+      (byte_order != lldb::eByteOrderBig &&
+       byte_order != lldb::eByteOrderLittle))
+    return false;
+
+  auto buffer_sp = std::make_shared<DataBufferHeap>(reg_info.byte_size, 0);
+  size_t source_offset = source_byte_order == lldb::eByteOrderBig
+                             ? source.GetByteSize() - reg_info.byte_size
+                             : 0;
+  const uint8_t *source_bytes = source.GetDataStart() + source_offset;
+  uint8_t *destination_bytes = buffer_sp->GetBytes();
+  if (source_byte_order == byte_order)
+    std::copy_n(source_bytes, reg_info.byte_size, destination_bytes);
+  else
+    std::reverse_copy(source_bytes, source_bytes + reg_info.byte_size,
+                      destination_bytes);
+
+  data.Clear();
+  data.SetByteOrder(byte_order);
+  return data.SetData(buffer_sp) == reg_info.byte_size;
+}
+
 uint32_t RegisterValue::GetAsMemoryData(const RegisterInfo &reg_info, void 
*dst,
                                         uint32_t dst_len,
                                         lldb::ByteOrder dst_byte_order,
diff --git a/lldb/source/ValueObject/ValueObjectRegister.cpp 
b/lldb/source/ValueObject/ValueObjectRegister.cpp
index 4ddf1dfee64b0..cba86ed5c252b 100644
--- a/lldb/source/ValueObject/ValueObjectRegister.cpp
+++ b/lldb/source/ValueObject/ValueObjectRegister.cpp
@@ -20,6 +20,7 @@
 #include "lldb/Utility/DataExtractor.h"
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterType.h"
 #include "lldb/Utility/Scalar.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/Stream.h"
@@ -207,27 +208,38 @@ 
ValueObjectRegister::ValueObjectRegister(ExecutionContextScope *exe_scope,
 ValueObjectRegister::~ValueObjectRegister() = default;
 
 CompilerType ValueObjectRegister::GetCompilerTypeImpl() {
-  if (!m_compiler_type.IsValid()) {
-    ExecutionContext exe_ctx(GetExecutionContextRef());
-    if (auto *target = exe_ctx.GetTargetPtr()) {
-      if (auto *exe_module = target->GetExecutableModulePointer()) {
-        auto type_system_or_err =
-            exe_module->GetTypeSystemForLanguage(eLanguageTypeC);
-        if (auto err = type_system_or_err.takeError()) {
-          LLDB_LOG_ERROR(GetLog(LLDBLog::Types), std::move(err),
-                         "Unable to get CompilerType from TypeSystem: {0}");
-        } else {
-          if (auto ts = *type_system_or_err)
-            m_compiler_type = ts->GetBuiltinTypeForEncodingAndBitSize(
-                m_reg_info.encoding, m_reg_info.byte_size * 8);
-        }
-      }
+  ExecutionContext exe_ctx(GetExecutionContextRef());
+  Target *target = exe_ctx.GetTargetPtr();
+  if (target && llvm::isa_and_present<RegisterTypeBuiltin, RegisterTypeVector>(
+                    m_reg_info.register_type)) {
+    CompilerType register_type = target->GetRegisterType(m_reg_info);
+    if (register_type.IsValid())
+      return register_type;
+  }
+
+  if (!m_compiler_type.IsValid() && target) {
+    auto *exe_module = target->GetExecutableModulePointer();
+    if (!exe_module)
+      return m_compiler_type;
+    auto type_system_or_err =
+        exe_module->GetTypeSystemForLanguage(eLanguageTypeC);
+    if (auto err = type_system_or_err.takeError()) {
+      LLDB_LOG_ERROR(GetLog(LLDBLog::Types), std::move(err),
+                     "Unable to get CompilerType from TypeSystem: {0}");
+    } else {
+      if (auto ts = *type_system_or_err)
+        m_compiler_type = ts->GetBuiltinTypeForEncodingAndBitSize(
+            m_reg_info.encoding, m_reg_info.byte_size * 8);
     }
   }
   return m_compiler_type;
 }
 
 ConstString ValueObjectRegister::GetTypeName() {
+  if (llvm::isa_and_present<RegisterTypeBuiltin, RegisterTypeVector>(
+          m_reg_info.register_type))
+    return GetCompilerType().GetTypeName();
+
   if (m_type_name.IsEmpty())
     m_type_name = GetCompilerType().GetTypeName();
   return m_type_name;
@@ -258,7 +270,16 @@ bool ValueObjectRegister::UpdateValue() {
   if (m_reg_ctx_sp) {
     RegisterValue m_old_reg_value(m_reg_value);
     if (m_reg_ctx_sp->ReadRegister(&m_reg_info, m_reg_value)) {
-      if (m_reg_value.GetData(m_data)) {
+      Target *target = exe_ctx.GetTargetPtr();
+      const bool has_vector_type =
+          llvm::isa_and_present<RegisterTypeVector>(m_reg_info.register_type);
+      // CompilerType children interpret bytes using the target's layout.
+      const bool got_data =
+          has_vector_type && target
+              ? m_reg_value.GetData(m_data, m_reg_info,
+                                    target->GetArchitecture().GetByteOrder())
+              : m_reg_value.GetData(m_data);
+      if (got_data) {
         Process *process = exe_ctx.GetProcessPtr();
         if (process)
           m_data.SetAddressByteSize(process->GetAddressByteSize());
diff --git 
a/lldb/test/API/functionalities/gdb_remote_client/TestXMLRegisterVector.py 
b/lldb/test/API/functionalities/gdb_remote_client/TestXMLRegisterVector.py
index 6802e78c8ff74..4f99992d5cc59 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/TestXMLRegisterVector.py
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestXMLRegisterVector.py
@@ -1,4 +1,4 @@
-"""Test vector metadata from GDB remote target description XML."""
+"""Test vectors from GDB remote target description XML."""
 
 from textwrap import dedent
 
@@ -43,24 +43,39 @@ def setup_multidoc_test(self, docs, register_data):
         lldbutil.expect_state_changes(
             self, self.dbg.GetListener(), process, [lldb.eStateStopped]
         )
+        return process
 
-    def setup_register_test(self, definitions, register_data):
-        self.setup_multidoc_test(
+    def setup_register_test(
+        self, definitions, register_data, architecture="aarch64"
+    ):
+        return self.setup_multidoc_test(
             {
                 "target.xml": dedent(
                     """\
                 <?xml version="1.0"?>
                 <target version="1.0">
-                  <architecture>aarch64</architecture>
+                  <architecture>{}</architecture>
                   <feature name="test.register.vectors">
                     {}
                   </feature>
                 </target>"""
-                ).format(definitions)
+                ).format(architecture, definitions)
             },
             register_data,
         )
 
+    def assert_float_children(self, value, expected):
+        self.assertTrue(value.IsValid())
+        self.assertTrue(value.MightHaveChildren())
+        self.assertEqual(value.GetNumChildren(), len(expected))
+        for index, expected_value in enumerate(expected):
+            child = value.GetChildAtIndex(index)
+            self.assertTrue(child.IsValid())
+            self.assertEqual(child.GetName(), "[{}]".format(index))
+            self.assertEqual(child.GetTypeName(), "float")
+            self.assertAlmostEqual(child.GetData().float[0], expected_value)
+            self.assertAlmostEqual(float(child.GetValue()), expected_value)
+
     def assert_vector_info(self, name, byte_size, count):
         self.expect(
             "register info {}".format(name),
@@ -167,36 +182,54 @@ def test_invalid_vectors_are_ignored(self):
     @skipIfXmlSupportMissing
     @skipIfRemote
     def test_duplicate_vector_id_uses_first_definition(self):
-        self.setup_register_test(
+        process = self.setup_register_test(
             """\
             <vector id="shared" type="ieee_single" count="2"/>
             <vector id="shared" type="uint16" count="4"/>
             <reg name="v0" regnum="0" bitsize="64" type="shared"/>
             <reg name="pc" bitsize="64"/>""",
-            "00" * 16,
+            "0000c03f00002040" + "00" * 8,
         )
 
         self.assert_vector_info("v0", 8, 2)
         self.expect("register info v0", matching=False, substrs=["Vector 
elements: 4"])
+        vector = (
+            process.GetThreadAtIndex(0).GetFrameAtIndex(0).FindRegister("v0")
+        )
+        self.assert_float_children(vector, [1.5, 2.5])
 
     @skipIfXmlSupportMissing
     @skipIfRemote
     def test_target_type_precedes_builtin_type(self):
-        self.setup_register_test(
+        process = self.setup_register_test(
             """\
             <vector id="ieee_single" type="uint8" count="2"/>
             <vector id="nested" type="ieee_single" count="3"/>
             <reg name="v0" regnum="0" bitsize="48" type="nested"/>
             <reg name="pc" bitsize="64"/>""",
-            "00" * 14,
+            "010203040506" + "00" * 8,
         )
 
         self.assert_vector_info("v0", 6, 3)
+        vector = (
+            process.GetThreadAtIndex(0).GetFrameAtIndex(0).FindRegister("v0")
+        )
+        self.assertEqual(vector.GetNumChildren(), 3)
+        self.assertEqual(
+            [
+                vector.GetChildAtIndex(outer)
+                .GetChildAtIndex(inner)
+                .GetValueAsUnsigned()
+                for outer in range(3)
+                for inner in range(2)
+            ],
+            [1, 2, 3, 4, 5, 6],
+        )
 
     @skipIfXmlSupportMissing
     @skipIfRemote
     def test_vector_ids_are_scoped_to_included_feature(self):
-        self.setup_multidoc_test(
+        process = self.setup_multidoc_test(
             {
                 "target.xml": dedent(
                     """\
@@ -233,9 +266,159 @@ def test_vector_ids_are_scoped_to_included_feature(self):
                 </feature>"""
                 ),
             },
-            "00" * 40,
+            "0000c03f00002040"
+            "0000c03f000020400000604000009040"
+            + "00" * 16,
         )
 
         self.assert_vector_info("first", 8, 2)
         self.assert_vector_info("second", 16, 4)
         self.assert_no_vector_info("unresolved")
+
+        frame = process.GetThreadAtIndex(0).GetFrameAtIndex(0)
+        self.assert_float_children(frame.FindRegister("first"), [1.5, 2.5])
+        self.assert_float_children(
+            frame.FindRegister("second"), [1.5, 2.5, 3.5, 4.5]
+        )
+
+    @skipIfXmlSupportMissing
+    @skipIfRemote
+    def test_direct_vector_sb_api(self):
+        process = self.setup_register_test(
+            """\
+            <vector id="v4f" type="ieee_single" count="4"/>
+            <reg name="v0" regnum="0" bitsize="128" type="v4f"/>
+            <reg name="pc" bitsize="64"/>""",
+            "0000c03f000020400000604000009040" + "00" * 8,
+        )
+
+        frame = process.GetThreadAtIndex(0).GetFrameAtIndex(0)
+        vector = frame.FindRegister("v0")
+        self.assertEqual(vector.GetName(), "v0")
+        self.assertEqual(vector.GetByteSize(), 16)
+        self.assertTrue(vector.GetType().IsValid())
+        self.assertEqual(vector.GetType().GetByteSize(), 16)
+        self.assertIn("float", vector.GetTypeName())
+        self.assert_float_children(vector, [1.5, 2.5, 3.5, 4.5])
+
+        lane = vector.GetValueForExpressionPath("[2]")
+        self.assertTrue(lane.IsValid())
+        self.assertAlmostEqual(lane.GetData().float[0], 3.5)
+
+    @skipIfXmlSupportMissing
+    @skipIfRemote
+    def test_byte_vector_sb_api(self):
+        process = self.setup_register_test(
+            """\
+            <vector id="bytes32" type="uint8" count="32"/>
+            <reg name="bytes" regnum="0" bitsize="256" type="bytes32"/>
+            <reg name="pc" bitsize="64"/>""",
+            "".join("{:02x}".format(value) for value in range(32)) + "00" * 8,
+        )
+
+        frame = process.GetThreadAtIndex(0).GetFrameAtIndex(0)
+        vector = frame.FindRegister("bytes")
+        self.assertEqual(vector.GetByteSize(), 32)
+        self.assertEqual(vector.GetNumChildren(), 32)
+        self.assertEqual(vector.GetData().uint8s, list(range(32)))
+
+        lane = vector.GetValueForExpressionPath("[16]")
+        self.assertTrue(lane.IsValid())
+        error = lldb.SBError()
+        self.assertEqual(lane.GetValueAsUnsigned(error, 0xDEADBEEF), 0x10)
+        self.assertTrue(error.Success())
+
+    @skipIfXmlSupportMissing
+    @skipIfRemote
+    def test_non_power_of_two_vector_exact_layout(self):
+        process = self.setup_register_test(
+            """\
+            <vector id="v3f" type="ieee_single" count="3"/>
+            <reg name="v0" regnum="0" bitsize="96" type="v3f"/>
+            <reg name="pc" bitsize="64"/>""",
+            "0000c03f0000204000006040" + "00" * 8,
+        )
+
+        vector = (
+            process.GetThreadAtIndex(0).GetFrameAtIndex(0).FindRegister("v0")
+        )
+        self.assertEqual(vector.GetByteSize(), 12)
+        self.assertEqual(vector.GetTypeName(), "float[3]")
+        self.assert_float_children(vector, [1.5, 2.5, 3.5])
+
+    @skipIfXmlSupportMissing
+    @skipIfRemote
+    def test_nested_vector_sb_api(self):
+        process = self.setup_register_test(
+            """\
+            <vector id="v2f" type="ieee_single" count="2"/>
+            <vector id="v2v2f" type="v2f" count="2"/>
+            <reg name="v0" regnum="0" bitsize="128" type="v2v2f"/>
+            <reg name="pc" bitsize="64"/>""",
+            "0000c03f000020400000604000009040" + "00" * 8,
+        )
+
+        vector = (
+            process.GetThreadAtIndex(0).GetFrameAtIndex(0).FindRegister("v0")
+        )
+        self.assertEqual(vector.GetNumChildren(), 2)
+        self.assert_float_children(vector.GetChildAtIndex(0), [1.5, 2.5])
+        self.assert_float_children(vector.GetChildAtIndex(1), [3.5, 4.5])
+
+        lane = vector.GetValueForExpressionPath("[1][0]")
+        self.assertTrue(lane.IsValid())
+        self.assertAlmostEqual(lane.GetData().float[0], 3.5)
+
+    @skipIfXmlSupportMissing
+    @skipIfRemote
+    def test_bool_and_single_uint128_vectors(self):
+        process = self.setup_register_test(
+            """\
+            <vector id="v4b" type="bool" count="4"/>
+            <vector id="v1u128" type="uint128" count="1"/>
+            <reg name="bools" regnum="0" bitsize="32" type="v4b"/>
+            <reg name="wide" regnum="1" bitsize="128" type="v1u128"/>
+            <reg name="pc" bitsize="64"/>""",
+            "00010100" + "01" + "00" * 15 + "00" * 8,
+        )
+
+        frame = process.GetThreadAtIndex(0).GetFrameAtIndex(0)
+        bools = frame.FindRegister("bools")
+        self.assertEqual(bools.GetTypeName(), "bool[4]")
+        self.assertEqual(bools.GetNumChildren(), 4)
+        self.assertEqual(
+            [bools.GetChildAtIndex(i).GetValueAsUnsigned() for i in range(4)],
+            [0, 1, 1, 0],
+        )
+
+        wide = frame.FindRegister("wide")
+        self.assertEqual(wide.GetNumChildren(), 1)
+        wide_child = wide.GetChildAtIndex(0)
+        expected_bytes = [1] + [0] * 15
+        self.assertEqual(wide.GetData().uint8s, expected_bytes)
+        self.assertEqual(wide_child.GetData().uint8s, expected_bytes)
+        self.assertEqual(wide_child.GetValue(), "1")
+
+    @skipIfXmlSupportMissing
+    @skipIfRemote
+    @skipIfLLVMTargetMissing("SystemZ")
+    def test_big_endian_vector_sb_api(self):
+        process = self.setup_register_test(
+            """\
+            <vector id="v2f" type="ieee_single" count="2"/>
+            <reg name="v0" regnum="0" bitsize="64" type="v2f"/>
+            <reg name="v1" regnum="1" bitsize="64" type="v2f"
+                 encoding="uint"/>
+            <reg name="pswa" regnum="2" bitsize="64"/>""",
+            "3fc0000040200000" * 2 + "00" * 8,
+            architecture="s390x",
+        )
+
+        frame = process.GetThreadAtIndex(0).GetFrameAtIndex(0)
+        ull = process.GetTarget().GetBasicType(lldb.eBasicTypeUnsignedLongLong)
+        for name in ["v0", "v1"]:
+            vector = frame.FindRegister(name)
+            self.assert_float_children(vector, [1.5, 2.5])
+            self.assertEqual(
+                vector.Cast(ull).GetValueAsUnsigned(), 0x3FC0000040200000
+            )
diff --git a/lldb/unittests/Target/RegisterTypeBuilderClangTest.cpp 
b/lldb/unittests/Target/RegisterTypeBuilderClangTest.cpp
index 33c014e92fc02..d9eed260d6487 100644
--- a/lldb/unittests/Target/RegisterTypeBuilderClangTest.cpp
+++ b/lldb/unittests/Target/RegisterTypeBuilderClangTest.cpp
@@ -225,4 +225,120 @@ TEST_F(RegisterTypeBuilderClangTest, RejectsSizeMismatch) 
{
   EXPECT_FALSE(builder.GetRegisterType(MakeRegisterInfo(pointer, 4)));
 }
 
+TEST_F(RegisterTypeBuilderClangTest, BuildsPowerOfTwoVector) {
+  Target &target = m_debugger_sp->GetDummyTarget();
+  RegisterTypeBuiltin element_type("ieee_single", eEncodingIEEE754,
+                                   eFormatFloat, 4);
+  RegisterTypeVector vector_type("v4f", &element_type, 4);
+  RegisterTypeBuilderClang builder(target);
+
+  CompilerType type =
+      builder.GetRegisterType(MakeRegisterInfo(vector_type, 16));
+
+  ASSERT_TRUE(type);
+  EXPECT_EQ(llvm::expectedToOptional(type.GetByteSize(nullptr)), 16u);
+  EXPECT_NE(type.GetTypeInfo() & eTypeIsVector, 0u);
+  EXPECT_EQ(llvm::expectedToOptional(type.GetNumChildren(true, nullptr)), 4u);
+}
+
+TEST_F(RegisterTypeBuilderClangTest, PreservesThreeLaneVectorLayout) {
+  Target &target = m_debugger_sp->GetDummyTarget();
+  RegisterTypeBuiltin element_type("ieee_single", eEncodingIEEE754,
+                                   eFormatFloat, 4);
+  RegisterTypeVector vector_type("v3f", &element_type, 3);
+  RegisterTypeBuilderClang builder(target);
+
+  CompilerType type =
+      builder.GetRegisterType(MakeRegisterInfo(vector_type, 12));
+
+  ASSERT_TRUE(type);
+  EXPECT_EQ(llvm::expectedToOptional(type.GetByteSize(nullptr)), 12u);
+  EXPECT_NE(type.GetTypeInfo() & eTypeIsArray, 0u);
+  EXPECT_EQ(type.GetTypeInfo() & eTypeIsVector, 0u);
+  EXPECT_EQ(llvm::expectedToOptional(type.GetNumChildren(true, nullptr)), 3u);
+}
+
+TEST_F(RegisterTypeBuilderClangTest, BuildsNestedVectors) {
+  Target &target = m_debugger_sp->GetDummyTarget();
+  RegisterTypeBuiltin element_type("ieee_single", eEncodingIEEE754,
+                                   eFormatFloat, 4);
+  RegisterTypeVector inner_type("v2f", &element_type, 2);
+  RegisterTypeVector outer_type("v2v2f", &inner_type, 2);
+  RegisterTypeBuilderClang builder(target);
+
+  CompilerType type = builder.GetRegisterType(MakeRegisterInfo(outer_type, 
16));
+
+  ASSERT_TRUE(type);
+  EXPECT_EQ(llvm::expectedToOptional(type.GetByteSize(nullptr)), 16u);
+  EXPECT_NE(type.GetTypeInfo() & eTypeIsArray, 0u);
+  EXPECT_EQ(llvm::expectedToOptional(type.GetNumChildren(true, nullptr)), 2u);
+
+  CompilerType inner = type.GetArrayElementType(nullptr);
+  ASSERT_TRUE(inner);
+  EXPECT_NE(inner.GetTypeInfo() & eTypeIsVector, 0u);
+  EXPECT_EQ(llvm::expectedToOptional(inner.GetNumChildren(true, nullptr)), 2u);
+}
+
+TEST_F(RegisterTypeBuilderClangTest, BuildsTargetSizedPointerVector) {
+  Target &target = m_debugger_sp->GetDummyTarget();
+  RegisterTypeBuiltin pointer_type("data_ptr", eEncodingUint,
+                                   eFormatAddressInfo, std::nullopt);
+  RegisterTypeVector vector_type("v2p", &pointer_type, 2);
+  RegisterTypeBuilderClang builder(target);
+
+  CompilerType type =
+      builder.GetRegisterType(MakeRegisterInfo(vector_type, 16));
+
+  ASSERT_TRUE(type);
+  EXPECT_EQ(llvm::expectedToOptional(type.GetByteSize(nullptr)), 16u);
+  EXPECT_NE(type.GetTypeInfo() & eTypeIsArray, 0u);
+  EXPECT_EQ(llvm::expectedToOptional(type.GetNumChildren(true, nullptr)), 2u);
+}
+
+TEST_F(RegisterTypeBuilderClangTest, BuildsBoolVectorAsArray) {
+  Target &target = m_debugger_sp->GetDummyTarget();
+  RegisterTypeBuiltin element_type("bool", eEncodingUint, eFormatBoolean, 1);
+  RegisterTypeVector vector_type("v4b", &element_type, 4);
+  RegisterTypeBuilderClang builder(target);
+
+  CompilerType type = builder.GetRegisterType(MakeRegisterInfo(vector_type, 
4));
+
+  ASSERT_TRUE(type);
+  EXPECT_EQ(llvm::expectedToOptional(type.GetByteSize(nullptr)), 4u);
+  EXPECT_NE(type.GetTypeInfo() & eTypeIsArray, 0u);
+  EXPECT_EQ(type.GetTypeInfo() & eTypeIsVector, 0u);
+  EXPECT_EQ(llvm::expectedToOptional(type.GetNumChildren(true, nullptr)), 4u);
+}
+
+TEST_F(RegisterTypeBuilderClangTest, BuildsSingleUint128Vector) {
+  Target &target = m_debugger_sp->GetDummyTarget();
+  RegisterTypeBuiltin element_type("uint128", eEncodingUint, eFormatHex, 16);
+  RegisterTypeVector vector_type("v1u128", &element_type, 1);
+  RegisterTypeBuilderClang builder(target);
+
+  CompilerType type =
+      builder.GetRegisterType(MakeRegisterInfo(vector_type, 16));
+
+  ASSERT_TRUE(type);
+  EXPECT_EQ(llvm::expectedToOptional(type.GetByteSize(nullptr)), 16u);
+  EXPECT_NE(type.GetTypeInfo() & eTypeIsVector, 0u);
+  EXPECT_EQ(llvm::expectedToOptional(type.GetNumChildren(true, nullptr)), 1u);
+}
+
+TEST_F(RegisterTypeBuilderClangTest, RejectsVectorSizeMismatch) {
+  Target &target = m_debugger_sp->GetDummyTarget();
+  RegisterTypeBuiltin float_type("ieee_single", eEncodingIEEE754, eFormatFloat,
+                                 4);
+  RegisterTypeVector float_vector("v4f", &float_type, 4);
+  RegisterTypeBuiltin pointer_type("data_ptr", eEncodingUint,
+                                   eFormatAddressInfo, std::nullopt);
+  RegisterTypeVector pointer_vector("v2p", &pointer_type, 2);
+  RegisterTypeBuilderClang builder(target);
+
+  EXPECT_FALSE(builder.GetRegisterType(MakeRegisterInfo(float_vector, 12)));
+  EXPECT_FALSE(builder.GetRegisterType(MakeRegisterInfo(float_vector, 20)));
+  EXPECT_FALSE(builder.GetRegisterType(MakeRegisterInfo(pointer_vector, 0)));
+  EXPECT_FALSE(builder.GetRegisterType(MakeRegisterInfo(pointer_vector, 15)));
+}
+
 } // namespace
diff --git a/lldb/unittests/Utility/RegisterValueTest.cpp 
b/lldb/unittests/Utility/RegisterValueTest.cpp
index 7b27e841cbec5..33fc4dabecea4 100644
--- a/lldb/unittests/Utility/RegisterValueTest.cpp
+++ b/lldb/unittests/Utility/RegisterValueTest.cpp
@@ -57,6 +57,99 @@ TEST(RegisterValueTest, GetScalarValue) {
                    APInt(128, 0x7766554433221100)));
 }
 
+TEST(RegisterValueTest, GetDataInTargetByteOrder) {
+  uint8_t big_endian_bytes[] = {0x01, 0x02, 0x03};
+  RegisterInfo reg_info{"test",
+                        nullptr,
+                        sizeof(big_endian_bytes),
+                        0,
+                        lldb::eEncodingUint,
+                        lldb::eFormatHex,
+                        {0, 0, 0, LLDB_INVALID_REGNUM, 0},
+                        nullptr,
+                        nullptr,
+                        nullptr};
+  DataExtractor source(big_endian_bytes, sizeof(big_endian_bytes),
+                       lldb::eByteOrderBig, 8);
+  RegisterValue value;
+  ASSERT_TRUE(value.SetValueFromData(reg_info, source, 0, false).Success());
+
+  DataExtractor target_data;
+  ASSERT_TRUE(value.GetData(target_data, reg_info, lldb::eByteOrderBig));
+  EXPECT_EQ(target_data.GetByteOrder(), lldb::eByteOrderBig);
+  EXPECT_EQ(
+      llvm::ArrayRef(target_data.GetDataStart(), target_data.GetByteSize()),
+      llvm::ArrayRef(big_endian_bytes));
+
+  ASSERT_TRUE(value.GetData(target_data, reg_info, lldb::eByteOrderLittle));
+  EXPECT_EQ(target_data.GetByteOrder(), lldb::eByteOrderLittle);
+  uint8_t little_endian_bytes[] = {0x03, 0x02, 0x01};
+  EXPECT_EQ(
+      llvm::ArrayRef(target_data.GetDataStart(), target_data.GetByteSize()),
+      llvm::ArrayRef(little_endian_bytes));
+
+  uint8_t padded_big_endian_bytes[] = {0x00, 0x01, 0x02, 0x03};
+  RegisterValue padded_value(llvm::ArrayRef(padded_big_endian_bytes),
+                             lldb::eByteOrderBig);
+  ASSERT_TRUE(padded_value.GetData(target_data, reg_info, 
lldb::eByteOrderBig));
+  EXPECT_EQ(
+      llvm::ArrayRef(target_data.GetDataStart(), target_data.GetByteSize()),
+      llvm::ArrayRef(big_endian_bytes));
+}
+
+TEST(RegisterValueTest, GetDataRejectsUnsupportedByteOrder) {
+  uint8_t bytes[] = {0x01, 0x02, 0x03};
+  RegisterInfo reg_info{"test",
+                        nullptr,
+                        sizeof(bytes),
+                        0,
+                        lldb::eEncodingUint,
+                        lldb::eFormatHex,
+                        {0, 0, 0, LLDB_INVALID_REGNUM, 0},
+                        nullptr,
+                        nullptr,
+                        nullptr};
+  DataExtractor data;
+
+  RegisterValue invalid_source(llvm::ArrayRef(bytes), lldb::eByteOrderInvalid);
+  EXPECT_FALSE(invalid_source.GetData(data, reg_info, lldb::eByteOrderLittle));
+
+  RegisterValue pdp_source(llvm::ArrayRef(bytes), lldb::eByteOrderPDP);
+  EXPECT_FALSE(pdp_source.GetData(data, reg_info, lldb::eByteOrderLittle));
+
+  RegisterValue little_source(llvm::ArrayRef(bytes), lldb::eByteOrderLittle);
+  EXPECT_FALSE(little_source.GetData(data, reg_info, lldb::eByteOrderInvalid));
+  EXPECT_FALSE(little_source.GetData(data, reg_info, lldb::eByteOrderPDP));
+}
+
+TEST(RegisterValueTest, GetScalarDataInTargetByteOrder) {
+  RegisterInfo reg_info{"test",
+                        nullptr,
+                        8,
+                        0,
+                        lldb::eEncodingUint,
+                        lldb::eFormatHex,
+                        {0, 0, 0, LLDB_INVALID_REGNUM, 0},
+                        nullptr,
+                        nullptr,
+                        nullptr};
+  RegisterValue value(uint64_t{0x0102030405060708});
+  DataExtractor target_data;
+
+  uint8_t big_endian_bytes[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
0x08};
+  ASSERT_TRUE(value.GetData(target_data, reg_info, lldb::eByteOrderBig));
+  EXPECT_EQ(
+      llvm::ArrayRef(target_data.GetDataStart(), target_data.GetByteSize()),
+      llvm::ArrayRef(big_endian_bytes));
+
+  uint8_t little_endian_bytes[] = {0x08, 0x07, 0x06, 0x05,
+                                   0x04, 0x03, 0x02, 0x01};
+  ASSERT_TRUE(value.GetData(target_data, reg_info, lldb::eByteOrderLittle));
+  EXPECT_EQ(
+      llvm::ArrayRef(target_data.GetDataStart(), target_data.GetByteSize()),
+      llvm::ArrayRef(little_endian_bytes));
+}
+
 void TestSetValueFromData(const Scalar &etalon, void *src, size_t 
src_byte_size,
                           const lldb::ByteOrder endianness,
                           const RegisterValue::Type register_value_type) {

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to