mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 19:08:21 +08:00
[lldb][TypeSystem] Better support for _BitInt types (#165689)
Depends on: * https://github.com/llvm/llvm-project/pull/165686 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 ``` Fixes https://github.com/llvm/llvm-project/issues/110273
This commit is contained in:
@@ -814,13 +814,18 @@ 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.
|
||||
const 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;
|
||||
|
||||
@@ -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() &&
|
||||
@@ -3889,6 +3893,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());
|
||||
|
||||
@@ -52,6 +52,12 @@ protected:
|
||||
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,91 @@ 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_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)
|
||||
.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)");
|
||||
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) {
|
||||
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
|
||||
|
||||
@@ -1741,3 +1741,215 @@ DWARF:
|
||||
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);
|
||||
EXPECT_EQ(type_sp->GetEncoding(), 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);
|
||||
EXPECT_EQ(type_sp->GetEncoding(), 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);
|
||||
EXPECT_EQ(type_sp->GetEncoding(), 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);
|
||||
EXPECT_EQ(type_sp->GetEncoding(), 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);
|
||||
EXPECT_EQ(type_sp->GetEncoding(), 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)");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user