blob: 19de204c24353ad6d6ec753741833e42bb05df1e [file] [log] [blame]
//===-- VectorType.cpp ----------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "lldb/DataFormatters/VectorType.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h"
#include <optional>
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
static CompilerType GetCompilerTypeForFormat(lldb::Format format,
CompilerType element_type,
TypeSystemSP type_system) {
lldbassert(type_system && "type_system needs to be not NULL");
if (!type_system)
return {};
switch (format) {
case lldb::eFormatAddressInfo:
case lldb::eFormatPointer:
return type_system->GetBuiltinTypeForEncodingAndBitSize(
eEncodingUint, 8 * type_system->GetPointerByteSize());
case lldb::eFormatBoolean:
return type_system->GetBasicTypeFromAST(lldb::eBasicTypeBool);
case lldb::eFormatBytes:
case lldb::eFormatBytesWithASCII:
case lldb::eFormatChar:
case lldb::eFormatCharArray:
case lldb::eFormatCharPrintable:
return type_system->GetBasicTypeFromAST(lldb::eBasicTypeChar);
case lldb::eFormatComplex /* lldb::eFormatComplexFloat */:
return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloatComplex);
case lldb::eFormatCString:
return type_system->GetBasicTypeFromAST(lldb::eBasicTypeChar)
.GetPointerType();
case lldb::eFormatFloat:
return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloat);
case lldb::eFormatHex:
case lldb::eFormatHexUppercase:
case lldb::eFormatOctal:
return type_system->GetBasicTypeFromAST(lldb::eBasicTypeInt);
case lldb::eFormatHexFloat:
return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloat);
case lldb::eFormatUnicode16:
case lldb::eFormatUnicode32:
case lldb::eFormatUnsigned:
return type_system->GetBasicTypeFromAST(lldb::eBasicTypeUnsignedInt);
case lldb::eFormatVectorOfChar:
return type_system->GetBasicTypeFromAST(lldb::eBasicTypeChar);
case lldb::eFormatVectorOfFloat32:
return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingIEEE754,
32);
case lldb::eFormatVectorOfFloat64:
return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingIEEE754,
64);
case lldb::eFormatVectorOfSInt16:
return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 16);
case lldb::eFormatVectorOfSInt32:
return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 32);
case lldb::eFormatVectorOfSInt64:
return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 64);
case lldb::eFormatVectorOfSInt8:
return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 8);
case lldb::eFormatVectorOfUInt128:
return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 128);
case lldb::eFormatVectorOfUInt16:
return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 16);
case lldb::eFormatVectorOfUInt32:
return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
case lldb::eFormatVectorOfUInt64:
return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 64);
case lldb::eFormatVectorOfUInt8:
return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8);
case lldb::eFormatDefault:
return element_type;
case lldb::eFormatBinary:
case lldb::eFormatComplexInteger:
case lldb::eFormatDecimal:
case lldb::eFormatEnum:
case lldb::eFormatInstruction:
case lldb::eFormatOSType:
case lldb::eFormatVoid:
default:
return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8);
}
}
static lldb::Format GetItemFormatForFormat(lldb::Format format,
CompilerType element_type) {
switch (format) {
case lldb::eFormatVectorOfChar:
return lldb::eFormatChar;
case lldb::eFormatVectorOfFloat32:
case lldb::eFormatVectorOfFloat64:
return lldb::eFormatFloat;
case lldb::eFormatVectorOfSInt16:
case lldb::eFormatVectorOfSInt32:
case lldb::eFormatVectorOfSInt64:
case lldb::eFormatVectorOfSInt8:
return lldb::eFormatDecimal;
case lldb::eFormatVectorOfUInt128:
case lldb::eFormatVectorOfUInt16:
case lldb::eFormatVectorOfUInt32:
case lldb::eFormatVectorOfUInt64:
case lldb::eFormatVectorOfUInt8:
return lldb::eFormatUnsigned;
case lldb::eFormatBinary:
case lldb::eFormatComplexInteger:
case lldb::eFormatDecimal:
case lldb::eFormatEnum:
case lldb::eFormatInstruction:
case lldb::eFormatOSType:
case lldb::eFormatVoid:
return eFormatHex;
case lldb::eFormatDefault: {
// special case the (default, char) combination to actually display as an
// integer value most often, you won't want to see the ASCII characters...
// (and if you do, eFormatChar is a keystroke away)
bool is_char = element_type.IsCharType();
bool is_signed = false;
element_type.IsIntegerType(is_signed);
return is_char ? (is_signed ? lldb::eFormatDecimal : eFormatHex) : format;
} break;
default:
return format;
}
}
/// Calculates the number of elements stored in a container (with
/// element type 'container_elem_type') as if it had elements of type
/// 'element_type'.
///
/// For example, a container of type
/// `uint8_t __attribute__((vector_size(16)))` has 16 elements.
/// But calling `CalculateNumChildren` with an 'element_type'
/// of `float` (4-bytes) will return `4` because we are interpreting
/// the byte-array as a `float32[]`.
///
/// \param[in] container_elem_type The type of the elements stored
/// in the container we are calculating the children of.
///
/// \param[in] num_elements Number of 'container_elem_type's our
/// container stores.
///
/// \param[in] element_type The type of elements we interpret
/// container_type to contain for the purposes of calculating
/// the number of children.
///
/// \returns The number of elements stored in a container of
/// type 'element_type'. Returns a std::nullopt if the
/// size of the container is not a multiple of 'element_type'
/// or if an error occurs.
static std::optional<size_t>
CalculateNumChildren(CompilerType container_elem_type, uint64_t num_elements,
CompilerType element_type) {
std::optional<uint64_t> container_elem_size =
container_elem_type.GetByteSize(/* exe_scope */ nullptr);
if (!container_elem_size)
return {};
auto container_size = *container_elem_size * num_elements;
std::optional<uint64_t> element_size =
element_type.GetByteSize(/* exe_scope */ nullptr);
if (!element_size || !*element_size)
return {};
if (container_size % *element_size)
return {};
return container_size / *element_size;
}
namespace lldb_private {
namespace formatters {
class VectorTypeSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
VectorTypeSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp), m_child_type() {}
~VectorTypeSyntheticFrontEnd() override = default;
llvm::Expected<uint32_t> CalculateNumChildren() override {
return m_num_children;
}
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
auto num_children_or_err = CalculateNumChildren();
if (!num_children_or_err)
return ValueObjectConstResult::Create(
nullptr, Status(num_children_or_err.takeError()));
if (idx >= *num_children_or_err)
return {};
std::optional<uint64_t> size = m_child_type.GetByteSize(nullptr);
if (!size)
return {};
auto offset = idx * *size;
StreamString idx_name;
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
ValueObjectSP child_sp(m_backend.GetSyntheticChildAtOffset(
offset, m_child_type, true, ConstString(idx_name.GetString())));
if (!child_sp)
return child_sp;
child_sp->SetFormat(m_item_format);
return child_sp;
}
lldb::ChildCacheState Update() override {
m_parent_format = m_backend.GetFormat();
CompilerType parent_type(m_backend.GetCompilerType());
CompilerType element_type;
uint64_t num_elements;
parent_type.IsVectorType(&element_type, &num_elements);
m_child_type = ::GetCompilerTypeForFormat(
m_parent_format, element_type,
parent_type.GetTypeSystem().GetSharedPointer());
m_num_children =
::CalculateNumChildren(element_type, num_elements, m_child_type)
.value_or(0);
m_item_format = GetItemFormatForFormat(m_parent_format, m_child_type);
return lldb::ChildCacheState::eRefetch;
}
bool MightHaveChildren() override { return true; }
size_t GetIndexOfChildWithName(ConstString name) override {
const char *item_name = name.GetCString();
uint32_t idx = ExtractIndexFromString(item_name);
if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
return UINT32_MAX;
return idx;
}
private:
lldb::Format m_parent_format = eFormatInvalid;
lldb::Format m_item_format = eFormatInvalid;
CompilerType m_child_type;
size_t m_num_children = 0;
};
} // namespace formatters
} // namespace lldb_private
bool lldb_private::formatters::VectorTypeSummaryProvider(
ValueObject &valobj, Stream &s, const TypeSummaryOptions &) {
auto synthetic_children =
VectorTypeSyntheticFrontEndCreator(nullptr, valobj.GetSP());
if (!synthetic_children)
return false;
synthetic_children->Update();
s.PutChar('(');
bool first = true;
size_t idx = 0,
len = synthetic_children->CalculateNumChildrenIgnoringErrors();
for (; idx < len; idx++) {
auto child_sp = synthetic_children->GetChildAtIndex(idx);
if (!child_sp)
continue;
child_sp = child_sp->GetQualifiedRepresentationIfAvailable(
lldb::eDynamicDontRunTarget, true);
const char *child_value = child_sp->GetValueAsCString();
if (child_value && *child_value) {
if (first) {
s.Printf("%s", child_value);
first = false;
} else {
s.Printf(", %s", child_value);
}
}
}
s.PutChar(')');
return true;
}
lldb_private::SyntheticChildrenFrontEnd *
lldb_private::formatters::VectorTypeSyntheticFrontEndCreator(
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
if (!valobj_sp)
return nullptr;
return new VectorTypeSyntheticFrontEnd(valobj_sp);
}