[Lldb-commits] [lldb] [lldb][TypeSystem] Better support for _BitInt types (PR #165689)
Michael Buch via lldb-commits
lldb-commits at lists.llvm.org
Thu Oct 30 09:33:14 PDT 2025
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/165689
>From facecc8415559b01e4b6d59c61f6692295eaca3e Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 30 Oct 2025 10:13:06 +0000
Subject: [PATCH 1/2] [lldb][TypeSystem] Better support for _BitInt types
This patch ensures we make use of the `DW_AT_bit_size` on `DW_TAG_base_type`s (which since https://github.com/llvm/llvm-project/pull/164372 can exist on `_BitInt`s) and adjusts `TypeSystemClang` to recognize `_BitInt`.
For DWARF from older versions of Clang that didn't emit a `DW_AT_bit_size`, we would create `_BitInt`s using the byte-size. Not sure we can do much better than that. But the situation beforehand wasn't much better.
Before:
```
(lldb) v
(char) a = '\x01'
(unsigned char) b = '\x01'
(long) c = 2
(unsigned long) d = 2
```
After:
```
(lldb) v
(_BitInt(2)) a = 1
(unsigned _BitInt(2)) b = 1
(_BitInt(52)) c = 2
(unsigned _BitInt(52)) d = 2
```
---
.../SymbolFile/DWARF/DWARFASTParserClang.cpp | 12 +-
.../TypeSystem/Clang/TypeSystemClang.cpp | 11 +
lldb/unittests/Symbol/TestTypeSystemClang.cpp | 75 ++++++
.../DWARF/DWARFASTParserClangTests.cpp | 217 ++++++++++++++++++
4 files changed, 311 insertions(+), 4 deletions(-)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index c049829f37219..76f0cec177019 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -814,13 +814,17 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc,
// there...
[[fallthrough]];
- case DW_TAG_base_type:
+ case DW_TAG_base_type: {
resolve_state = Type::ResolveState::Full;
+ // If a builtin type's size isn't a multiple of a byte, DWARF producers may
+ // add a precise bit-size to the type. Use the most precise bit-size
+ // possible.
+ uint64_t bit_size = attrs.data_bit_size ? *attrs.data_bit_size
+ : attrs.byte_size.value_or(0) * 8;
clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize(
- attrs.name.GetStringRef(), attrs.encoding,
- attrs.byte_size.value_or(0) * 8);
+ attrs.name.GetStringRef(), attrs.encoding, bit_size);
break;
-
+ }
case DW_TAG_pointer_type:
encoding_data_type = Type::eEncodingIsPointerUID;
break;
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 6ec054d5eac05..d4cb788920ab6 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -1000,6 +1000,8 @@ CompilerType TypeSystemClang::GetBuiltinTypeForDWARFEncodingAndBitSize(
case DW_ATE_signed:
if (!type_name.empty()) {
+ if (type_name.starts_with("_BitInt"))
+ return GetType(ast.getBitIntType(/*Unsigned=*/false, bit_size));
if (type_name == "wchar_t" &&
QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy) &&
(getTargetInfo() &&
@@ -1056,6 +1058,8 @@ CompilerType TypeSystemClang::GetBuiltinTypeForDWARFEncodingAndBitSize(
case DW_ATE_unsigned:
if (!type_name.empty()) {
+ if (type_name.starts_with("unsigned _BitInt"))
+ return GetType(ast.getBitIntType(/*Unsigned=*/true, bit_size));
if (type_name == "wchar_t") {
if (QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy)) {
if (!(getTargetInfo() &&
@@ -3893,6 +3897,13 @@ TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type,
->getModifiedType()
.getAsOpaquePtr(),
pointee_or_element_clang_type);
+ case clang::Type::BitInt: {
+ uint32_t type_flags = eTypeIsScalar | eTypeIsInteger | eTypeHasValue;
+ if (qual_type->isSignedIntegerType())
+ type_flags |= eTypeIsSigned;
+
+ return type_flags;
+ }
case clang::Type::Builtin: {
const clang::BuiltinType *builtin_type =
llvm::cast<clang::BuiltinType>(qual_type->getCanonicalTypeInternal());
diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
index 1981e912fa4fa..b2fb0814b70f9 100644
--- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp
+++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
@@ -52,6 +52,12 @@ class TestTypeSystemClang : public testing::Test {
return ClangUtil::GetQualType(
m_ast->GetBuiltinTypeByName(ConstString(name)));
}
+
+ CompilerType GetBuiltinTypeForDWARFEncodingAndBitSize(
+ llvm::StringRef type_name, uint32_t encoding, uint32_t bit_size) const {
+ return m_ast->GetBuiltinTypeForDWARFEncodingAndBitSize(type_name, encoding,
+ bit_size);
+ }
};
TEST_F(TestTypeSystemClang, TestGetBasicTypeFromEnum) {
@@ -238,6 +244,75 @@ TEST_F(TestTypeSystemClang, TestBuiltinTypeForEncodingAndBitSize) {
VerifyEncodingAndBitSize(*m_ast, eEncodingIEEE754, 64);
}
+TEST_F(TestTypeSystemClang, TestGetBuiltinTypeForDWARFEncodingAndBitSize) {
+ EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "_BitIn", llvm::dwarf::DW_ATE_signed, 2)
+ .IsValid());
+ EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "BitInt", llvm::dwarf::DW_ATE_signed, 2)
+ .IsValid());
+ EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "_BitInt(2)", llvm::dwarf::DW_ATE_signed_char, 2)
+ .IsValid());
+ EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "_BitInt", llvm::dwarf::DW_ATE_signed_char, 2)
+ .IsValid());
+ EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "_BitInt(2)", llvm::dwarf::DW_ATE_unsigned, 2)
+ .IsValid());
+ EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "_BitInt", llvm::dwarf::DW_ATE_unsigned, 2)
+ .IsValid());
+
+ EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "_BitInt(2)", llvm::dwarf::DW_ATE_signed, 2)
+ .GetTypeName(),
+ "_BitInt(2)");
+ EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "_BitInt", llvm::dwarf::DW_ATE_signed, 2)
+ .GetTypeName(),
+ "_BitInt(2)");
+
+ EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "unsigned _BitIn", llvm::dwarf::DW_ATE_unsigned, 2)
+ .IsValid());
+ EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "unsigned BitInt", llvm::dwarf::DW_ATE_unsigned, 2)
+ .IsValid());
+ EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "unsigned _BitInt(2)", llvm::dwarf::DW_ATE_unsigned_char, 2)
+ .IsValid());
+ EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "unsigned _BitInt", llvm::dwarf::DW_ATE_unsigned_char, 2)
+ .IsValid());
+ EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "unsigned _BitInt(2)", llvm::dwarf::DW_ATE_signed, 2)
+ .IsValid());
+ EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "unsigned _BitInt", llvm::dwarf::DW_ATE_signed, 2)
+ .IsValid());
+
+ EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "unsigned _BitInt(2)", llvm::dwarf::DW_ATE_unsigned, 2)
+ .GetTypeName(),
+ "unsigned _BitInt(2)");
+ EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "unsigned _BitInt", llvm::dwarf::DW_ATE_unsigned, 2)
+ .GetTypeName(),
+ "unsigned _BitInt(2)");
+}
+
+TEST_F(TestTypeSystemClang, TestBitIntTypeInfo) {
+ EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "_BitInt", llvm::dwarf::DW_ATE_signed, 2)
+ .GetTypeInfo(),
+ eTypeIsSigned | eTypeIsScalar | eTypeHasValue | eTypeIsInteger);
+ EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "unsigned _BitInt", llvm::dwarf::DW_ATE_unsigned, 2)
+ .GetTypeInfo(),
+ eTypeIsScalar | eTypeHasValue | eTypeIsInteger);
+}
+
TEST_F(TestTypeSystemClang, TestBuiltinTypeForEmptyTriple) {
// Test that we can access type-info of builtin Clang AST
// types without crashing even when the target triple is
diff --git a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
index 064ed6d1d3e58..72e2fa175fdea 100644
--- a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
+++ b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
@@ -1741,3 +1741,220 @@ TEST_F(DWARFASTParserClangTests, TestTypeBitSize) {
EXPECT_EQ(llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0),
1U);
}
+
+TEST_F(DWARFASTParserClangTests, TestBitIntParsing) {
+ // Tests that we correctly parse the DW_AT_base_type for a _BitInt.
+ // Older versions of Clang only emit the `_BitInt` string into the
+ // DW_AT_name (not including the bitsize). Make sure we understand
+ // those too.
+
+ const char *yamldata = R"(
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_AARCH64
+DWARF:
+ debug_str:
+ - _BitInt(2)
+ - _BitInt
+ - unsigned _BitInt(2)
+ - unsigned _BitInt
+ debug_abbrev:
+ - ID: 0
+ Table:
+ - Code: 0x1
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Code: 0x2
+ Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Attribute: DW_AT_encoding
+ Form: DW_FORM_data1
+ - Attribute: DW_AT_byte_size
+ Form: DW_FORM_data1
+ - Attribute: DW_AT_bit_size
+ Form: DW_FORM_data1
+ - Code: 0x3
+ Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Attribute: DW_AT_encoding
+ Form: DW_FORM_data1
+ - Attribute: DW_AT_byte_size
+ Form: DW_FORM_data1
+
+ debug_info:
+ - Version: 5
+ UnitType: DW_UT_compile
+ AddrSize: 8
+ Entries:
+
+# DW_TAG_compile_unit
+# DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus)
+
+ - AbbrCode: 0x1
+ Values:
+ - Value: 0x04
+
+# DW_TAG_base_type
+# DW_AT_name [DW_FORM_strp] ('_BitInt(2)')
+
+ - AbbrCode: 0x2
+ Values:
+ - Value: 0x0
+ - Value: 0x05
+ - Value: 0x01
+ - Value: 0x02
+
+# DW_TAG_base_type
+# DW_AT_name [DW_FORM_strp] ('_BitInt')
+
+ - AbbrCode: 0x2
+ Values:
+ - Value: 0x0b
+ - Value: 0x05
+ - Value: 0x08
+ - Value: 0x34
+
+# DW_TAG_base_type
+# DW_AT_name [DW_FORM_strp] ('unsigned _BitInt(2)')
+
+ - AbbrCode: 0x2
+ Values:
+ - Value: 0x13
+ - Value: 0x07
+ - Value: 0x01
+ - Value: 0x02
+
+# DW_TAG_base_type
+# DW_AT_name [DW_FORM_strp] ('unsigned _BitInt')
+
+ - AbbrCode: 0x2
+ Values:
+ - Value: 0x27
+ - Value: 0x07
+ - Value: 0x08
+ - Value: 0x34
+
+# DW_TAG_base_type
+# DW_AT_name [DW_FORM_strp] ('_BitInt')
+
+ - AbbrCode: 0x3
+ Values:
+ - Value: 0x0b
+ - Value: 0x05
+ - Value: 0x08
+...
+
+)";
+
+ YAMLModuleTester t(yamldata);
+
+ DWARFUnit *unit = t.GetDwarfUnit();
+ ASSERT_NE(unit, nullptr);
+ const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
+ ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
+ ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus);
+ DWARFDIE cu_die(unit, cu_entry);
+
+ auto holder = std::make_unique<clang_utils::TypeSystemClangHolder>("ast");
+ auto &ast_ctx = *holder->GetAST();
+ DWARFASTParserClangStub ast_parser(ast_ctx);
+
+ auto type_die = cu_die.GetFirstChild();
+ ASSERT_TRUE(type_die.IsValid());
+
+ {
+ SymbolContext sc;
+ auto type_sp = ast_parser.ParseTypeFromDWARF(sc, type_die,
+ /*type_is_new_ptr=*/nullptr);
+ ASSERT_NE(type_sp, nullptr);
+
+ EXPECT_EQ(
+ llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0),
+ 1U);
+ uint64_t count;
+ EXPECT_EQ(type_sp->GetEncoding(count), lldb::eEncodingSint);
+ EXPECT_EQ(type_sp->GetName(), "_BitInt(2)");
+ EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName(), "_BitInt(2)");
+ }
+
+ {
+ type_die = type_die.GetSibling();
+ SymbolContext sc;
+ auto type_sp = ast_parser.ParseTypeFromDWARF(sc, type_die,
+ /*type_is_new_ptr=*/nullptr);
+ ASSERT_NE(type_sp, nullptr);
+
+ EXPECT_EQ(
+ llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0),
+ 8U);
+ uint64_t count;
+ EXPECT_EQ(type_sp->GetEncoding(count), lldb::eEncodingSint);
+ EXPECT_EQ(type_sp->GetName(), "_BitInt");
+ EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName(), "_BitInt(52)");
+ }
+
+ {
+ type_die = type_die.GetSibling();
+ SymbolContext sc;
+ auto type_sp = ast_parser.ParseTypeFromDWARF(sc, type_die,
+ /*type_is_new_ptr=*/nullptr);
+ ASSERT_NE(type_sp, nullptr);
+
+ EXPECT_EQ(
+ llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0),
+ 1U);
+ uint64_t count;
+ EXPECT_EQ(type_sp->GetEncoding(count), lldb::eEncodingUint);
+ EXPECT_EQ(type_sp->GetName(), "unsigned _BitInt(2)");
+ EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName(),
+ "unsigned _BitInt(2)");
+ }
+
+ {
+ type_die = type_die.GetSibling();
+ SymbolContext sc;
+ auto type_sp = ast_parser.ParseTypeFromDWARF(sc, type_die,
+ /*type_is_new_ptr=*/nullptr);
+ ASSERT_NE(type_sp, nullptr);
+
+ EXPECT_EQ(
+ llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0),
+ 8U);
+ uint64_t count;
+ EXPECT_EQ(type_sp->GetEncoding(count), lldb::eEncodingUint);
+ EXPECT_EQ(type_sp->GetName(), "unsigned _BitInt");
+ EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName(),
+ "unsigned _BitInt(52)");
+ }
+
+ {
+ type_die = type_die.GetSibling();
+ SymbolContext sc;
+ auto type_sp = ast_parser.ParseTypeFromDWARF(sc, type_die,
+ /*type_is_new_ptr=*/nullptr);
+ ASSERT_NE(type_sp, nullptr);
+
+ EXPECT_EQ(
+ llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0),
+ 8U);
+ uint64_t count;
+ EXPECT_EQ(type_sp->GetEncoding(count), lldb::eEncodingSint);
+ EXPECT_EQ(type_sp->GetName(), "_BitInt");
+
+ // Older versions of Clang didn't emit a DW_AT_bit_size for _BitInt. In
+ // those cases we would format the CompilerType name using the byte-size.
+ EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName(), "_BitInt(64)");
+ }
+}
>From 9c68ad5b3431a909226f6735871a544950e9fd71 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 30 Oct 2025 10:46:07 +0000
Subject: [PATCH 2/2] fixup! add 129-bit test-case
---
lldb/unittests/Symbol/TestTypeSystemClang.cpp | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
index b2fb0814b70f9..e1acdb1473479 100644
--- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp
+++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
@@ -272,6 +272,14 @@ TEST_F(TestTypeSystemClang, TestGetBuiltinTypeForDWARFEncodingAndBitSize) {
"_BitInt", llvm::dwarf::DW_ATE_signed, 2)
.GetTypeName(),
"_BitInt(2)");
+ EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "_BitInt(129)", llvm::dwarf::DW_ATE_signed, 129)
+ .GetTypeName(),
+ "_BitInt(129)");
+ EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "_BitInt", llvm::dwarf::DW_ATE_signed, 129)
+ .GetTypeName(),
+ "_BitInt(129)");
EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize(
"unsigned _BitIn", llvm::dwarf::DW_ATE_unsigned, 2)
@@ -300,6 +308,14 @@ TEST_F(TestTypeSystemClang, TestGetBuiltinTypeForDWARFEncodingAndBitSize) {
"unsigned _BitInt", llvm::dwarf::DW_ATE_unsigned, 2)
.GetTypeName(),
"unsigned _BitInt(2)");
+ EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "unsigned _BitInt(129)", llvm::dwarf::DW_ATE_unsigned, 129)
+ .GetTypeName(),
+ "unsigned _BitInt(129)");
+ EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "unsigned _BitInt", llvm::dwarf::DW_ATE_unsigned, 129)
+ .GetTypeName(),
+ "unsigned _BitInt(129)");
}
TEST_F(TestTypeSystemClang, TestBitIntTypeInfo) {
More information about the lldb-commits
mailing list