From cdc3876229abdacbaf120ca11dab3985f69a5c09 Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Wed, 6 Nov 2024 17:36:50 -0800 Subject: [PATCH] [DebugInfo] Add num_extra_inhabitants to debug info (#112590) An extra inhabitant is a bit pattern that does not represent a valid value for instances of a given type. The number of extra inhabitants is the number of those bit configurations. This is used by Swift to save space when composing types. For example, because Bool only needs 2 bit patterns to represent all of its values (true and false), an Optional only occupies 1 byte in memory by using a bit configuration that is unused by Bool. Which bit patterns are unused are part of the ABI of the language. Since Swift generics are not monomorphized, by using dynamic libraries you can have generic types whose size, alignment, etc, are known only at runtime (which is why this feature is needed). This patch adds num_extra_inhabitants to LLVM-IR debug info and in DWARF as an Apple extension. (cherry picked from commit f6617d65e496823c748236cdbe8e42bf4c8d8a55) --- .../DWARFASTParserSwiftDescriptorFinder.cpp | 2 +- llvm/include/llvm/BinaryFormat/Dwarf.def | 2 +- llvm/include/llvm/IR/DIBuilder.h | 4 +-- llvm/include/llvm/IR/DebugInfoMetadata.h | 20 +++++++++---- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 9 +++--- llvm/lib/IR/DebugInfoMetadata.cpp | 3 +- llvm/test/Assembler/debug-info.ll | 10 +++++-- .../AArch64/num_extra_inhabitants.ll | 29 +++++++++++++------ llvm/unittests/IR/MetadataTest.cpp | 9 +++--- 9 files changed, 55 insertions(+), 33 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwiftDescriptorFinder.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwiftDescriptorFinder.cpp index c122f65a717b2..c377d2fdb4413 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwiftDescriptorFinder.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwiftDescriptorFinder.cpp @@ -318,7 +318,7 @@ DWARFASTParserSwift::getBuiltinTypeDescriptor( unsigned stride = ((byte_size + alignment - 1) & ~(alignment - 1)); auto num_extra_inhabitants = - die.GetAttributeValueAsUnsigned(DW_AT_APPLE_num_extra_inhabitants, 0); + die.GetAttributeValueAsUnsigned(DW_AT_LLVM_num_extra_inhabitants, 0); auto is_bitwise_takable = true; // TODO: encode it in DWARF diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def index d54a307a5cdfd..09496cbdd4c8d 100644 --- a/llvm/include/llvm/BinaryFormat/Dwarf.def +++ b/llvm/include/llvm/BinaryFormat/Dwarf.def @@ -617,6 +617,7 @@ HANDLE_DW_AT(0x3e07, LLVM_apinotes, 0, APPLE) HANDLE_DW_AT(0x3e08, LLVM_ptrauth_isa_pointer, 0, LLVM) HANDLE_DW_AT(0x3e09, LLVM_ptrauth_authenticates_null_values, 0, LLVM) HANDLE_DW_AT(0x3e0a, LLVM_ptrauth_authentication_mode, 0, LLVM) +HANDLE_DW_AT(0x3e0b, LLVM_num_extra_inhabitants, 0, LLVM) // Apple extensions. HANDLE_DW_AT(0x3fe1, APPLE_optimized, 0, APPLE) @@ -635,7 +636,6 @@ HANDLE_DW_AT(0x3fed, APPLE_property, 0, APPLE) HANDLE_DW_AT(0x3fee, APPLE_objc_direct, 0, APPLE) HANDLE_DW_AT(0x3fef, APPLE_sdk, 0, APPLE) HANDLE_DW_AT(0x3ff0, APPLE_origin, 0, APPLE) -HANDLE_DW_AT(0x3ff1, APPLE_num_extra_inhabitants, 0, APPLE) // Attribute form encodings. HANDLE_DW_FORM(0x01, addr, 2, DWARF) diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h index b304c4d56a319..367a4002054f6 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -227,7 +227,7 @@ namespace llvm { /// \param Flags Optional DWARF attributes, e.g., DW_AT_endianity. /// \param NumExtraInhabitants The number of extra inhabitants of the type. /// An extra inhabitant is a bit pattern that does not represent a valid - /// value for objects of a given type. + /// value for instances of a given type. This is used by the Swift language. DIBasicType *createBasicType(StringRef Name, uint64_t SizeInBits, unsigned Encoding, DINode::DIFlags Flags = DINode::FlagZero, @@ -493,7 +493,7 @@ namespace llvm { /// template parameters have been substituted in. /// \param NumExtraInhabitants The number of extra inhabitants of the type. /// An extra inhabitant is a bit pattern that does not represent a valid - /// value for objects of a given type. + /// value for instances of a given type. DICompositeType *createStructType( DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, DINode::DIFlags Flags, diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index d243a087f49a4..6754ac0d9d73e 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -739,10 +739,12 @@ class DIType : public DIScope { /// Change fields in place. void mutate(unsigned Tag, unsigned Line, uint64_t SizeInBits, - uint32_t AlignInBits, uint64_t OffsetInBits, uint32_t NumExtraInhabitants, DIFlags Flags) { + uint32_t AlignInBits, uint64_t OffsetInBits, + uint32_t NumExtraInhabitants, DIFlags Flags) { assert(isDistinct() && "Only distinct nodes can mutate"); setTag(Tag); - init(Line, SizeInBits, AlignInBits, OffsetInBits, NumExtraInhabitants, Flags); + init(Line, SizeInBits, AlignInBits, OffsetInBits, NumExtraInhabitants, + Flags); } public: @@ -838,8 +840,7 @@ class DIBasicType : public DIType { StringRef Name, uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, uint32_t NumExtraInhabitants, DIFlags Flags, - StorageType Storage, - bool ShouldCreate = true) { + StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Tag, getCanonicalMDString(Context, Name), SizeInBits, AlignInBits, Encoding, NumExtraInhabitants, Flags, Storage, ShouldCreate); @@ -865,6 +866,14 @@ class DIBasicType : public DIType { DEFINE_MDNODE_GET(DIBasicType, (unsigned Tag, MDString *Name, uint64_t SizeInBits), (Tag, Name, SizeInBits, 0, 0, 0, FlagZero)) + DEFINE_MDNODE_GET(DIBasicType, + (unsigned Tag, StringRef Name, uint64_t SizeInBits, + uint32_t AlignInBits, unsigned Encoding, DIFlags Flags), + (Tag, Name, SizeInBits, AlignInBits, Encoding, 0, Flags)) + DEFINE_MDNODE_GET(DIBasicType, + (unsigned Tag, MDString *Name, uint64_t SizeInBits, + uint32_t AlignInBits, unsigned Encoding, DIFlags Flags), + (Tag, Name, SizeInBits, AlignInBits, Encoding, 0, Flags)) DEFINE_MDNODE_GET(DIBasicType, (unsigned Tag, StringRef Name, uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, @@ -1033,8 +1042,7 @@ class DIDerivedType : public DIType { std::optional PtrAuthData, DIFlags Flags, ArrayRef Ops) : DIType(C, DIDerivedTypeKind, Storage, Tag, Line, SizeInBits, - AlignInBits, OffsetInBits, /*NumExtraInhabitants=*/0, Flags, - Ops), + AlignInBits, OffsetInBits, /*NumExtraInhabitants=*/0, Flags, Ops), DWARFAddressSpace(DWARFAddressSpace) { if (PtrAuthData) SubclassData32 = PtrAuthData->RawData; diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index a8fe1e062285d..e821dca85a35b 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -737,7 +737,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIBasicType *BTy) { addUInt(Buffer, dwarf::DW_AT_endianity, std::nullopt, dwarf::DW_END_little); if (uint32_t NumExtraInhabitants = BTy->getNumExtraInhabitants()) - addUInt(Buffer, dwarf::DW_AT_APPLE_num_extra_inhabitants, std::nullopt, + addUInt(Buffer, dwarf::DW_AT_LLVM_num_extra_inhabitants, std::nullopt, NumExtraInhabitants); } @@ -1100,10 +1100,9 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { AlignInBytes); if (uint32_t NumExtraInhabitants = CTy->getNumExtraInhabitants()) - addUInt(Buffer, dwarf::DW_AT_APPLE_num_extra_inhabitants, - std::nullopt, NumExtraInhabitants); - - } + addUInt(Buffer, dwarf::DW_AT_LLVM_num_extra_inhabitants, std::nullopt, + NumExtraInhabitants); + } } void DwarfUnit::constructTemplateTypeParameterDIE( diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 42a771a0add2b..7861f902cd28a 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -664,8 +664,7 @@ DIBasicType *DIBasicType::getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, uint32_t NumExtraInhabitants, DIFlags Flags, - StorageType Storage, - bool ShouldCreate) { + StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); DEFINE_GETIMPL_LOOKUP(DIBasicType, (Tag, Name, SizeInBits, AlignInBits, Encoding, NumExtraInhabitants, Flags)); diff --git a/llvm/test/Assembler/debug-info.ll b/llvm/test/Assembler/debug-info.ll index 06144b261373f..7faaf50496def 100644 --- a/llvm/test/Assembler/debug-info.ll +++ b/llvm/test/Assembler/debug-info.ll @@ -1,8 +1,8 @@ ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s ; RUN: verify-uselistorder %s -; CHECK: !named = !{!0, !0, !1, !2, !3, !4, !5, !6, !7, !8, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36, !37, !38, !39, !40, !41, !42, !43} -!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36, !37, !38, !39, !40, !41, !42, !43, !44, !45, !46} +; CHECK: !named = !{!0, !0, !1, !2, !3, !4, !5, !6, !7, !8, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36, !37, !38, !39, !40, !41, !42, !43, !44, !45} +!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36, !37, !38, !39, !40, !41, !42, !43, !44, !45, !46, !47, !48} ; CHECK: !0 = !DISubrange(count: 3, lowerBound: 0) ; CHECK-NEXT: !1 = !DISubrange(count: 3, lowerBound: 4) @@ -111,3 +111,9 @@ ; CHECK: !DIDerivedType(tag: DW_TAG_LLVM_ptrauth_type, baseType: !13, ptrAuthKey: 2, ptrAuthIsAddressDiscriminated: true, ptrAuthExtraDiscriminator: 1234, ptrAuthIsaPointer: true, ptrAuthAuthenticatesNullValues: true) !46 = !DIDerivedType(tag: DW_TAG_LLVM_ptrauth_type, baseType: !15, ptrAuthKey: 2, ptrAuthIsAddressDiscriminated: true, ptrAuthExtraDiscriminator: 1234, ptrAuthIsaPointer: true, ptrAuthAuthenticatesNullValues: true) + +; CHECK: !DIBasicType(name: "ExtraInhabitantBasicType", size: 1, encoding: DW_ATE_unsigned, num_extra_inhabitants: 254) +!47 = !DIBasicType(name: "ExtraInhabitantBasicType", size: 1, encoding: DW_ATE_unsigned, num_extra_inhabitants: 254) + +;CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "ExtraInhabitantCompositeType", file: !10, size: 64, num_extra_inhabitants: 66, identifier: "MangledExtraInhabitantCompositeType") +!48 = !DICompositeType(tag: DW_TAG_structure_type, name: "ExtraInhabitantCompositeType", file: !12, size: 64, num_extra_inhabitants: 66, identifier: "MangledExtraInhabitantCompositeType") diff --git a/llvm/test/DebugInfo/AArch64/num_extra_inhabitants.ll b/llvm/test/DebugInfo/AArch64/num_extra_inhabitants.ll index 7c552aa10e29c..6d35f2b2fc9da 100644 --- a/llvm/test/DebugInfo/AArch64/num_extra_inhabitants.ll +++ b/llvm/test/DebugInfo/AArch64/num_extra_inhabitants.ll @@ -2,29 +2,40 @@ ; RUN: | llvm-dwarfdump - | FileCheck %s ; CHECK: DW_TAG_base_type -; CHECK: DW_AT_APPLE_num_extra_inhabitants (0xfe) +; CHECK: DW_AT_name ("ExtraInhabitantBasicType") +; CHECK: DW_AT_LLVM_num_extra_inhabitants (0xfe) ; CHECK: DW_TAG_structure_type -; CHECK: DW_AT_APPLE_num_extra_inhabitants (0x42) +; CHECK: DW_AT_name ("ExtraInhabitantCompositeType") +; CHECK: DW_AT_LLVM_num_extra_inhabitants (0x42) + +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("NoExtraInhabitantType") +; CHECK-NOT: DW_AT_LLVM_num_extra_inhabitants + target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" -@p = common global i8* null, align 8, !dbg !0 -@q = common global i8* null, align 8, !dbg !8 +@p = common global i8* null, align 8, !dbg !100 +@q = common global i8* null, align 8, !dbg !102 +@r = common global i8* null, align 8, !dbg !105 !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!6, !7} -!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) -!1 = distinct !DIGlobalVariable(name: "p", scope: !2, file: !3, line: 1, type: !10, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, emissionKind: FullDebug, globals: !5) !3 = !DIFile(filename: "/tmp/p.c", directory: "/") !4 = !{} -!5 = !{!0, !8} +!5 = !{!100, !102, !105} !6 = !{i32 2, !"Dwarf Version", i32 4} !7 = !{i32 2, !"Debug Info Version", i32 3} -!8 = !DIGlobalVariableExpression(var: !9, expr: !DIExpression()) -!9 = distinct !DIGlobalVariable(name: "q", scope: !2, file: !3, line: 1, type: !11, isLocal: false, isDefinition: true) !10 = !DIBasicType(name: "ExtraInhabitantBasicType", size: 1, encoding: DW_ATE_unsigned, num_extra_inhabitants: 254) !11 = !DICompositeType(tag: DW_TAG_structure_type, name: "ExtraInhabitantCompositeType", file: !3, size: 64, num_extra_inhabitants: 66, identifier: "MangledExtraInhabitantCompositeType") +!12 = !DICompositeType(tag: DW_TAG_structure_type, name: "NoExtraInhabitantType", file: !3, size: 64, identifier: "MangledNoExtraInhabitantType") +!100 = !DIGlobalVariableExpression(var: !101, expr: !DIExpression()) +!101 = distinct !DIGlobalVariable(name: "p", scope: !2, file: !3, line: 1, type: !10, isLocal: false, isDefinition: true) +!102 = !DIGlobalVariableExpression(var: !103, expr: !DIExpression()) +!103 = distinct !DIGlobalVariable(name: "q", scope: !2, file: !3, line: 1, type: !11, isLocal: false, isDefinition: true) +!104 = distinct !DIGlobalVariable(name: "r", scope: !2, file: !3, line: 1, type: !12, isLocal: false, isDefinition: true) +!105 = !DIGlobalVariableExpression(var: !104, expr: !DIExpression()) diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp index b1353d9954a22..51246c1655d3b 100644 --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -1787,17 +1787,16 @@ TEST_F(DIBasicTypeTest, get) { 26, 7, 100, DINode::FlagZero)); EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, - "special", 33, 26, 7,100, DINode::FlagZero)); - EXPECT_NE(N, - DIBasicType::get(Context, dwarf::DW_TAG_base_type, "s", 33, 26, 7, 100, - DINode::FlagZero)); + "special", 33, 26, 7, 100, DINode::FlagZero)); + EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "s", 33, 26, + 7, 100, DINode::FlagZero)); EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", 32, 26, 7, 100, DINode::FlagZero)); EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", 33, 25, 7, 100, DINode::FlagZero)); EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", 33, - 26, 7, 99, DINode::FlagZero)); + 26, 7, 99, DINode::FlagZero)); EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", 33, 26, 6, 100, DINode::FlagZero)); EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", 33,