[lldb] Add support for displaying __float128 variables (#98369)

This commit is contained in:
beetrees 2025-08-01 02:04:48 +01:00 committed by GitHub
parent 03bb10bea6
commit e15b3ef704
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 70 additions and 14 deletions

View File

@ -594,6 +594,7 @@ def is_numeric_type(basic_type):
if basic_type == eBasicTypeFloat: return (True,True) if basic_type == eBasicTypeFloat: return (True,True)
if basic_type == eBasicTypeDouble: return (True,True) if basic_type == eBasicTypeDouble: return (True,True)
if basic_type == eBasicTypeLongDouble: return (True,True) if basic_type == eBasicTypeLongDouble: return (True,True)
if basic_type == eBasicTypeFloat128: return (True,True)
if basic_type == eBasicTypeFloatComplex: return (True,True) if basic_type == eBasicTypeFloatComplex: return (True,True)
if basic_type == eBasicTypeDoubleComplex: return (True,True) if basic_type == eBasicTypeDoubleComplex: return (True,True)
if basic_type == eBasicTypeLongDoubleComplex: return (True,True) if basic_type == eBasicTypeLongDoubleComplex: return (True,True)

View File

@ -321,6 +321,7 @@ Format
.. py:data:: eFormatInstruction .. py:data:: eFormatInstruction
.. py:data:: eFormatVoid .. py:data:: eFormatVoid
.. py:data:: eFormatUnicode8 .. py:data:: eFormatUnicode8
.. py:data:: eFormatFloat128
.. _DescriptionLevel: .. _DescriptionLevel:
@ -1045,6 +1046,7 @@ BasicType
.. py:data:: eBasicTypeObjCSel .. py:data:: eBasicTypeObjCSel
.. py:data:: eBasicTypeNullPtr .. py:data:: eBasicTypeNullPtr
.. py:data:: eBasicTypeOther .. py:data:: eBasicTypeOther
.. py:data:: eBasicTypeFloat128
.. _TraceType: .. _TraceType:

View File

@ -310,7 +310,8 @@ public:
// Exploring the type // Exploring the type
virtual const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size) = 0; virtual const llvm::fltSemantics &
GetFloatTypeSemantics(size_t byte_size, lldb::Format format) = 0;
virtual llvm::Expected<uint64_t> virtual llvm::Expected<uint64_t>
GetBitSize(lldb::opaque_compiler_type_t type, GetBitSize(lldb::opaque_compiler_type_t type,

View File

@ -198,11 +198,15 @@ enum Format {
///< character arrays that can contain non printable ///< character arrays that can contain non printable
///< characters ///< characters
eFormatAddressInfo, ///< Describe what an address points to (func + offset eFormatAddressInfo, ///< Describe what an address points to (func + offset
///< with file/line, symbol + offset, data, etc) ///< with file/line, symbol + offset, data, etc)
eFormatHexFloat, ///< ISO C99 hex float string eFormatHexFloat, ///< ISO C99 hex float string
eFormatInstruction, ///< Disassemble an opcode eFormatInstruction, ///< Disassemble an opcode
eFormatVoid, ///< Do not print this eFormatVoid, ///< Do not print this
eFormatUnicode8, eFormatUnicode8,
eFormatFloat128, ///< Disambiguate between 128-bit `long double` (which uses
///< `eFormatFloat`) and `__float128` (which uses
///< `eFormatFloat128`). If the value being formatted is not
///< 128 bits, then this is identical to `eFormatFloat`.
kNumFormats kNumFormats
}; };
@ -838,7 +842,8 @@ enum BasicType {
eBasicTypeObjCClass, eBasicTypeObjCClass,
eBasicTypeObjCSel, eBasicTypeObjCSel,
eBasicTypeNullPtr, eBasicTypeNullPtr,
eBasicTypeOther eBasicTypeOther,
eBasicTypeFloat128
}; };
/// Deprecated /// Deprecated

View File

@ -156,6 +156,7 @@ public:
case eFormatBinary: case eFormatBinary:
case eFormatFloat: case eFormatFloat:
case eFormatFloat128:
case eFormatOctal: case eFormatOctal:
case eFormatDecimal: case eFormatDecimal:
case eFormatEnum: case eFormatEnum:
@ -1356,6 +1357,7 @@ protected:
switch (m_format_options.GetFormat()) { switch (m_format_options.GetFormat()) {
case kNumFormats: case kNumFormats:
case eFormatFloat: // TODO: add support for floats soon case eFormatFloat: // TODO: add support for floats soon
case eFormatFloat128:
case eFormatCharPrintable: case eFormatCharPrintable:
case eFormatBytesWithASCII: case eFormatBytesWithASCII:
case eFormatComplex: case eFormatComplex:

View File

@ -318,14 +318,15 @@ static void printMemoryTags(const DataExtractor &DE, Stream *s,
} }
static const llvm::fltSemantics &GetFloatSemantics(const TargetSP &target_sp, static const llvm::fltSemantics &GetFloatSemantics(const TargetSP &target_sp,
size_t byte_size) { size_t byte_size,
lldb::Format format) {
if (target_sp) { if (target_sp) {
auto type_system_or_err = auto type_system_or_err =
target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC); target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC);
if (!type_system_or_err) if (!type_system_or_err)
llvm::consumeError(type_system_or_err.takeError()); llvm::consumeError(type_system_or_err.takeError());
else if (auto ts = *type_system_or_err) else if (auto ts = *type_system_or_err)
return ts->GetFloatTypeSemantics(byte_size); return ts->GetFloatTypeSemantics(byte_size, format);
} }
// No target, just make a reasonable guess // No target, just make a reasonable guess
switch(byte_size) { switch(byte_size) {
@ -335,7 +336,13 @@ static const llvm::fltSemantics &GetFloatSemantics(const TargetSP &target_sp,
return llvm::APFloat::IEEEsingle(); return llvm::APFloat::IEEEsingle();
case 8: case 8:
return llvm::APFloat::IEEEdouble(); return llvm::APFloat::IEEEdouble();
} case 16:
if (format == eFormatFloat128) {
return llvm::APFloat::IEEEquad();
}
// Otherwise it's ambigious whether a 16-byte float is a float128 or a
// target-specific long double.
}
return llvm::APFloat::Bogus(); return llvm::APFloat::Bogus();
} }
@ -653,6 +660,7 @@ lldb::offset_t lldb_private::DumpDataExtractor(
} }
} break; } break;
case eFormatFloat128:
case eFormatFloat: { case eFormatFloat: {
TargetSP target_sp; TargetSP target_sp;
if (exe_scope) if (exe_scope)
@ -666,7 +674,7 @@ lldb::offset_t lldb_private::DumpDataExtractor(
const unsigned format_precision = 0; const unsigned format_precision = 0;
const llvm::fltSemantics &semantics = const llvm::fltSemantics &semantics =
GetFloatSemantics(target_sp, item_byte_size); GetFloatSemantics(target_sp, item_byte_size, item_format);
// Recalculate the byte size in case of a difference. This is possible // Recalculate the byte size in case of a difference. This is possible
// when item_byte_size is 16 (128-bit), because you could get back the // when item_byte_size is 16 (128-bit), because you could get back the

View File

@ -72,6 +72,7 @@ static constexpr FormatInfo g_format_infos[] = {
{eFormatInstruction, 'i', "instruction"}, {eFormatInstruction, 'i', "instruction"},
{eFormatVoid, 'v', "void"}, {eFormatVoid, 'v', "void"},
{eFormatUnicode8, 'u', "unicode8"}, {eFormatUnicode8, 'u', "unicode8"},
{eFormatFloat128, '\0', "float128"},
}; };
static_assert((sizeof(g_format_infos) / sizeof(g_format_infos[0])) == static_assert((sizeof(g_format_infos) / sizeof(g_format_infos[0])) ==

View File

@ -55,6 +55,8 @@ static CompilerType GetCompilerTypeForFormat(lldb::Format format,
case lldb::eFormatFloat: case lldb::eFormatFloat:
return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloat); return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloat);
case lldb::eFormatFloat128:
return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloat128);
case lldb::eFormatHex: case lldb::eFormatHex:
case lldb::eFormatHexUppercase: case lldb::eFormatHexUppercase:

View File

@ -795,6 +795,8 @@ TypeSystemClang::GetBuiltinTypeForEncodingAndBitSize(Encoding encoding,
return GetType(ast.LongDoubleTy); return GetType(ast.LongDoubleTy);
if (QualTypeMatchesBitSize(bit_size, ast, ast.HalfTy)) if (QualTypeMatchesBitSize(bit_size, ast, ast.HalfTy))
return GetType(ast.HalfTy); return GetType(ast.HalfTy);
if (QualTypeMatchesBitSize(bit_size, ast, ast.Float128Ty))
return GetType(ast.Float128Ty);
break; break;
case eEncodingVector: case eEncodingVector:
@ -956,6 +958,13 @@ CompilerType TypeSystemClang::GetBuiltinTypeForDWARFEncodingAndBitSize(
if (type_name == "long double" && if (type_name == "long double" &&
QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleTy)) QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleTy))
return GetType(ast.LongDoubleTy); return GetType(ast.LongDoubleTy);
// As Rust currently uses `TypeSystemClang`, match `f128` here as well so it
// doesn't get misinterpreted as `long double` on targets where they are
// the same size but different formats.
if ((type_name == "__float128" || type_name == "_Float128" ||
type_name == "f128") &&
QualTypeMatchesBitSize(bit_size, ast, ast.Float128Ty))
return GetType(ast.Float128Ty);
// Fall back to not requiring a name match // Fall back to not requiring a name match
if (QualTypeMatchesBitSize(bit_size, ast, ast.FloatTy)) if (QualTypeMatchesBitSize(bit_size, ast, ast.FloatTy))
return GetType(ast.FloatTy); return GetType(ast.FloatTy);
@ -965,6 +974,8 @@ CompilerType TypeSystemClang::GetBuiltinTypeForDWARFEncodingAndBitSize(
return GetType(ast.LongDoubleTy); return GetType(ast.LongDoubleTy);
if (QualTypeMatchesBitSize(bit_size, ast, ast.HalfTy)) if (QualTypeMatchesBitSize(bit_size, ast, ast.HalfTy))
return GetType(ast.HalfTy); return GetType(ast.HalfTy);
if (QualTypeMatchesBitSize(bit_size, ast, ast.Float128Ty))
return GetType(ast.Float128Ty);
break; break;
case DW_ATE_signed: case DW_ATE_signed:
@ -2054,6 +2065,8 @@ TypeSystemClang::GetOpaqueCompilerType(clang::ASTContext *ast,
return ast->DoubleTy.getAsOpaquePtr(); return ast->DoubleTy.getAsOpaquePtr();
case eBasicTypeLongDouble: case eBasicTypeLongDouble:
return ast->LongDoubleTy.getAsOpaquePtr(); return ast->LongDoubleTy.getAsOpaquePtr();
case eBasicTypeFloat128:
return ast->Float128Ty.getAsOpaquePtr();
case eBasicTypeFloatComplex: case eBasicTypeFloatComplex:
return ast->getComplexType(ast->FloatTy).getAsOpaquePtr(); return ast->getComplexType(ast->FloatTy).getAsOpaquePtr();
case eBasicTypeDoubleComplex: case eBasicTypeDoubleComplex:
@ -4742,19 +4755,24 @@ CompilerType TypeSystemClang::CreateGenericFunctionPrototype() {
// Exploring the type // Exploring the type
const llvm::fltSemantics & const llvm::fltSemantics &
TypeSystemClang::GetFloatTypeSemantics(size_t byte_size) { TypeSystemClang::GetFloatTypeSemantics(size_t byte_size, lldb::Format format) {
clang::ASTContext &ast = getASTContext(); clang::ASTContext &ast = getASTContext();
const size_t bit_size = byte_size * 8; const size_t bit_size = byte_size * 8;
if (bit_size == ast.getTypeSize(ast.FloatTy)) if (bit_size == ast.getTypeSize(ast.FloatTy))
return ast.getFloatTypeSemantics(ast.FloatTy); return ast.getFloatTypeSemantics(ast.FloatTy);
else if (bit_size == ast.getTypeSize(ast.DoubleTy)) else if (bit_size == ast.getTypeSize(ast.DoubleTy))
return ast.getFloatTypeSemantics(ast.DoubleTy); return ast.getFloatTypeSemantics(ast.DoubleTy);
else if (format == eFormatFloat128 &&
bit_size == ast.getTypeSize(ast.Float128Ty))
return ast.getFloatTypeSemantics(ast.Float128Ty);
else if (bit_size == ast.getTypeSize(ast.LongDoubleTy) || else if (bit_size == ast.getTypeSize(ast.LongDoubleTy) ||
bit_size == llvm::APFloat::semanticsSizeInBits( bit_size == llvm::APFloat::semanticsSizeInBits(
ast.getFloatTypeSemantics(ast.LongDoubleTy))) ast.getFloatTypeSemantics(ast.LongDoubleTy)))
return ast.getFloatTypeSemantics(ast.LongDoubleTy); return ast.getFloatTypeSemantics(ast.LongDoubleTy);
else if (bit_size == ast.getTypeSize(ast.HalfTy)) else if (bit_size == ast.getTypeSize(ast.HalfTy))
return ast.getFloatTypeSemantics(ast.HalfTy); return ast.getFloatTypeSemantics(ast.HalfTy);
else if (bit_size == ast.getTypeSize(ast.Float128Ty))
return ast.getFloatTypeSemantics(ast.Float128Ty);
return llvm::APFloatBase::Bogus(); return llvm::APFloatBase::Bogus();
} }
@ -5232,6 +5250,8 @@ lldb::Format TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) {
case clang::BuiltinType::Double: case clang::BuiltinType::Double:
case clang::BuiltinType::LongDouble: case clang::BuiltinType::LongDouble:
return lldb::eFormatFloat; return lldb::eFormatFloat;
case clang::BuiltinType::Float128:
return lldb::eFormatFloat128;
default: default:
return lldb::eFormatHex; return lldb::eFormatHex;
} }
@ -5529,6 +5549,8 @@ TypeSystemClang::GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type) {
return eBasicTypeDouble; return eBasicTypeDouble;
case clang::BuiltinType::LongDouble: case clang::BuiltinType::LongDouble:
return eBasicTypeLongDouble; return eBasicTypeLongDouble;
case clang::BuiltinType::Float128:
return eBasicTypeFloat128;
case clang::BuiltinType::NullPtr: case clang::BuiltinType::NullPtr:
return eBasicTypeNullPtr; return eBasicTypeNullPtr;
@ -6090,6 +6112,7 @@ uint32_t TypeSystemClang::GetNumPointeeChildren(clang::QualType type) {
case clang::BuiltinType::Float: case clang::BuiltinType::Float:
case clang::BuiltinType::Double: case clang::BuiltinType::Double:
case clang::BuiltinType::LongDouble: case clang::BuiltinType::LongDouble:
case clang::BuiltinType::Float128:
case clang::BuiltinType::Dependent: case clang::BuiltinType::Dependent:
case clang::BuiltinType::Overload: case clang::BuiltinType::Overload:
case clang::BuiltinType::ObjCId: case clang::BuiltinType::ObjCId:
@ -8733,6 +8756,7 @@ bool TypeSystemClang::DumpTypeValue(
case eFormatHex: case eFormatHex:
case eFormatHexUppercase: case eFormatHexUppercase:
case eFormatFloat: case eFormatFloat:
case eFormatFloat128:
case eFormatOctal: case eFormatOctal:
case eFormatOSType: case eFormatOSType:
case eFormatUnsigned: case eFormatUnsigned:

View File

@ -823,7 +823,8 @@ public:
// Exploring the type // Exploring the type
const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size) override; const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size,
lldb::Format format) override;
llvm::Expected<uint64_t> GetByteSize(lldb::opaque_compiler_type_t type, llvm::Expected<uint64_t> GetByteSize(lldb::opaque_compiler_type_t type,
ExecutionContextScope *exe_scope) { ExecutionContextScope *exe_scope) {

View File

@ -1466,8 +1466,9 @@ bool ValueObject::DumpPrintableRepresentation(
(custom_format == eFormatComplexFloat) || (custom_format == eFormatComplexFloat) ||
(custom_format == eFormatDecimal) || (custom_format == eFormatHex) || (custom_format == eFormatDecimal) || (custom_format == eFormatHex) ||
(custom_format == eFormatHexUppercase) || (custom_format == eFormatHexUppercase) ||
(custom_format == eFormatFloat) || (custom_format == eFormatOctal) || (custom_format == eFormatFloat) ||
(custom_format == eFormatOSType) || (custom_format == eFormatFloat128) ||
(custom_format == eFormatOctal) || (custom_format == eFormatOSType) ||
(custom_format == eFormatUnicode16) || (custom_format == eFormatUnicode16) ||
(custom_format == eFormatUnicode32) || (custom_format == eFormatUnicode32) ||
(custom_format == eFormatUnsigned) || (custom_format == eFormatUnsigned) ||

View File

@ -163,6 +163,9 @@ TEST_F(DumpDataExtractorTest, Formats) {
TestDump(0xcafef00d, lldb::Format::eFormatHex, "0xcafef00d"); TestDump(0xcafef00d, lldb::Format::eFormatHex, "0xcafef00d");
TestDump(0xcafef00d, lldb::Format::eFormatHexUppercase, "0xCAFEF00D"); TestDump(0xcafef00d, lldb::Format::eFormatHexUppercase, "0xCAFEF00D");
TestDump(0.456, lldb::Format::eFormatFloat, "0.45600000000000002"); TestDump(0.456, lldb::Format::eFormatFloat, "0.45600000000000002");
TestDump(std::vector<uint64_t>{0x47ae147ae147ae14, 0x40011147ae147ae1},
lldb::Format::eFormatFloat128,
"4.26999999999999999999999999999999963");
TestDump(9, lldb::Format::eFormatOctal, "011"); TestDump(9, lldb::Format::eFormatOctal, "011");
// Chars packed into an integer. // Chars packed into an integer.
TestDump<uint32_t>(0x4C4C4442, lldb::Format::eFormatOSType, "'LLDB'"); TestDump<uint32_t>(0x4C4C4442, lldb::Format::eFormatOSType, "'LLDB'");
@ -388,6 +391,9 @@ TEST_F(DumpDataExtractorTest, ItemByteSizeErrors) {
TestDumpWithItemByteSize( TestDumpWithItemByteSize(
18, lldb::Format::eFormatFloat, 18, lldb::Format::eFormatFloat,
"error: unsupported byte size (18) for float format"); "error: unsupported byte size (18) for float format");
TestDumpWithItemByteSize(
17, lldb::Format::eFormatFloat128,
"error: unsupported byte size (17) for float format");
// We want sizes to exactly match one of float/double. // We want sizes to exactly match one of float/double.
TestDumpWithItemByteSize( TestDumpWithItemByteSize(

View File

@ -76,6 +76,8 @@ TEST_F(TestTypeSystemClang, TestGetBasicTypeFromEnum) {
context.getComplexType(context.FloatTy))); context.getComplexType(context.FloatTy)));
EXPECT_TRUE( EXPECT_TRUE(
context.hasSameType(GetBasicQualType(eBasicTypeHalf), context.HalfTy)); context.hasSameType(GetBasicQualType(eBasicTypeHalf), context.HalfTy));
EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeFloat128),
context.Float128Ty));
EXPECT_TRUE( EXPECT_TRUE(
context.hasSameType(GetBasicQualType(eBasicTypeInt), context.IntTy)); context.hasSameType(GetBasicQualType(eBasicTypeInt), context.IntTy));
EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeInt128), EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeInt128),