From 102f7fce8d8251655be5bf6955af33e55bea9c9e Mon Sep 17 00:00:00 2001 From: serge-sans-paille Date: Thu, 16 Nov 2023 21:55:43 +0000 Subject: [PATCH] [llvm] Reduce memory footprint of Debug metadata nodes (#71227) Using a combination of reordering fields and using empty SubclassData32 / SubclassData1, it's possible to improve the size of data structures used to store debug info in the IR: Before: DILexicalBlock: 24 DILexicalBlockFile: 24 DIModule: 24 DITemplateParameter: 24 DICommonBlock: 24 DIMacro: 24 DICompileUnit: 56 DIType: 48 DINamespace: 24 DIVariable: 24 DIGlobalVariable: 32 DILocalVariable: 32 DILabel: 24 After: DILexicalBlock: 24 DILexicalBlockFile: 16 DIModule: 16 DITemplateParameter: 16 DICommonBlock: 16 DIMacro: 16 DICompileUnit: 48 DIType: 40 DINamespace: 16 DIVariable: 24 DIGlobalVariable: 24 DILocalVariable: 32 DILabel: 16 --- llvm/include/llvm/IR/DebugInfoMetadata.h | 115 ++++++++++++++--------- llvm/lib/IR/DebugInfoMetadata.cpp | 33 ++++--- 2 files changed, 90 insertions(+), 58 deletions(-) diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index 1fe054316b75c..3d9ee1c33e946 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -128,6 +128,8 @@ class DITypeRefArray { /// A metadata node with a DWARF tag (i.e., a constant named \c DW_TAG_*, /// defined in llvm/BinaryFormat/Dwarf.h). Called \a DINode because it's /// potentially used for non-DWARF output. +/// +/// Uses the SubclassData16 Metadata slot. class DINode : public MDNode { friend class LLVMContextImpl; friend class MDNode; @@ -227,6 +229,8 @@ class DINode : public MDNode { /// (possibly empty) null-separated \a MDString header that contains arbitrary /// fields. The remaining operands are \a dwarf_operands(), and are pointers /// to other metadata. +/// +/// Uses the SubclassData32 Metadata slot. class GenericDINode : public DINode { friend class LLVMContextImpl; friend class MDNode; @@ -695,12 +699,13 @@ std::optional DIScope::getSource() const { /// TODO: Remove the hardcoded name and context, since many types don't use /// them. /// TODO: Split up flags. +/// +/// Uses the SubclassData32 Metadata slot. class DIType : public DIScope { unsigned Line; DIFlags Flags; uint64_t SizeInBits; uint64_t OffsetInBits; - uint32_t AlignInBits; protected: DIType(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Tag, @@ -716,7 +721,7 @@ class DIType : public DIScope { this->Line = Line; this->Flags = Flags; this->SizeInBits = SizeInBits; - this->AlignInBits = AlignInBits; + this->SubclassData32 = AlignInBits; this->OffsetInBits = OffsetInBits; } @@ -735,7 +740,7 @@ class DIType : public DIScope { unsigned getLine() const { return Line; } uint64_t getSizeInBits() const { return SizeInBits; } - uint32_t getAlignInBits() const { return AlignInBits; } + uint32_t getAlignInBits() const { return SubclassData32; } uint32_t getAlignInBytes() const { return getAlignInBits() / CHAR_BIT; } uint64_t getOffsetInBits() const { return OffsetInBits; } DIFlags getFlags() const { return Flags; } @@ -1389,13 +1394,13 @@ class DICompileUnit : public DIScope { private: unsigned SourceLanguage; - bool IsOptimized; unsigned RuntimeVersion; - unsigned EmissionKind; uint64_t DWOId; + unsigned EmissionKind; + unsigned NameTableKind; + bool IsOptimized; bool SplitDebugInlining; bool DebugInfoForProfiling; - unsigned NameTableKind; bool RangesBaseAddress; DICompileUnit(LLVMContext &C, StorageType Storage, unsigned SourceLanguage, @@ -1876,6 +1881,10 @@ class DISubprogram : public DILocalScope { /// Debug location. /// /// A debug location in source code, used for debug info and otherwise. +/// +/// Uses the SubclassData1, SubclassData16 and SubclassData32 +/// Metadata slots. + class DILocation : public MDNode { friend class LLVMContextImpl; friend class MDNode; @@ -2161,17 +2170,20 @@ class DILexicalBlockBase : public DILocalScope { } }; +/// Debug lexical block. +/// +/// Uses the SubclassData32 Metadata slot. class DILexicalBlock : public DILexicalBlockBase { friend class LLVMContextImpl; friend class MDNode; - unsigned Line; uint16_t Column; DILexicalBlock(LLVMContext &C, StorageType Storage, unsigned Line, unsigned Column, ArrayRef Ops) - : DILexicalBlockBase(C, DILexicalBlockKind, Storage, Ops), Line(Line), + : DILexicalBlockBase(C, DILexicalBlockKind, Storage, Ops), Column(Column) { + SubclassData32 = Line; assert(Column < (1u << 16) && "Expected 16-bit column"); } ~DILexicalBlock() = default; @@ -2206,7 +2218,7 @@ class DILexicalBlock : public DILexicalBlockBase { TempDILexicalBlock clone() const { return cloneImpl(); } - unsigned getLine() const { return Line; } + unsigned getLine() const { return SubclassData32; } unsigned getColumn() const { return Column; } static bool classof(const Metadata *MD) { @@ -2218,12 +2230,11 @@ class DILexicalBlockFile : public DILexicalBlockBase { friend class LLVMContextImpl; friend class MDNode; - unsigned Discriminator; - DILexicalBlockFile(LLVMContext &C, StorageType Storage, unsigned Discriminator, ArrayRef Ops) - : DILexicalBlockBase(C, DILexicalBlockFileKind, Storage, Ops), - Discriminator(Discriminator) {} + : DILexicalBlockBase(C, DILexicalBlockFileKind, Storage, Ops) { + SubclassData32 = Discriminator; + } ~DILexicalBlockFile() = default; static DILexicalBlockFile *getImpl(LLVMContext &Context, DILocalScope *Scope, @@ -2255,7 +2266,7 @@ class DILexicalBlockFile : public DILexicalBlockBase { (Scope, File, Discriminator)) TempDILexicalBlockFile clone() const { return cloneImpl(); } - unsigned getDiscriminator() const { return Discriminator; } + unsigned getDiscriminator() const { return SubclassData32; } static bool classof(const Metadata *MD) { return MD->getMetadataID() == DILexicalBlockFileKind; @@ -2338,12 +2349,13 @@ DILocation::cloneByMultiplyingDuplicationFactor(unsigned DF) const { return std::nullopt; } +/// Debug lexical block. +/// +/// Uses the SubclassData1 Metadata slot. class DINamespace : public DIScope { friend class LLVMContextImpl; friend class MDNode; - unsigned ExportSymbols : 1; - DINamespace(LLVMContext &Context, StorageType Storage, bool ExportSymbols, ArrayRef Ops); ~DINamespace() = default; @@ -2373,7 +2385,7 @@ class DINamespace : public DIScope { TempDINamespace clone() const { return cloneImpl(); } - bool getExportSymbols() const { return ExportSymbols; } + bool getExportSymbols() const { return SubclassData1; } DIScope *getScope() const { return cast_or_null(getRawScope()); } StringRef getName() const { return getStringOperand(2); } @@ -2387,11 +2399,11 @@ class DINamespace : public DIScope { /// Represents a module in the programming language, for example, a Clang /// module, or a Fortran module. +/// +/// Uses the SubclassData1 and SubclassData32 Metadata slots. class DIModule : public DIScope { friend class LLVMContextImpl; friend class MDNode; - unsigned LineNo; - bool IsDecl; DIModule(LLVMContext &Context, StorageType Storage, unsigned LineNo, bool IsDecl, ArrayRef Ops); @@ -2443,8 +2455,8 @@ class DIModule : public DIScope { StringRef getConfigurationMacros() const { return getStringOperand(3); } StringRef getIncludePath() const { return getStringOperand(4); } StringRef getAPINotesFile() const { return getStringOperand(5); } - unsigned getLineNo() const { return LineNo; } - bool getIsDecl() const { return IsDecl; } + unsigned getLineNo() const { return SubclassData32; } + bool getIsDecl() const { return SubclassData1; } Metadata *getRawScope() const { return getOperand(1); } MDString *getRawName() const { return getOperandAs(2); } @@ -2460,13 +2472,15 @@ class DIModule : public DIScope { }; /// Base class for template parameters. +/// +/// Uses the SubclassData1 Metadata slot. class DITemplateParameter : public DINode { protected: - bool IsDefault; - DITemplateParameter(LLVMContext &Context, unsigned ID, StorageType Storage, unsigned Tag, bool IsDefault, ArrayRef Ops) - : DINode(Context, ID, Storage, Tag, Ops), IsDefault(IsDefault) {} + : DINode(Context, ID, Storage, Tag, Ops) { + SubclassData1 = IsDefault; + } ~DITemplateParameter() = default; public: @@ -2475,7 +2489,7 @@ class DITemplateParameter : public DINode { MDString *getRawName() const { return getOperandAs(0); } Metadata *getRawType() const { return getOperand(1); } - bool isDefault() const { return IsDefault; } + bool isDefault() const { return SubclassData1; } static bool classof(const Metadata *MD) { return MD->getMetadataID() == DITemplateTypeParameterKind || @@ -2572,9 +2586,10 @@ class DITemplateValueParameter : public DITemplateParameter { }; /// Base class for variables. +/// +/// Uses the SubclassData32 Metadata slot. class DIVariable : public DINode { unsigned Line; - uint32_t AlignInBits; protected: DIVariable(LLVMContext &C, unsigned ID, StorageType Storage, signed Line, @@ -2587,7 +2602,7 @@ class DIVariable : public DINode { StringRef getName() const { return getStringOperand(1); } DIFile *getFile() const { return cast_or_null(getRawFile()); } DIType *getType() const { return cast_or_null(getRawType()); } - uint32_t getAlignInBits() const { return AlignInBits; } + uint32_t getAlignInBits() const { return SubclassData32; } uint32_t getAlignInBytes() const { return getAlignInBits() / CHAR_BIT; } /// Determines the size of the variable's type. std::optional getSizeInBits() const; @@ -3161,9 +3176,10 @@ class DIGlobalVariable : public DIVariable { } }; +/// Debug common block. +/// +/// Uses the SubclassData32 Metadata slot. class DICommonBlock : public DIScope { - unsigned LineNo; - friend class LLVMContextImpl; friend class MDNode; @@ -3205,7 +3221,7 @@ class DICommonBlock : public DIScope { } StringRef getName() const { return getStringOperand(2); } DIFile *getFile() const { return cast_or_null(getRawFile()); } - unsigned getLineNo() const { return LineNo; } + unsigned getLineNo() const { return SubclassData32; } Metadata *getRawScope() const { return getOperand(0); } Metadata *getRawDecl() const { return getOperand(1); } @@ -3310,12 +3326,11 @@ class DILocalVariable : public DIVariable { /// Label. /// +/// Uses the SubclassData32 Metadata slot. class DILabel : public DINode { friend class LLVMContextImpl; friend class MDNode; - unsigned Line; - DILabel(LLVMContext &C, StorageType Storage, unsigned Line, ArrayRef Ops); ~DILabel() = default; @@ -3353,7 +3368,7 @@ class DILabel : public DINode { DILocalScope *getScope() const { return cast_or_null(getRawScope()); } - unsigned getLine() const { return Line; } + unsigned getLine() const { return SubclassData32; } StringRef getName() const { return getStringOperand(1); } DIFile *getFile() const { return cast_or_null(getRawFile()); } @@ -3455,15 +3470,17 @@ class DIObjCProperty : public DINode { }; /// An imported module (C++ using directive or similar). +/// +/// Uses the SubclassData32 Metadata slot. class DIImportedEntity : public DINode { friend class LLVMContextImpl; friend class MDNode; - unsigned Line; - DIImportedEntity(LLVMContext &C, StorageType Storage, unsigned Tag, unsigned Line, ArrayRef Ops) - : DINode(C, DIImportedEntityKind, Storage, Tag, Ops), Line(Line) {} + : DINode(C, DIImportedEntityKind, Storage, Tag, Ops) { + SubclassData32 = Line; + } ~DIImportedEntity() = default; static DIImportedEntity *getImpl(LLVMContext &Context, unsigned Tag, @@ -3499,7 +3516,7 @@ class DIImportedEntity : public DINode { TempDIImportedEntity clone() const { return cloneImpl(); } - unsigned getLine() const { return Line; } + unsigned getLine() const { return SubclassData32; } DIScope *getScope() const { return cast_or_null(getRawScope()); } DINode *getEntity() const { return cast_or_null(getRawEntity()); } StringRef getName() const { return getStringOperand(2); } @@ -3567,6 +3584,8 @@ class DIGlobalVariableExpression : public MDNode { /// \c DW_MACINFO_*, defined in llvm/BinaryFormat/Dwarf.h). Called \a /// DIMacroNode /// because it's potentially used for non-DWARF output. +/// +/// Uses the SubclassData16 Metadata slot. class DIMacroNode : public MDNode { friend class LLVMContextImpl; friend class MDNode; @@ -3611,15 +3630,18 @@ class DIMacroNode : public MDNode { } }; +/// Macro +/// +/// Uses the SubclassData32 Metadata slot. class DIMacro : public DIMacroNode { friend class LLVMContextImpl; friend class MDNode; - unsigned Line; - DIMacro(LLVMContext &C, StorageType Storage, unsigned MIType, unsigned Line, ArrayRef Ops) - : DIMacroNode(C, DIMacroKind, Storage, MIType, Ops), Line(Line) {} + : DIMacroNode(C, DIMacroKind, Storage, MIType, Ops) { + SubclassData32 = Line; + } ~DIMacro() = default; static DIMacro *getImpl(LLVMContext &Context, unsigned MIType, unsigned Line, @@ -3649,7 +3671,7 @@ class DIMacro : public DIMacroNode { TempDIMacro clone() const { return cloneImpl(); } - unsigned getLine() const { return Line; } + unsigned getLine() const { return SubclassData32; } StringRef getName() const { return getStringOperand(0); } StringRef getValue() const { return getStringOperand(1); } @@ -3662,15 +3684,18 @@ class DIMacro : public DIMacroNode { } }; +/// Macro file +/// +/// Uses the SubclassData32 Metadata slot. class DIMacroFile : public DIMacroNode { friend class LLVMContextImpl; friend class MDNode; - unsigned Line; - DIMacroFile(LLVMContext &C, StorageType Storage, unsigned MIType, unsigned Line, ArrayRef Ops) - : DIMacroNode(C, DIMacroFileKind, Storage, MIType, Ops), Line(Line) {} + : DIMacroNode(C, DIMacroFileKind, Storage, MIType, Ops) { + SubclassData32 = Line; + } ~DIMacroFile() = default; static DIMacroFile *getImpl(LLVMContext &Context, unsigned MIType, @@ -3711,7 +3736,7 @@ class DIMacroFile : public DIMacroNode { replaceOperandWith(1, Elements.get()); } - unsigned getLine() const { return Line; } + unsigned getLine() const { return SubclassData32; } DIFile *getFile() const { return cast_or_null(getRawFile()); } DIMacroNodeArray getElements() const { diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 943826c6ac89d..927aefb8bd477 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -915,11 +915,11 @@ DICompileUnit::DICompileUnit(LLVMContext &C, StorageType Storage, bool DebugInfoForProfiling, unsigned NameTableKind, bool RangesBaseAddress, ArrayRef Ops) : DIScope(C, DICompileUnitKind, Storage, dwarf::DW_TAG_compile_unit, Ops), - SourceLanguage(SourceLanguage), IsOptimized(IsOptimized), - RuntimeVersion(RuntimeVersion), EmissionKind(EmissionKind), DWOId(DWOId), - SplitDebugInlining(SplitDebugInlining), + SourceLanguage(SourceLanguage), RuntimeVersion(RuntimeVersion), + DWOId(DWOId), EmissionKind(EmissionKind), NameTableKind(NameTableKind), + IsOptimized(IsOptimized), SplitDebugInlining(SplitDebugInlining), DebugInfoForProfiling(DebugInfoForProfiling), - NameTableKind(NameTableKind), RangesBaseAddress(RangesBaseAddress) { + RangesBaseAddress(RangesBaseAddress) { assert(Storage != Uniqued); } @@ -1181,8 +1181,9 @@ DILexicalBlockFile *DILexicalBlockFile::getImpl(LLVMContext &Context, DINamespace::DINamespace(LLVMContext &Context, StorageType Storage, bool ExportSymbols, ArrayRef Ops) - : DIScope(Context, DINamespaceKind, Storage, dwarf::DW_TAG_namespace, Ops), - ExportSymbols(ExportSymbols) {} + : DIScope(Context, DINamespaceKind, Storage, dwarf::DW_TAG_namespace, Ops) { + SubclassData1 = ExportSymbols; +} DINamespace *DINamespace::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, bool ExportSymbols, StorageType Storage, bool ShouldCreate) { @@ -1196,8 +1197,9 @@ DINamespace *DINamespace::getImpl(LLVMContext &Context, Metadata *Scope, DICommonBlock::DICommonBlock(LLVMContext &Context, StorageType Storage, unsigned LineNo, ArrayRef Ops) : DIScope(Context, DICommonBlockKind, Storage, dwarf::DW_TAG_common_block, - Ops), - LineNo(LineNo) {} + Ops) { + SubclassData32 = LineNo; +} DICommonBlock *DICommonBlock::getImpl(LLVMContext &Context, Metadata *Scope, Metadata *Decl, MDString *Name, Metadata *File, unsigned LineNo, @@ -1211,8 +1213,10 @@ DICommonBlock *DICommonBlock::getImpl(LLVMContext &Context, Metadata *Scope, DIModule::DIModule(LLVMContext &Context, StorageType Storage, unsigned LineNo, bool IsDecl, ArrayRef Ops) - : DIScope(Context, DIModuleKind, Storage, dwarf::DW_TAG_module, Ops), - LineNo(LineNo), IsDecl(IsDecl) {} + : DIScope(Context, DIModuleKind, Storage, dwarf::DW_TAG_module, Ops) { + SubclassData1 = IsDecl; + SubclassData32 = LineNo; +} DIModule *DIModule::getImpl(LLVMContext &Context, Metadata *File, Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, @@ -1301,8 +1305,9 @@ DILocalVariable::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, DIVariable::DIVariable(LLVMContext &C, unsigned ID, StorageType Storage, signed Line, ArrayRef Ops, uint32_t AlignInBits) - : DINode(C, ID, Storage, dwarf::DW_TAG_variable, Ops), Line(Line), - AlignInBits(AlignInBits) {} + : DINode(C, ID, Storage, dwarf::DW_TAG_variable, Ops), Line(Line) { + SubclassData32 = AlignInBits; +} std::optional DIVariable::getSizeInBits() const { // This is used by the Verifier so be mindful of broken types. const Metadata *RawType = getRawType(); @@ -1328,7 +1333,9 @@ std::optional DIVariable::getSizeInBits() const { DILabel::DILabel(LLVMContext &C, StorageType Storage, unsigned Line, ArrayRef Ops) - : DINode(C, DILabelKind, Storage, dwarf::DW_TAG_label, Ops), Line(Line) {} + : DINode(C, DILabelKind, Storage, dwarf::DW_TAG_label, Ops) { + SubclassData32 = Line; +} DILabel *DILabel::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, Metadata *File, unsigned Line, StorageType Storage, bool ShouldCreate) {