From d441ee7dbc8fcb54faeda22921325dbb273e1598 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) (cherry picked from commit cdc3876229abdacbaf120ca11dab3985f69a5c09) --- .../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 0eeecb232efb6..2d856286c2ad9 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 114b085875495..a923789ca469a 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 986934c25bd5b..d1554d5bd1011 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 54b6bd8185155..cb45af0c5c31b 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); } @@ -1101,10 +1101,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 219b04c0f29c1..dc0438e32ea44 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 f8cd0cf4f92d7..9e1deea2ea4d9 100644 --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -1786,17 +1786,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,